From 01a260bcf7710cde7159a83e2718bf0ebd4d3022 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 24 Oct 2018 15:20:53 -0400 Subject: [PATCH] bib-search indexing; search api wip Signed-off-by: Bill Erickson --- .../lib/OpenILS/Application/Search/Biblio.pm | 88 +++++++++++++++++++--- Open-ILS/src/perlmods/lib/OpenILS/Elastic.pm | 4 +- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm index 73289aa186..2826da2d49 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Search/Biblio.pm @@ -1389,17 +1389,25 @@ sub one_class_one_term { sub elastic_search { my ($query, $offset, $limit) = @_; - # TODO visibility limits on holdings summaries - my ($site) = ($query =~ /site\(([^\)]+)\)/); - $query =~ s/site\(([^\)]+)\)//g; + my ($available) = ($query =~ s/(\#available)//g); + my ($descending) = ($query =~ s/(\#descending)//g); + + my @funcs = qw/site depth sort item_lang/; # todo add others + my %calls; + + for my $func (@funcs) { + my ($val) = ($query =~ /$func\(([^\)]+)\)/); + if (defined $val) { + # scrub from query string + $query =~ s/$func\(([^\)]+)\)//g; + $calls{$func} = $val; + } + } + my $elastic_query = { - _source => ['id'] , # return only the ID field -# sort => [ -# {'title.raw' => 'asc'}, -# {'author.raw' => 'asc'}, -# '_score' -# ], + # Fetch only the bib ID field from each source document + _source => ['id'], size => $limit, from => $offset, query => { @@ -1414,6 +1422,68 @@ sub elastic_search { } }; + # No need to filter on holdings lib when searching globally + # (i.e. depth = 0) + if ($calls{site}) { + + my $types = $U->get_org_types; + my $org = $U->find_org_by_shortname($U->get_org_tree, $calls{site}); + my ($type) = grep {$_->id == $org->ou_type} @$types; + my $depth = $calls{depth} || $type->depth; + + # No holdings-level circ lib filter needed when searching globally + if ($depth > 0) { + + # TODO + # this makes a cstore call, but could easily come from cache. + my $org_ids = $U->get_org_descendants($org->id, $depth); + + # Add a boolean OR-filter on holdings circ lib and optionally + # add a boolean AND-filter on copy status for availability + # checking. + $elastic_query->{query}->{bool}->{filter} = { + nested => { + path => 'holdings', + query => {bool => {should => []}} + } + }; + + my $should = + $elastic_query->{query}{bool}{filter}{nested}{query}{bool}{should}; + + for my $org_id (@$org_ids) { + + # Ensure at least one copy exists at the selected org unit + my $and = { + bool => { + must => [ + {term => {'holdings.circ_lib' => $org_id}} + ] + } + }; + + # When limiting to available, ensure at least one of the + # above copies is in status 0 or 7. + # TODO: consult config.copy_status.is_available + push( + @{$and->{bool}{must}}, + {terms => {'holdings.status' => [0, 7]}} + ) if $available; + + push(@$should, $and); + } + } + } + + if ($calls{sort}) { + my $key = 'title.raw' if ($calls{sort} =~ /title/); + $key = 'author.raw' if ($calls{sort} =~ /author/); + $key = 'pub_date' if ($calls{sort} =~ /pubdate/); + if ($key) { + $elastic_query->{sort} = [{$key => $descending ? 'desc' : 'asc'}]; + } + } + my $es = OpenILS::Elastic::BibSearch->new('main'); $es->connect; my $results = $es->search($elastic_query); diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Elastic.pm b/Open-ILS/src/perlmods/lib/OpenILS/Elastic.pm index 9892a6db8e..9f75ee6a35 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Elastic.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Elastic.pm @@ -202,8 +202,8 @@ sub search { } $logger->info( - sprintf("ES search found %d results in %f seconds.", - $result->{hits}->{total}, substr($duration, 0, 6) + sprintf("ES search found %d results in %0.3f seconds.", + $result->{hits}->{total}, $duration ) ); -- 2.11.0