From 49c0ddde66c1bbb61f0733193e8ddb009f492c02 Mon Sep 17 00:00:00 2001 From: Nick Clemens Date: Thu, 12 Dec 2024 21:42:22 +0000 Subject: [PATCH] Bug 38694: Title boost ES (WIP) This patch is a rough example, will need tests and maybe an on/off switch What this patch does is: 1 - Wraps the existing search code in a a "bool" compound query as a "must". This should not affect relevancy or results of the existing searches. 2 - Before we clean/truncate terms, loop through the passed in search terms and indexes to build a new 'should' query, using the 'match' on the specified index/field that is added to the 'bool' query from above. This means that if a result from the original query is also returned here, that item will be boosted in the result. For searches on 'keyword' or 'title', or if no index is set, we use 'title-cover' as the most narrow form of title This query isn't going to help when users enter CCL (i.e. ti:To die for) and it won't boost titles from 505, series, etc when doing a general search. Nor will it have a detrimental effect, it will only boost field matches To test: 1 - Add a record with 245 $a novel 2 - Add a record with 245 $a A novel : $b about things / $c by me 3 - Search for: novel 4 - Search for: a novel 5 - Apply patch, restart all 6 - Repeat searches, note exact titles are boosted --- .../Elasticsearch/QueryBuilder.pm | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm index ad240bdde60..8240e1634e0 100644 --- a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm +++ b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm @@ -200,17 +200,25 @@ sub build_query { if ($options{whole_record}) { push @$fields, 'marc_data_array.*'; } - $res->{query} = { - query_string => { + my $query_string = { query => $query, fuzziness => $fuzzy_enabled ? 'auto' : '0', default_operator => 'AND', fields => $fields, lenient => JSON::true, analyze_wildcard => JSON::true, + }; + $query_string->{type} = 'cross_fields' if C4::Context->preference('ElasticsearchCrossFields'); + + $res->{query} = { + bool => { + must => [ + {query_string => $query_string} + ] } }; - $res->{query}->{query_string}->{type} = 'cross_fields' if C4::Context->preference('ElasticsearchCrossFields'); + + $res->{query}->{bool}->{should} = $options{field_match_boost_query} if $options{field_match_boost_query}; if ( $options{sort} ) { foreach my $sort ( @{ $options{sort} } ) { @@ -262,6 +270,8 @@ sub build_query_compat { $lang, $params ) = @_; + my $field_match_boost_query = _build_field_match_boost_query({ operands => $operands, indexes => $indexes }); + my $query; my $query_str = ''; my $search_param_query_str = ''; @@ -314,6 +324,7 @@ sub build_query_compat { $options{is_opac} = $params->{is_opac}; $options{weighted_fields} = $params->{weighted_fields}; $options{whole_record} = $params->{whole_record}; + $options{field_match_boost_query} = $field_match_boost_query if @$field_match_boost_query; $query = $self->build_query( $query_str, %options ); } @@ -348,6 +359,20 @@ sub build_query_compat { $limit, $limit_cgi, $limit_desc, undef, undef ); } +sub _build_field_match_boost_query { + my ( $params ) = @_; + my $indexes = $params->{indexes}; + my $operands = $params->{operands}; + + my @boost_query; + my $ea = each_array( @$operands, @$indexes ); + while ( my ( $operand, $index ) = $ea->() ) { + next unless $operand; + $index = 'title-cover' if ( $index eq 'kw' || $index eq 'ti' || $index eq 'title' || !$index); + push @boost_query, { match => { $index => { query => $operand } } }; + } + return \@boost_query; +} =head2 build_authorities_query -- 2.39.5