|
Lines 85-107
sub build_query {
Link Here
|
| 85 |
$query = '*' unless defined $query; |
85 |
$query = '*' unless defined $query; |
| 86 |
|
86 |
|
| 87 |
my $res; |
87 |
my $res; |
| 88 |
my $fields = $self->_search_fields({ |
88 |
$res->{query} = $query; |
| 89 |
is_opac => $options{is_opac}, |
|
|
| 90 |
weighted_fields => $options{weighted_fields}, |
| 91 |
}); |
| 92 |
if ($options{whole_record}) { |
| 93 |
push @$fields, 'marc_data_array.*'; |
| 94 |
} |
| 95 |
$res->{query} = { |
| 96 |
query_string => { |
| 97 |
query => $query, |
| 98 |
fuzziness => $fuzzy_enabled ? 'auto' : '0', |
| 99 |
default_operator => 'AND', |
| 100 |
fields => $fields, |
| 101 |
lenient => JSON::true, |
| 102 |
analyze_wildcard => JSON::true, |
| 103 |
} |
| 104 |
}; |
| 105 |
|
89 |
|
| 106 |
if ( $options{sort} ) { |
90 |
if ( $options{sort} ) { |
| 107 |
foreach my $sort ( @{ $options{sort} } ) { |
91 |
foreach my $sort ( @{ $options{sort} } ) { |
|
Lines 195-217
sub build_query_compat {
Link Here
|
| 195 |
}; |
179 |
}; |
| 196 |
} |
180 |
} |
| 197 |
|
181 |
|
| 198 |
# We build a string query from limits and the queries. An alternative |
182 |
|
| 199 |
# would be to pass them separately into build_query and let it build |
|
|
| 200 |
# them into a structured ES query itself. Maybe later, though that'd be |
| 201 |
# more robust. |
| 202 |
$search_param_query_str = join( ' ', $self->_create_query_string(@search_params) ); |
| 203 |
$query_str = join( ' AND ', |
| 204 |
$search_param_query_str || (), |
| 205 |
$self->_join_queries( $self->_convert_index_strings(@$limits) ) || () ); |
| 206 |
|
| 207 |
# If there's no query on the left, let's remove the junk left behind |
| 208 |
$query_str =~ s/^ AND //; |
| 209 |
my %options; |
183 |
my %options; |
| 210 |
$options{sort} = \@sort_params; |
184 |
$options{sort} = \@sort_params; |
| 211 |
$options{is_opac} = $params->{is_opac}; |
185 |
$options{is_opac} = $params->{is_opac}; |
| 212 |
$options{weighted_fields} = $params->{weighted_fields}; |
186 |
$options{weighted_fields} = $params->{weighted_fields}; |
| 213 |
$options{whole_record} = $params->{whole_record}; |
187 |
$options{whole_record} = $params->{whole_record}; |
| 214 |
$query = $self->build_query( $query_str, %options ); |
188 |
|
|
|
189 |
my $fields = $self->_search_fields({ |
| 190 |
is_opac => $options{is_opac}, |
| 191 |
weighted_fields => $options{weighted_fields}, |
| 192 |
}); |
| 193 |
if ($options{whole_record}) { |
| 194 |
push @$fields, 'marc_data_array.*'; |
| 195 |
} |
| 196 |
|
| 197 |
my $bool_query = { |
| 198 |
bool => { |
| 199 |
minimum_should_match => 1, |
| 200 |
should => [ |
| 201 |
{ |
| 202 |
bool => { |
| 203 |
must => [] |
| 204 |
} |
| 205 |
} |
| 206 |
] |
| 207 |
} |
| 208 |
}; |
| 209 |
|
| 210 |
foreach my $search_param (@search_params) { |
| 211 |
next if $search_param->{operand} eq '*'; |
| 212 |
my $operator = $search_param->{operator} // ''; |
| 213 |
my $expression = $self->_create_match_expression($search_param, \%options); |
| 214 |
if (defined($expression->{multi_match})) { |
| 215 |
$expression->{multi_match}->{fields} = $fields; |
| 216 |
} |
| 217 |
|
| 218 |
if ($operator eq 'OR') { |
| 219 |
push @{ $bool_query->{bool}->{should} }, { |
| 220 |
bool => { |
| 221 |
must => [$expression], |
| 222 |
}, |
| 223 |
}; |
| 224 |
} else { |
| 225 |
push @{ $bool_query->{bool}->{should}->[-1]->{bool}->{must} }, $expression; |
| 226 |
} |
| 227 |
} |
| 228 |
|
| 229 |
unless (@{ $bool_query->{bool}->{should}->[0]->{bool}->{must} }) { |
| 230 |
$bool_query->{bool}->{should}->[0] = { match_all => {} }; |
| 231 |
} |
| 232 |
|
| 233 |
if (@$limits) { |
| 234 |
$bool_query->{bool}->{filter} = $self->_build_limit_filters($limits); |
| 235 |
} |
| 236 |
|
| 237 |
$query = $self->build_query( $bool_query, %options ); |
| 215 |
} |
238 |
} |
| 216 |
|
239 |
|
| 217 |
# We roughly emulate the CGI parameters of the zebra query builder |
240 |
# We roughly emulate the CGI parameters of the zebra query builder |
|
Lines 246-251
sub build_query_compat {
Link Here
|
| 246 |
); |
269 |
); |
| 247 |
} |
270 |
} |
| 248 |
|
271 |
|
|
|
272 |
sub _create_match_expression { |
| 273 |
my ($self, $search_param) = @_; |
| 274 |
|
| 275 |
my $expression = {}; |
| 276 |
unless (defined($search_param->{field})) { |
| 277 |
$expression->{multi_match} = { |
| 278 |
query => $search_param->{operand}, |
| 279 |
lenient => JSON::true |
| 280 |
|
| 281 |
}; |
| 282 |
return $expression; |
| 283 |
} |
| 284 |
|
| 285 |
my $field = $search_param->{field}; |
| 286 |
$expression->{match} = { |
| 287 |
$field => $search_param->{operand} |
| 288 |
}; |
| 289 |
|
| 290 |
return $expression; |
| 291 |
} |
| 292 |
|
| 249 |
=head2 build_authorities_query |
293 |
=head2 build_authorities_query |
| 250 |
|
294 |
|
| 251 |
my $query = $builder->build_authorities_query(\%search); |
295 |
my $query = $builder->build_authorities_query(\%search); |
|
Lines 735-740
sub _convert_index_fields {
Link Here
|
| 735 |
} @indexes; |
779 |
} @indexes; |
| 736 |
} |
780 |
} |
| 737 |
|
781 |
|
|
|
782 |
=head2 _build_limit_filters |
| 783 |
my @filters = $self->_build_limit_filters |
| 784 |
|
| 785 |
Transform limit strings to Elasticsearch filters |
| 786 |
|
| 787 |
=cut |
| 788 |
|
| 789 |
sub _build_limit_filters { |
| 790 |
my ( $self, $limits ) = @_; |
| 791 |
my @res; |
| 792 |
foreach my $s (@$limits) { |
| 793 |
next if $s eq ''; |
| 794 |
my ( $field, $term ) = $s =~ /^\s*([\w,-]*?):(.*)/; |
| 795 |
next unless ( defined($field) && defined($term) ); |
| 796 |
|
| 797 |
my ($conv) = $self->_convert_index_fields($field); |
| 798 |
my $facet_name = $conv->{field} . '__facet'; |
| 799 |
push @res, { |
| 800 |
term => { |
| 801 |
$facet_name => $term |
| 802 |
} |
| 803 |
}; |
| 804 |
} |
| 805 |
|
| 806 |
return \@res; |
| 807 |
} |
| 808 |
|
| 738 |
=head2 _convert_index_strings |
809 |
=head2 _convert_index_strings |
| 739 |
|
810 |
|
| 740 |
my @searches = $self->_convert_index_strings(@searches); |
811 |
my @searches = $self->_convert_index_strings(@searches); |
|
Lines 880-908
sub _make_phrases {
Link Here
|
| 880 |
map { s/^\s*(\w*?:)(.*)$/$1"$2"/r } @parts; |
951 |
map { s/^\s*(\w*?:)(.*)$/$1"$2"/r } @parts; |
| 881 |
} |
952 |
} |
| 882 |
|
953 |
|
| 883 |
=head2 _create_query_string |
|
|
| 884 |
|
| 885 |
my @query_strings = $self->_create_query_string(@queries); |
| 886 |
|
| 887 |
Given a list of hashrefs, it will turn them into a lucene-style query string. |
| 888 |
The hash should contain field, type (both for the indexes), operator, and |
| 889 |
operand. |
| 890 |
|
| 891 |
=cut |
| 892 |
|
| 893 |
sub _create_query_string { |
| 894 |
my ( $self, @queries ) = @_; |
| 895 |
|
| 896 |
map { |
| 897 |
my $otor = $_->{operator} ? $_->{operator} . ' ' : ''; |
| 898 |
my $field = $_->{field} ? $_->{field} . ':' : ''; |
| 899 |
|
| 900 |
my $oand = $self->_modify_string_by_type(%$_); |
| 901 |
$oand = "($oand)" if $field && scalar(split(/\s+/, $oand)) > 1 && (!defined $_->{type} || $_->{type} ne 'st-year'); |
| 902 |
"$otor($field$oand)"; |
| 903 |
} @queries; |
| 904 |
} |
| 905 |
|
| 906 |
=head2 _clean_search_term |
954 |
=head2 _clean_search_term |
| 907 |
|
955 |
|
| 908 |
my $term = $self->_clean_search_term($term); |
956 |
my $term = $self->_clean_search_term($term); |
| 909 |
- |
|
|