1 package OpenILS::Application::Storage::Publisher::metabib;
2 use base qw/OpenILS::Application::Storage/;
4 use OpenSRF::EX qw/:try/;
5 use OpenILS::Application::Storage::CDBI::metabib;
6 use OpenILS::Application::Storage::FTS;
7 use OpenILS::Utils::Fieldmapper;
8 use OpenSRF::Utils::Logger qw/:level/;
9 use OpenSRF::Utils::Cache;
11 use Digest::MD5 qw/md5_hex/;
13 my $log = 'OpenSRF::Utils::Logger';
24 my $term = $args{term};
25 my $limiters = $args{restrict};
26 my $limit = $args{limit} || 100;
27 my $offset = $args{offset} || 0;
30 my $cache_key = md5_hex(Dumper($limiters).$term);
32 my $cached_recs = OpenSRF::Utils::Cache->new->get_cache( $cache_key );
33 if (defined $cached_recs) {
34 $log->debug("Found ".scalar(@$cached_recs)." records in the cache", INFO);
35 $log->debug("Values from cache: ".join(', ', @$cached_recs), INTERNAL);
36 return [ @$cached_recs[$offset .. int($offset + $limit - 1)] ];
39 my ($index_col) = metabib::full_rec->columns('FTS');
40 $index_col ||= 'value';
41 my $search_table = metabib::full_rec->table;
43 my $metabib_metarecord_source_map_table = metabib::metarecord_source_map->table;
44 my $asset_call_number_table = asset::call_number->table;
46 my $fts = OpenILS::Application::Storage::FTS->compile($term, 'value',"$index_col");
48 my $fts_where = $fts->sql_where_clause();
49 my @fts_ranks = $fts->fts_rank;
51 my $rank = join(' + ', @fts_ranks);
55 for my $limit (@$limiters) {
56 push @wheres, "( tag = ? AND subfield LIKE ? AND $fts_where )";
57 push @binds, $$limit{tag}, $$limit{subfield};
58 $log->debug("Limiting query using { tag => $$limit{tag}, subfield => $$limit{subfield} }", DEBUG);
60 my $where = join(' OR ', @wheres);
62 my $select = "SELECT record, sum($rank) FROM $search_table WHERE $where GROUP BY 1 ORDER BY 2 DESC;";
64 $log->debug("Search SQL :: [$select]",DEBUG);
66 my $recs = metabib::full_rec->db_Main->selectall_arrayref($select, {}, @binds);
67 $log->debug("Search yielded ".scalar(@$recs)." results.",DEBUG);
69 $client->respond_complete( [ @$recs[$offset .. int($offset + $limit - 1)] ] );
71 OpenSRF::Utils::Cache->new->put_cache( $cache_key => $recs );
76 __PACKAGE__->register_method(
77 api_name => 'open-ils.storage.direct.metabib.full_rec.search_fts.value',
78 method => 'search_full_rec',
82 __PACKAGE__->register_method(
83 api_name => 'open-ils.storage.direct.metabib.full_rec.search_fts.index_vector',
84 method => 'search_full_rec',
90 # XXX factored most of the PG dependant stuff out of here... need to find a way to do "dependants".
91 sub search_class_fts {
96 my $term = $args{term};
97 my $ou = $args{org_unit};
98 my $ou_type = $args{depth};
99 my $limit = $args{limit} || 100;
100 my $offset = $args{offset} || 0;
103 (my $search_class = $self->api_name) =~ s/.*metabib.(\w+).search_fts.*/$1/o;
104 my $cache_key = md5_hex($search_class.$term.$ou.$ou_type);
106 my $cached_recs = OpenSRF::Utils::Cache->new->get_cache( $cache_key );
107 if (defined $cached_recs && @$cached_recs) {
108 $log->debug("Found ".scalar(@$cached_recs)." records in the cache", INFO);
109 $log->debug("Values from cache: ".join(', ', @$cached_recs), INTERNAL);
110 return [ @$cached_recs[$offset .. int($offset + $limit - 1)] ];
114 $log->debug("Cache key for $search_class search of '$term' at ($ou,$ou_type) will be $cache_key", DEBUG);
116 my $descendants = defined($ou_type) ?
117 "actor.org_unit_descendants($ou, $ou_type)" :
118 "actor.org_unit_descendants($ou)";
120 my $class = $self->{cdbi};
121 my $search_table = $class->table;
123 my $metabib_metarecord_source_map_table = metabib::metarecord_source_map->table;
124 my $asset_call_number_table = asset::call_number->table;
126 my ($index_col) = $class->columns('FTS');
127 $index_col ||= 'value';
129 my $fts = OpenILS::Application::Storage::FTS->compile($term, 'value', "$index_col");
131 my $fts_where = $fts->sql_where_clause;
132 my @fts_ranks = $fts->fts_rank;
134 my $rank = join(' + ', @fts_ranks);
136 my $select = <<" SQL";
137 SELECT m.metarecord, sum($rank)/count(m.source)
138 FROM $search_table f,
139 $metabib_metarecord_source_map_table m,
140 $asset_call_number_table cn,
143 AND m.source = f.source
144 AND cn.record = m.source
145 AND cn.owning_lib = d.id
150 $log->debug("Field Search SQL :: [$select]",DEBUG);
152 my $recs = $class->db_Main->selectall_arrayref($select);
154 $log->debug("Search yielded ".scalar(@$recs)." results.",DEBUG);
156 $client->respond_complete( [ @$recs[$offset .. int($offset + $limit - 1)] ] );
158 OpenSRF::Utils::Cache->new->put_cache( $cache_key => $recs );
163 __PACKAGE__->register_method(
164 api_name => 'open-ils.storage.metabib.title.search_fts.metarecord',
165 method => 'search_class_fts',
168 cdbi => 'metabib::title_field_entry',
170 __PACKAGE__->register_method(
171 api_name => 'open-ils.storage.metabib.author.search_fts.metarecord',
172 method => 'search_class_fts',
175 cdbi => 'metabib::author_field_entry',
177 __PACKAGE__->register_method(
178 api_name => 'open-ils.storage.metabib.subject.search_fts.metarecord',
179 method => 'search_class_fts',
182 cdbi => 'metabib::subject_field_entry',
184 __PACKAGE__->register_method(
185 api_name => 'open-ils.storage.metabib.keyword.search_fts.metarecord',
186 method => 'search_class_fts',
189 cdbi => 'metabib::keyword_field_entry',
192 # XXX factored most of the PG dependant stuff out of here... need to find a way to do "dependants".
193 sub search_class_fts_count {
198 my $term = $args{term};
199 my $ou = $args{org_unit};
200 my $ou_type = $args{depth};
201 my $limit = $args{limit} || 100;
202 my $offset = $args{offset} || 0;
204 my $descendants = defined($ou_type) ?
205 "actor.org_unit_descendants($ou, $ou_type)" :
206 "actor.org_unit_descendants($ou)";
209 (my $search_class = $self->api_name) =~ s/.*metabib.(\w+).search_fts.*/$1/o;
210 my $cache_key = md5_hex($search_class.$term.$ou.$ou_type.'_COUNT_');
212 my $cached_recs = OpenSRF::Utils::Cache->new->get_cache( $cache_key );
213 return $cached_recs if (defined $cached_recs);
215 my $class = $self->{cdbi};
216 my $search_table = $class->table;
218 my $metabib_metarecord_source_map_table = metabib::metarecord_source_map->table;
219 my $asset_call_number_table = asset::call_number->table;
221 my ($index_col) = $class->columns('FTS');
222 $index_col ||= 'value';
224 my $fts = OpenILS::Application::Storage::FTS->compile($term, 'value',"$index_col");
226 my $fts_where = $fts->sql_where_clause;
228 # XXX test an "EXISTS version of descendant checking...
229 my $select = <<" SQL";
230 SELECT count(distinct m.metarecord)
231 FROM $search_table f,
232 $metabib_metarecord_source_map_table m,
233 $asset_call_number_table cn,
236 AND m.source = f.source
237 AND cn.record = m.source
238 AND cn.owning_lib = d.id;
241 $log->debug("Field Search Count SQL :: [$select]",DEBUG);
243 my $recs = $class->db_Main->selectrow_arrayref($select)->[0];
245 $log->debug("Count Search yielded $recs results.",DEBUG);
247 OpenSRF::Utils::Cache->new->put_cache( $cache_key => $recs );
252 __PACKAGE__->register_method(
253 api_name => 'open-ils.storage.metabib.title.search_fts.metarecord_count',
254 method => 'search_class_fts_count',
257 cdbi => 'metabib::title_field_entry',
259 __PACKAGE__->register_method(
260 api_name => 'open-ils.storage.metabib.author.search_fts.metarecord_count',
261 method => 'search_class_fts_count',
264 cdbi => 'metabib::author_field_entry',
266 __PACKAGE__->register_method(
267 api_name => 'open-ils.storage.metabib.subject.search_fts.metarecord_count',
268 method => 'search_class_fts_count',
271 cdbi => 'metabib::subject_field_entry',
273 __PACKAGE__->register_method(
274 api_name => 'open-ils.storage.metabib.keyword.search_fts.metarecord_count',
275 method => 'search_class_fts_count',
278 cdbi => 'metabib::keyword_field_entry',