From fb539c48ee3f1956538a1a4109b6b41c759e9533 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 25 Sep 2019 14:56:10 -0400 Subject: [PATCH] Support metarecord indexing and searching Signed-off-by: Bill Erickson --- .../eg2/src/app/share/catalog/elastic.service.ts | 9 ++-- .../lib/OpenILS/Application/Search/Elastic.pm | 57 +++++++++++++++++----- .../src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm | 6 ++- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/Open-ILS/src/eg2/src/app/share/catalog/elastic.service.ts b/Open-ILS/src/eg2/src/app/share/catalog/elastic.service.ts index 94e72a9cce..22cbe7c2e2 100644 --- a/Open-ILS/src/eg2/src/app/share/catalog/elastic.service.ts +++ b/Open-ILS/src/eg2/src/app/share/catalog/elastic.service.ts @@ -25,7 +25,6 @@ export class ElasticService { if (ctx.marcSearch.isSearchable()) { return true; } if ( ctx.termSearch.isSearchable() && - !ctx.termSearch.groupByMetarecord && !ctx.termSearch.fromMetarecord && !ctx.termSearch.hasBrowseEntry) { return true; @@ -45,9 +44,11 @@ export class ElasticService { const requestBody = this.compileRequestBody(ctx); - const method = ctx.isStaff ? - 'open-ils.search.elastic.bib_search.staff' : - 'open-ils.search.elastic.bib_search'; + let method = ctx.termSearch.isMetarecordSearch() ? + 'open-ils.search.elastic.bib_search.metabib' : + 'open-ils.search.elastic.bib_search' + + if (ctx.isStaff) { method += '.staff'; } // Extract just the bits that get sent to ES. const elasticStruct: Object = requestBody.toJSON(); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Elastic.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Elastic.pm index 75934bf6c8..2fc0c3708d 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Elastic.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Elastic.pm @@ -154,15 +154,23 @@ __PACKAGE__->register_method( __PACKAGE__->register_method( method => 'bib_search', api_name => 'open-ils.search.elastic.bib_search.staff', - signature => { - desc => q/ - Staff version of open-ils.search.elastic.bib_search + signature => {desc => q/Staff version of open-ils.search.elastic.bib_search /} +); - / - } +__PACKAGE__->register_method( + method => 'bib_search', + api_name => 'open-ils.search.elastic.bib_search.metabib', + signature => {desc => q/Staff version of open-ils.search.elastic.bib_search /} ); -# Translate a bib search API call into something consumable by Elasticsearch +__PACKAGE__->register_method( + method => 'bib_search', + api_name => 'open-ils.search.elastic.bib_search.metabib.staff', + signature => {desc => q/Staff version of open-ils.search.elastic.bib_search /} +); + + +# Augment and relay an Elastic query to the Elasticsearch backend. # Translate search results into a structure consistent with a bib search # API response. sub bib_search { @@ -172,15 +180,28 @@ sub bib_search { init(); my $staff = ($self->api_name =~ /staff/); + my $meta = ($self->api_name =~ /metabib/); return {count => 0, ids => []} unless $query && $query->{query}; # Only ask ES to return the 'id' field from the source bibs in # the response object, since that's all we need. - $query->{_source} = ['id']; + $query->{_source} = [$meta ? 'metarecord' : 'id']; my $elastic_query = compile_elastic_query($query, $options, $staff); + my $from = $elastic_query->{from} || 0; + my $size = $elastic_query->{size} || 20; + + if ($meta) { + $elastic_query->{collapse} = {field => 'metarecord'}; + # ES field collapse queries return counts for matched documents + # instead of matched groups. To determine the metarecord hit + # count (up to 1k), fetch up to 1k responses and count them. + $elastic_query->{from} = 0; + $elastic_query->{size} = 1000; + } + my $es = OpenILS::Elastic::BibSearch->new('main'); $es->connect; @@ -198,12 +219,26 @@ sub bib_search { # This is not guaranteed to be 1-to-1 given key shuffling, but meh. my $cache_key = md5_hex(OpenSRF::Utils::JSON->perl2JSON($elastic_query)); + my $hits = $results->{hits}->{hits}; + if ($meta) { + # count the number of groups represented in the result set. + $results->{hits}->{total} = scalar(@$hits); + + # Only return the requested window of hits to the caller. + $hits = [ grep {defined $_} @$hits[$from .. ($from + $size)] ]; + } + + my $ids = [ + map {[ + $meta ? $_->{_source}->{'metarecord'} : $_->{_id}, + undef, + $_->{_score} + ]} @$hits + ]; + return { + ids => $ids, count => $results->{hits}->{total}, - ids => [ - map { [$_->{_id}, undef, $_->{_score}] } - grep {defined $_} @{$results->{hits}->{hits}} - ], facets => format_facets($results->{aggregations}), cache_key => $cache_key, facet_key => $cache_key.'_facets' diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm b/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm index b328be071d..8e19383ff1 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm @@ -52,6 +52,7 @@ my $BASE_PROPERTIES = { bib_source => {type => 'integer'}, create_date => {type => 'date'}, edit_date => {type => 'date'}, + metarecord => {type => 'integer'}, # Holdings summaries. For bib-search, we don't need # copy-specific details, only aggregate visibility information. @@ -322,9 +323,11 @@ SELECT bre.edit_date, bre.source AS bib_source, bre.deleted, + mmrsm.metarecord, (elastic.bib_record_properties(bre.id)).* FROM biblio.record_entry bre -WHERE id IN ($ids_str) +LEFT JOIN metabib.metarecord_source_map mmrsm ON (mmrsm.source = bre.id) +WHERE bre.id IN ($ids_str) SQL return $self->get_db_rows($sql); @@ -381,6 +384,7 @@ sub populate_bib_index_batch { # some values are repeated per field. # extract them from the first entry. $body->{bib_source} = $field->{bib_source}; + $body->{metarecord} = $field->{metarecord}; # ES ikes the "T" separator for ISO dates ($body->{create_date} = $field->{create_date}) =~ s/ /T/g; -- 2.11.0