|
Lines 102-111
sub build_query {
Link Here
|
| 102 |
if $d && ( $d ne 'asc' && $d ne 'desc' ); |
102 |
if $d && ( $d ne 'asc' && $d ne 'desc' ); |
| 103 |
$d = 'asc' unless $d; |
103 |
$d = 'asc' unless $d; |
| 104 |
|
104 |
|
| 105 |
# TODO account for fields that don't have a 'phrase' type |
|
|
| 106 |
|
| 107 |
$f = $self->_sort_field($f); |
105 |
$f = $self->_sort_field($f); |
| 108 |
push @{ $res->{sort} }, { "$f.phrase" => { order => $d } }; |
106 |
push @{ $res->{sort} }, { $f => { order => $d } }; |
| 109 |
} |
107 |
} |
| 110 |
} |
108 |
} |
| 111 |
|
109 |
|
|
Lines 171-177
sub build_browse_query {
Link Here
|
| 171 |
} |
169 |
} |
| 172 |
} |
170 |
} |
| 173 |
}, |
171 |
}, |
| 174 |
sort => [ { "$sort.phrase" => { order => "asc" } } ], |
172 |
sort => [ { $sort => { order => "asc" } } ], |
| 175 |
}; |
173 |
}; |
| 176 |
} |
174 |
} |
| 177 |
|
175 |
|
|
Lines 294-300
sub build_authorities_query {
Link Here
|
| 294 |
foreach my $s ( @{ $search->{searches} } ) { |
292 |
foreach my $s ( @{ $search->{searches} } ) { |
| 295 |
my ( $wh, $op, $val ) = @{$s}{qw(where operator value)}; |
293 |
my ( $wh, $op, $val ) = @{$s}{qw(where operator value)}; |
| 296 |
$wh = '_all' if $wh eq ''; |
294 |
$wh = '_all' if $wh eq ''; |
| 297 |
if ( $op eq 'is' || $op eq '=' ) { |
295 |
if ( $op eq 'is' || $op eq '=' || $op eq 'exact' ) { |
| 298 |
|
296 |
|
| 299 |
# look for something that matches completely |
297 |
# look for something that matches completely |
| 300 |
# note, '=' is about numerical vals. May need special handling. |
298 |
# note, '=' is about numerical vals. May need special handling. |
|
Lines 302-313
sub build_authorities_query {
Link Here
|
| 302 |
# matches. Also, we lowercase our search because the ES |
300 |
# matches. Also, we lowercase our search because the ES |
| 303 |
# index lowercases its values, and term searches don't get the |
301 |
# index lowercases its values, and term searches don't get the |
| 304 |
# search analyzer applied to them. |
302 |
# search analyzer applied to them. |
| 305 |
push @filter_parts, { term => { "$wh.phrase" => lc $val } }; |
303 |
push @query_parts, { match_phrase => { "$wh.phrase" => lc $val } }; |
| 306 |
} |
|
|
| 307 |
elsif ( $op eq 'exact' ) { |
| 308 |
|
| 309 |
# left and right truncation, otherwise an exact phrase |
| 310 |
push @query_parts, { match_phrase => { $wh => $val } }; |
| 311 |
} |
304 |
} |
| 312 |
elsif ( $op eq 'start' ) { |
305 |
elsif ( $op eq 'start' ) { |
| 313 |
|
306 |
|
|
Lines 316-337
sub build_authorities_query {
Link Here
|
| 316 |
} |
309 |
} |
| 317 |
else { |
310 |
else { |
| 318 |
# regular wordlist stuff |
311 |
# regular wordlist stuff |
| 319 |
push @query_parts, { match => { $wh => $val } }; |
312 |
push @query_parts, { match => { $wh => { query => $val, operator => 'AND' } } }; |
| 320 |
} |
313 |
} |
| 321 |
} |
314 |
} |
| 322 |
|
315 |
|
|
|
316 |
# Add authtype if specified |
| 317 |
if (defined $search->{authtypecode} && $search->{authtypecode}) { |
| 318 |
push @query_parts, { match => { authtype => $search->{authtypecode} } }; |
| 319 |
} |
| 320 |
|
| 323 |
# Merge the query and filter parts appropriately |
321 |
# Merge the query and filter parts appropriately |
| 324 |
# 'should' behaves like 'or', if we want 'and', use 'must' |
322 |
# 'should' behaves like 'or', if we want 'and', use 'must' |
| 325 |
my $query_part = { bool => { should => \@query_parts } }; |
323 |
my $query_part = { bool => { must => \@query_parts } }; |
| 326 |
my $filter_part = { bool => { should => \@filter_parts } }; |
324 |
my $filter_part = { bool => { must => \@filter_parts } }; |
| 327 |
|
325 |
|
| 328 |
# We need to add '.phrase' to all the sort headings otherwise it'll sort |
|
|
| 329 |
# based on the tokenised form. |
| 330 |
my %s; |
326 |
my %s; |
| 331 |
if ( exists $search->{sort} ) { |
327 |
if ( exists $search->{sort} ) { |
| 332 |
foreach my $k ( keys %{ $search->{sort} } ) { |
328 |
foreach my $k ( keys %{ $search->{sort} } ) { |
| 333 |
my $f = $self->_sort_field($k); |
329 |
my $f = $self->_sort_field($k); |
| 334 |
$s{"$f.phrase"} = $search->{sort}{$k}; |
330 |
$s{$f} = $search->{sort}{$k}; |
| 335 |
} |
331 |
} |
| 336 |
$search->{sort} = \%s; |
332 |
$search->{sort} = \%s; |
| 337 |
} |
333 |
} |
|
Lines 383-391
Also ignored.
Link Here
|
| 383 |
|
379 |
|
| 384 |
=item operator |
380 |
=item operator |
| 385 |
|
381 |
|
| 386 |
What form of search to do. Options are: is (phrase, no trunction, whole field |
382 |
What form of search to do. Options are: is (phrase, no truncation, whole field |
| 387 |
must match), = (number exact match), exact (phrase, but with left and right |
383 |
must match), = (number exact match), exact (phrase, no truncation, whole field |
| 388 |
truncation). If left blank, then word list, right truncted, anywhere is used. |
384 |
must match). If left blank, then word list, right truncated, anywhere is used. |
| 389 |
|
385 |
|
| 390 |
=item value |
386 |
=item value |
| 391 |
|
387 |
|
|
Lines 417-423
our $koha_to_index_name = {
Link Here
|
| 417 |
'match-heading' => 'Match-heading', |
413 |
'match-heading' => 'Match-heading', |
| 418 |
'see-from' => 'Match-heading-see-from', |
414 |
'see-from' => 'Match-heading-see-from', |
| 419 |
thesaurus => 'Subject-heading-thesaurus', |
415 |
thesaurus => 'Subject-heading-thesaurus', |
| 420 |
all => '' |
416 |
any => '', |
|
|
417 |
all => '' |
| 421 |
}; |
418 |
}; |
| 422 |
|
419 |
|
| 423 |
sub build_authorities_query_compat { |
420 |
sub build_authorities_query_compat { |
|
Lines 435-452
sub build_authorities_query_compat {
Link Here
|
| 435 |
unless exists $koha_to_index_name->{$m}; |
432 |
unless exists $koha_to_index_name->{$m}; |
| 436 |
} |
433 |
} |
| 437 |
for ( my $i = 0 ; $i < @$value ; $i++ ) { |
434 |
for ( my $i = 0 ; $i < @$value ; $i++ ) { |
| 438 |
push @searches, |
435 |
if (defined $value->[$i]) { |
| 439 |
{ |
436 |
my $escaped_value = $value->[$i]; |
| 440 |
where => $koha_to_index_name->{$marclist->[$i]}, |
437 |
$escaped_value =~ s/(["()\\])/\\$1/g; |
| 441 |
operator => $operator->[$i], |
438 |
push @searches, |
| 442 |
value => $value->[$i], |
439 |
{ |
| 443 |
}; |
440 |
where => $koha_to_index_name->{$marclist->[$i]}, |
|
|
441 |
operator => $operator->[$i], |
| 442 |
value => $escaped_value, |
| 443 |
}; |
| 444 |
} |
| 444 |
} |
445 |
} |
| 445 |
|
446 |
|
| 446 |
my %sort; |
447 |
my %sort; |
| 447 |
my $sort_field = |
448 |
my $sort_field = |
| 448 |
( $orderby =~ /^Heading/ ) ? 'Heading' |
449 |
( $orderby =~ /^Heading/ ) ? 'Heading' |
| 449 |
: ( $orderby =~ /^Auth/ ) ? 'Local-Number' |
450 |
: ( $orderby =~ /^Auth/ ) ? 'Local-number' |
| 450 |
: undef; |
451 |
: undef; |
| 451 |
if ($sort_field) { |
452 |
if ($sort_field) { |
| 452 |
my $sort_order = ( $orderby =~ /Asc$/ ) ? 'asc' : 'desc'; |
453 |
my $sort_order = ( $orderby =~ /Asc$/ ) ? 'asc' : 'desc'; |
|
Lines 778-785
the end. Maybe it'll be something else in the future, who knows?
Link Here
|
| 778 |
|
779 |
|
| 779 |
sub _sort_field { |
780 |
sub _sort_field { |
| 780 |
my ($self, $f) = @_; |
781 |
my ($self, $f) = @_; |
|
|
782 |
|
| 783 |
my $mappings = $self->get_elasticsearch_mappings(); |
| 784 |
my $textField = defined $mappings->{data}{properties}{$f}{type} && $mappings->{data}{properties}{$f}{type} eq 'text'; |
| 781 |
if ($self->sort_fields()->{$f}) { |
785 |
if ($self->sort_fields()->{$f}) { |
| 782 |
$f .= '__sort'; |
786 |
$f .= '__sort'; |
|
|
787 |
# We need to add '.phrase' to text fields, otherwise it'll sort |
| 788 |
# based on the tokenised form. |
| 789 |
$f .= '.phrase' if $textField; |
| 790 |
} else { |
| 791 |
# We need to add '.raw' to text fields without a sort field, |
| 792 |
# otherwise it'll sort based on the tokenised form. |
| 793 |
$f .= '.raw' if $textField; |
| 783 |
} |
794 |
} |
| 784 |
return $f; |
795 |
return $f; |
| 785 |
} |
796 |
} |