From 59f1e8e04e3bfa68139e9db2c25fec2a9a2de4b6 Mon Sep 17 00:00:00 2001 From: Nick Clemens <nick@bywatersolutions.com> Date: Wed, 21 Mar 2018 13:27:12 +0000 Subject: [PATCH] Bug 18316: Add weighting/relevancy options to ES query on simple search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The idea is the following: if some search field(s) are weighted in search engine config page, Koha will query ES on these fields only and with the coresponding weights. Else, search is done on the entire record. Test plan (having Koha working with Elasticsearch): - apply this patch, - try searches with and without weight defined on search fields Signed-off-by: Séverine QUEUNE <severine.queune@bulac.fr> Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Séverine QUEUNE <severine.queune@bulac.fr> Rebased-by: Alex Arnaud <alex.arnaud@biblibre.com> --- Koha/SearchEngine/Elasticsearch/QueryBuilder.pm | 12 ++++ Koha/SearchFields.pm | 23 +++++++ catalogue/search.pl | 8 ++- .../prog/en/modules/catalogue/advsearch.tt | 1 + t/db_dependent/Koha/SearchField.t | 70 +++++++++++++++++++++- 5 files changed, 112 insertions(+), 2 deletions(-) diff --git a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm index 8a0ead1deb..7f12e77664 100644 --- a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm +++ b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm @@ -92,6 +92,8 @@ sub build_query { default_operator => 'AND', default_field => '_all', lenient => JSON::true, + fields => $options{fields}, + use_dis_max => JSON::true, } }; @@ -228,9 +230,19 @@ sub build_query_compat { join( ' ', $self->_create_query_string(@search_params) ) || (), $self->_join_queries( $self->_convert_index_strings(@$limits) ) || () ); + my @weights = $params->{weight}; + my @w_fields = $params->{w_fields}; + my @fields = '_all'; + if ( defined $weights[0] ) { + for (my $i = 0 ; $i < (scalar @weights) ; $i++ ){ + push @fields, "$w_fields[$i]^$weights[$i]"; + } + } + # If there's no query on the left, let's remove the junk left behind $query_str =~ s/^ AND //; my %options; + $options{fields} = \@fields; $options{sort} = \@sort_params; $options{expanded_facet} = $params->{expanded_facet}; my $query = $self->build_query( $query_str, %options ); diff --git a/Koha/SearchFields.pm b/Koha/SearchFields.pm index 7af3c0b162..3cfcec3c09 100644 --- a/Koha/SearchFields.pm +++ b/Koha/SearchFields.pm @@ -35,6 +35,29 @@ Koha::SearchFields - Koha SearchField Object set class =cut +=head3 weighted_fields + +my (@w_fields, @weight) = Koha::SearchFields->weighted_fields(); + +=cut + +sub weighted_fields { + my ($self) = @_; + + my ($w_fields, $weight) = ([], []); + my $fields = $self->search( + { weight => { '>' => 0, '!=' => undef } }, + { order_by => { -desc => 'weight' } } + ); + + while ( my $field = $fields->next ) { + push @$w_fields, $field->name; + push @$weight, $field->weight; + } + + return ($w_fields, $weight); +} + =head3 type =cut diff --git a/catalogue/search.pl b/catalogue/search.pl index 27b36b7802..5aaacd0545 100755 --- a/catalogue/search.pl +++ b/catalogue/search.pl @@ -155,6 +155,7 @@ use Koha::Patrons; use Koha::SearchEngine::Search; use Koha::SearchEngine::QueryBuilder; use Koha::Virtualshelves; +use Koha::SearchFields; use URI::Escape; @@ -455,6 +456,11 @@ my $expanded_facet = $params->{'expand'}; # Define some global variables my ( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$query_type); +my ($w_fields, $weight); +unless ( $cgi->param('advsearch') ) { + ($w_fields, $weight) = Koha::SearchFields->weighted_fields(); +} + my $builder = Koha::SearchEngine::QueryBuilder->new( { index => $Koha::SearchEngine::BIBLIOS_INDEX } ); my $searcher = Koha::SearchEngine::Search->new( @@ -467,7 +473,7 @@ my $searcher = Koha::SearchEngine::Search->new( $query_type ) = $builder->build_query_compat( \@operators, \@operands, \@indexes, \@limits, - \@sort_by, $scan, $lang ); + \@sort_by, $scan, $lang, { w_fields => @$w_fields, weight => @$weight } ); ## parse the query_cgi string and put it into a form suitable for <input>s my @query_inputs; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/advsearch.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/advsearch.tt index 5be1aa54c8..697fc5c357 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/advsearch.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/advsearch.tt @@ -17,6 +17,7 @@ <form action="search.pl" method="get"> <div id="advanced-search"> +<input type="hidden" name="advsearch" value="1"/> <h1>Advanced search</h1> <p> <a href="/cgi-bin/koha/catalogue/itemsearch.pl">Go to item search</a> diff --git a/t/db_dependent/Koha/SearchField.t b/t/db_dependent/Koha/SearchField.t index 2e4bed1435..3338b594fa 100644 --- a/t/db_dependent/Koha/SearchField.t +++ b/t/db_dependent/Koha/SearchField.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 8; +use Test::More tests => 16; use Koha::Database; use Koha::SearchFields; @@ -132,4 +132,72 @@ my $sf3 = $builder->build({ $search_field = Koha::SearchFields->find($sf3->{id}); ok(!$search_field->is_mapped_biblios, 'Search field is not mapped'); +Koha::SearchFields->search({})->delete; + +$builder->build({ + source => 'SearchField', + value => { + name => 'acqdate', + label => 'acqdate', + weight => undef + } +}); + +$builder->build({ + source => 'SearchField', + value => { + name => 'copydate', + label => 'copydate', + weight => undef + } +}); + +$builder->build({ + source => 'SearchField', + value => { + name => 'ccode', + label => 'ccode', + weight => 0 + } +}); + +$builder->build({ + source => 'SearchField', + value => { + name => 'title', + label => 'title', + weight => 25 + } +}); + +$builder->build({ + source => 'SearchField', + value => { + name => 'subject', + label => 'subject', + weight => 15 + } +}); + +$builder->build({ + source => 'SearchField', + value => { + name => 'author', + label => 'author', + weight => 5 + } +}); + +my ($w_fields, $weight) = Koha::SearchFields->weighted_fields(); +is(scalar(@$w_fields), 3, 'weighted_fields should return 3 weighted fields.'); +is(scalar(@$weight), 3, 'weighted_fields should return 3 weight.'); + +is($w_fields->[0], 'title', 'First field is title.'); +is($w_fields->[1], 'subject', 'Second field is subject.'); +is($w_fields->[2], 'author', 'Third field is author.'); + +is($weight->[0], 25, 'Title weight is 25.'); +is($weight->[1], 15, 'Subject weight is 15.'); +is($weight->[2], 5, 'Author weight is 5.'); + $schema->storage->txn_rollback; \ No newline at end of file -- 2.11.0