From 6282d0c6cf69d25925935b3283b4f5bc3934c9bd Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 10 Sep 2019 16:03:31 -0400 Subject: [PATCH] Identifier searches / isbn issn normalizers Signed-off-by: Bill Erickson --- .../eg2/src/app/share/catalog/elastic.service.ts | 22 +++++- .../src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm | 86 ++++++++++++++++++---- 2 files changed, 91 insertions(+), 17 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 bee44035ad..cdc2b46f35 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 @@ -6,7 +6,8 @@ import {NetService} from '@eg/core/net.service'; import {PcrudService} from '@eg/core/pcrud.service'; import {CatalogSearchContext} from './search-context'; import {RequestBodySearch, MatchQuery, MultiMatchQuery, TermsQuery, Query, Sort, - PrefixQuery, NestedQuery, BoolQuery, TermQuery, RangeQuery} from 'elastic-builder'; + PrefixQuery, NestedQuery, BoolQuery, TermQuery, WildcardQuery, RangeQuery + } from 'elastic-builder'; @Injectable() export class ElasticService { @@ -38,8 +39,14 @@ export class ElasticService { if ( ctx.termSearch.isSearchable() && !ctx.termSearch.groupByMetarecord && - !ctx.termSearch.fromMetarecord - ) { return true; } + !ctx.termSearch.fromMetarecord) { + return true; + } + + if (ctx.identSearch.isSearchable() + && ctx.identSearch.queryType !== 'item_barcode') { + return true; + } return false; } @@ -83,7 +90,10 @@ export class ElasticService { this.addFieldSearches(ctx, rootNode); } else if (ctx.marcSearch.isSearchable()) { this.addMarcSearches(ctx, rootNode); + } else if (ctx.identSearch.isSearchable()) { + this.addIdentSearches(ctx, rootNode); } + this.addFilters(ctx, rootNode); this.addSort(ctx, search); @@ -157,6 +167,12 @@ export class ElasticService { } } + + addIdentSearches(ctx: CatalogSearchContext, rootNode: BoolQuery) { + rootNode.must( + new TermQuery(ctx.identSearch.queryType, ctx.identSearch.value)); + } + addMarcSearches(ctx: CatalogSearchContext, rootNode: BoolQuery) { const ms = ctx.marcSearch; 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 c45beec76c..e002b93313 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm @@ -18,6 +18,8 @@ use warnings; use Encode; use DateTime; use Time::HiRes qw/time/; +use Business::ISBN; +use Business::ISSN; use OpenSRF::Utils::Logger qw/:logger/; use OpenSRF::Utils::JSON; use OpenILS::Utils::CStoreEditor qw/:funcs/; @@ -87,7 +89,6 @@ my $BASE_PROPERTIES = { } } } - }; sub index_name { @@ -303,20 +304,12 @@ sub populate_bib_index_batch { $fname = "$fclass|$fname" if $fclass; $value = $self->truncate_value($value); - if ($body->{$fname}) { - if (ref $body->{$fname}) { - # Three or more values encountered for field. - # Add to the list. - push(@{$body->{$fname}}, $value); - } else { - # Second value encountered for field. - # Upgrade to array storage. - $body->{$fname} = [$body->{$fname}, $value]; - } + if ($fname eq 'identifier|isbn') { + index_isbns($body, $value); + } elsif ($fname eq 'identifier|issn') { + index_issns($body, $value); } else { - # First value encountered for field. - # Assume for now there will only be one value. - $body->{$fname} = $value + append_field_value($body, $fname, $value); } } @@ -332,6 +325,71 @@ sub populate_bib_index_batch { return $index_count; } + +# Indexes ISBN10, ISBN13, and formatted values of both (with hyphens) +sub index_isbns { + my ($body, $value) = @_; + return unless $value; + + my %seen; # deduplicate values + + # Chop up the collected raw values into parts and let + # Business::* tell us which parts looks like ISBNs. + for my $token (split(/ /, $value)) { + my $isbn = Business::ISBN->new($token); + if ($isbn && $isbn->is_valid) { + $seen{$isbn->as_isbn10->isbn} = 1; + $seen{$isbn->as_isbn10->as_string} = 1; + $seen{$isbn->as_isbn13->isbn} = 1; + $seen{$isbn->as_isbn13->as_string} = 1; + } + } + + append_field_value($body, 'identifier|isbn', $_) foreach keys %seen; +} + +# Indexes ISSN values with and wihtout hyphen formatting. +sub index_issns { + my ($body, $value) = @_; + return unless $value; + + my %seen; # deduplicate values + + # Chop up the collected raw values into parts and let + # Business::* tell us which parts looks valid. + for my $token (split(/ /, $value)) { + my $issn = Business::ISSN->new($token); + if ($issn && $issn->is_valid) { + # no option in business::issn to get the unformatted value. + (my $unformatted = $issn->as_string) =~ s/-//g; + $seen{$unformatted} = 1; + $seen{$issn->as_string} = 1; + } + } + + append_field_value($body, 'identifier|issn', $_) foreach keys %seen; +} + +sub append_field_value { + my ($body, $fname, $value) = @_; + + if ($body->{$fname}) { + if (ref $body->{$fname}) { + # Three or more values encountered for field. + # Add to the list. + push(@{$body->{$fname}}, $value); + } else { + # Second value encountered for field. + # Upgrade to array storage. + $body->{$fname} = [$body->{$fname}, $value]; + } + } else { + # First value encountered for field. + # Assume for now there will only be one value. + $body->{$fname} = $value + } +} + # Load holdings summary blobs for requested bibs sub load_holdings { my ($self, $bib_ids) = @_; -- 2.11.0