Identifier searches / isbn issn normalizers
authorBill Erickson <berickxx@gmail.com>
Tue, 10 Sep 2019 20:03:31 +0000 (16:03 -0400)
committerBill Erickson <berickxx@gmail.com>
Mon, 3 Feb 2020 22:13:59 +0000 (17:13 -0500)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/catalog/elastic.service.ts
Open-ILS/src/perlmods/lib/OpenILS/Elastic/Bib/Search.pm

index bee4403..cdc2b46 100644 (file)
@@ -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;
 
index c45beec..e002b93 100644 (file)
@@ -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) = @_;