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 |
- |
|
|