]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Authority.pm
Merge branch 'master' of git.evergreen-ils.org:Evergreen into template-toolkit-opac
[Evergreen.git] / Open-ILS / src / perlmods / lib / OpenILS / Application / Search / Authority.pm
1 package OpenILS::Application::Search::Authority;
2 use base qw/OpenILS::Application/;
3 use strict; use warnings;
4
5 use OpenILS::Utils::Fieldmapper;
6 use OpenILS::Application::AppUtils;
7 use XML::LibXML;
8 use XML::LibXSLT;
9 use OpenILS::Utils::CStoreEditor q/:funcs/;
10 use OpenSRF::Utils::Logger qw/$logger/;
11
12 use OpenSRF::Utils::JSON;
13
14 use Time::HiRes qw(time);
15 use OpenSRF::EX qw(:try);
16 use Digest::MD5 qw(md5_hex);
17
18 my $cache;
19
20
21 sub validate_authority {
22         my $self = shift;
23         my $client = shift;
24
25         my $session = OpenSRF::AppSession->create("open-ils.storage");
26         return $session->request( 'open-ils.storage.authority.validate.tag' => @_ )->gather(1);
27 }
28 __PACKAGE__->register_method(
29         method          => "validate_authority",
30         api_name        => "open-ils.search.authority.validate.tag",
31         argc            => 4, 
32         note            => "Validates authority data from existing controlled terms",
33 );              
34
35 sub validate_authority_return_records_by_id {
36         my $self = shift;
37         my $client = shift;
38
39         my $session = OpenSRF::AppSession->create("open-ils.storage");
40         return $session->request( 'open-ils.storage.authority.validate.tag.id_list' => @_ )->gather(1);
41 }
42 __PACKAGE__->register_method(
43         method          => "validate_authority_return_records_by_id",
44         api_name        => "open-ils.search.authority.validate.tag.id_list",
45         argc            => 4, 
46         note            => "Validates authority data from existing controlled terms",
47 );              
48
49 sub search_authority {
50         my $self = shift;
51         my $client = shift;
52
53         my $session = OpenSRF::AppSession->create("open-ils.storage");
54         return $session->request( 'open-ils.storage.authority.search.marc.atomic' => @_ )->gather(1);
55 }
56 __PACKAGE__->register_method(
57         method          => "search_authority",
58         api_name        => "open-ils.search.authority.fts",
59         argc            => 2, 
60         note            => "Searches authority data for existing controlled terms and crossrefs",
61 );              
62
63 sub search_authority_by_simple_normalize_heading {
64     my $self = shift;
65     my $client = shift;
66     my $marcxml = shift;
67     my $controlset = shift;
68
69     my $query = {
70         select => { are => ['id'] },
71         from   => 'are',
72         where  => {
73             deleted => 'f',
74             marc => { 'startwith' => {
75                 transform => 'authority.simple_normalize_heading',
76                 value     => [ 'authority.simple_normalize_heading' => $marcxml ]
77             }},
78             defined($controlset) ? ( control_set => $controlset ) : ()
79         }
80     };
81
82     $client->respond($_->{id}) for @{ new_editor()->json_query( $query ) };
83     $client->respond_complete;
84 }
85 __PACKAGE__->register_method(
86         method          => "search_authority_by_simple_normalize_heading",
87         api_name        => "open-ils.search.authority.simple_heading.from_xml",
88         argc            => 1, 
89         stream      => 1,
90         note            => "Searches authority data by main entry using marcxml, returning 'are' ids; params are marcxml and optional control-set-id",
91 );
92
93 sub search_authority_batch_by_simple_normalize_heading {
94     my $self = shift;
95     my $client = shift;
96     my $search_set = [@_];
97
98     my $m = $self->method_lookup('open-ils.search.authority.simple_heading.from_xml.atomic');
99
100     for my $s ( @$search_set ) {
101         for my $k ( keys %$s ) {
102             $client->respond( { $k => $m->run( $s->{$k}, $k ) } );
103         }
104     }
105
106     $client->respond_complete;
107 }
108 __PACKAGE__->register_method(
109         method          => "search_authority_batch_by_simple_normalize_heading",
110         api_name        => "open-ils.search.authority.simple_heading.from_xml.batch",
111         argc            => 1, 
112         stream      => 1,
113         note            => "Searches authority data by main entry using marcxml, in control-set batches, returning 'are' ids; params are hashes of { control-set-id => marcxml }",
114 );
115
116
117 sub crossref_authority {
118         my $self = shift;
119         my $client = shift;
120         my $class = shift;
121         my $term = shift;
122         my $limit = shift || 10;
123
124         my $session = OpenSRF::AppSession->create("open-ils.storage");
125
126         # Avoid generating spurious errors for more granular indexes, like author|personal
127         $class =~ s/^(.*?)\|.*?$/$1/;
128
129         $logger->info("authority xref search for $class=$term, limit=$limit");
130         my $fr = $session->request(
131                 "open-ils.storage.authority.$class.see_from.controlled.atomic",$term, $limit)->gather(1);
132         my $al = $session->request(
133                 "open-ils.storage.authority.$class.see_also_from.controlled.atomic",$term, $limit)->gather(1);
134
135         my $data = _auth_flatten( $term, $fr, $al, 1 );
136
137         return $data;
138 }
139
140 sub _auth_flatten {
141         my $term = shift;
142         my $fr = shift;
143         my $al = shift;
144         my $limit = shift;
145
146         my %hash = ();
147         for my $x (@$fr) {
148                 my $string = $$x[0];
149                 for my $i (1..10) {
150                         last unless ($$x[$i]);
151                         if ($string =~ /\W$/o) {
152                                 $string .= ' '.$$x[$i];
153                         } else {
154                                 $string .= ' -- '.$$x[$i];
155                         }
156                 }
157                 next if (lc($string) eq lc($term));
158                 $hash{$string}++;
159                 $hash{$string}++ if (lc($$x[0]) eq lc($term));
160         }
161         my $from = [keys %hash]; #[ sort { $hash{$b} <=> $hash{$a} || $a cmp $b } keys %hash ];
162
163 #       $from = [ @$from[0..4] ] if $limit;
164
165         %hash = ();
166         for my $x (@$al) {
167                 my $string = $$x[0];
168                 for my $i (1..10) {
169                         last unless ($$x[$i]);
170                         if ($string =~ /\W$/o) {
171                                 $string .= ' '.$$x[$i];
172                         } else {
173                                 $string .= ' -- '.$$x[$i];
174                         }
175                 }
176                 next if (lc($string) eq lc($term));
177                 $hash{$string}++;
178                 $hash{$string}++ if (lc($$x[0]) eq lc($term));
179         }
180         my $also = [keys %hash]; #[ sort { $hash{$b} <=> $hash{$a} || $a cmp $b } keys %hash ];
181
182 #       $also = [ @$also[0..4] ] if $limit;
183
184         #warn Dumper( { from => $from, also => $also } );
185
186         return { from => $from, also => $also };
187 }
188
189 __PACKAGE__->register_method(
190         method          => "crossref_authority",
191         api_name        => "open-ils.search.authority.crossref",
192         argc            => 2, 
193         note            => "Searches authority data for existing controlled terms and crossrefs",
194 );              
195
196 __PACKAGE__->register_method(
197         #method         => "new_crossref_authority_batch",
198         method          => "crossref_authority_batch2",
199         api_name        => "open-ils.search.authority.crossref.batch",
200         argc            => 1, 
201         note            => <<"  NOTE");
202         Takes an array of class,term pair sub-arrays and performs an authority lookup for each
203
204         PARAMS( [ ["subject", "earth"], ["author","shakespeare"] ] );
205
206         Returns an object like so:
207         {
208                 "classname" : {
209                         "term" : { "from" : [ ...], "also" : [...] }
210                         "term2" : { "from" : [ ...], "also" : [...] }
211                 }
212         }
213         NOTE
214
215 sub new_crossref_authority_batch {
216         my( $self, $client, $reqs ) = @_;
217
218         my $response = {};
219         my $lastr = [];
220         my $session = OpenSRF::AppSession->create("open-ils.storage");
221
222         for my $req (@$reqs) {
223
224                 my $class = $req->[0];
225                 my $term = $req->[1];
226                 next unless $class and $term;
227                 $logger->info("Sending authority request for $class : $term");
228                 my $fr = $session->request("open-ils.storage.authority.$class.see_from.controlled.atomic",$term, 10)->gather(1);
229                 my $al = $session->request("open-ils.storage.authority.$class.see_also_from.controlled.atomic",$term, 10)->gather(1);
230
231                 $response->{$class} = {} unless exists $response->{$class};
232                 $response->{$class}->{$term} = _auth_flatten( $term, $fr, $al, 1 );
233
234         }
235
236         #warn Dumper( $response );
237         return $response;
238 }
239
240 sub crossref_authority_batch {
241         my( $self, $client, $reqs ) = @_;
242
243         my $response = {};
244         my $lastr = [];
245         my $session = OpenSRF::AppSession->create("open-ils.storage");
246
247         for my $req (@$reqs) {
248
249                 my $class = $req->[0];
250                 my $term = $req->[1];
251                 next unless $class and $term;
252                 $logger->info("Sending authority request for $class : $term");
253                 my $freq = $session->request("open-ils.storage.authority.$class.see_from.controlled.atomic",$term, 10);
254                 my $areq = $session->request("open-ils.storage.authority.$class.see_also_from.controlled.atomic",$term, 10);
255
256                 if( $lastr->[0] ) { #process old data while waiting on new data
257                         my $cls = $lastr->[0];
258                         my $trm = $lastr->[1];
259                         my $fr  = $lastr->[2];
260                         my $al  = $lastr->[3];
261                         $response->{$cls} = {} unless exists $response->{$cls};
262                         $response->{$cls}->{$trm} = _auth_flatten( $trm, $fr, $al, 1 );
263                 }
264
265                 $lastr->[0] = $class;
266                 $lastr->[1] = $term; 
267                 $lastr->[2] = $freq->gather(1);
268                 $lastr->[3] = $areq->gather(1);
269         }
270
271         if( $lastr->[0] ) { #process old data while waiting on new data
272                 my $cls = $lastr->[0];
273                 my $trm = $lastr->[1];
274                 my $fr  = $lastr->[2];
275                 my $al  = $lastr->[3];
276                 $response->{$cls} = {} unless exists $response->{$cls};
277                 $response->{$cls}->{$trm} = _auth_flatten( $trm, $fr, $al, 1);
278         }
279
280         return $response;
281 }
282
283
284
285
286 sub crossref_authority_batch2 {
287         my( $self, $client, $reqs ) = @_;
288
289         my $response = {};
290         my $lastr = [];
291         my $session = OpenSRF::AppSession->create("open-ils.storage");
292
293         $cache = OpenSRF::Utils::Cache->new('global') unless $cache;
294
295         for my $req (@$reqs) {
296
297                 my $class = $req->[0];
298                 my $term = $req->[1];
299                 next unless $class and $term;
300
301                 my $t = $term;
302                 $t =~ s/\s//og;
303                 my $cdata = $cache->get_cache("oils_authority_${class}_$t");
304
305                 if( $cdata ) {
306                         $logger->debug("returning authority response from cache..");
307                         $response->{$class} = {} unless exists $response->{$class};
308                         $response->{$class}->{$term} = $cdata;
309                         next;
310                 }
311
312                 $logger->debug("authority data not found in cache.. fetching from storage");
313
314                 $logger->info("Sending authority request for $class : $term");
315                 my $freq = $session->request("open-ils.storage.authority.$class.see_from.controlled.atomic",$term, 10);
316                 my $areq = $session->request("open-ils.storage.authority.$class.see_also_from.controlled.atomic",$term, 10);
317                 my $fr = $freq->gather(1);      
318                 my $al = $areq->gather(1);
319                 $response->{$class} = {} unless exists $response->{$class};
320                 my $auth = _auth_flatten( $term, $fr, $al, 1 );
321
322                 my $timeout = 7200; #two hours
323                 $timeout = 300 if @{$auth->{from}} or @{$auth->{also}}; # 5 minutes
324                 $response->{$class}->{$term} = $auth;
325                 $logger->debug("adding authority lookup to cache with timeout $timeout");
326                 $cache->put_cache("oils_authority_${class}_$t", $auth, $timeout);
327         }
328         return $response;
329 }
330
331
332
333 1;