From 417553a9e47bf31f4cb785162e3dced856a2ac2a Mon Sep 17 00:00:00 2001 From: Robin Sheat Date: Thu, 14 May 2015 15:15:04 +1200 Subject: [PATCH] Bug 12478: starting to add search to staff client Signed-off-by: Nick Clemens Signed-off-by: Jesse Weaver Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kyle M Hall Signed-off-by: Brendan Gallagher --- .../Elasticsearch/QueryBuilder.pm | 43 +++--- Koha/SearchEngine/Elasticsearch/Search.pm | 2 +- catalogue/search.pl | 132 ++++++++++++++---- 3 files changed, 130 insertions(+), 47 deletions(-) diff --git a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm index f7c2ba2aca..260ff062fa 100644 --- a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm +++ b/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm @@ -177,7 +177,7 @@ sub build_query_compat { $lang ) = @_; -#die Dumper ( $self, $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang ); +#die Dumper ( $self, $operators, $operands, $indexes, $orig_limits, $sort_by, $scan, $lang ); my @sort_params = $self->_convert_sort_fields(@$sort_by); my @index_params = $self->_convert_index_fields(@$indexes); my $limits = $self->_fix_limit_special_cases($orig_limits); @@ -523,6 +523,28 @@ sub _convert_index_strings { return @res; } +=head2 _convert_index_strings_freeform + + my $search = $self->_convert_index_strings_freeform($search); + +This is similar to L<_convert_index_strings>, however it'll search out the +things to change within the string. So it can handle strings such as +C<(su:foo) AND (su:bar)>, converting the C appropriately. + +If there is something of the form "su,complete-subfield" or something, the +second part is stripped off as we can't yet handle that. Making it work +will have to wait for a real query parser. + +=cut + +sub _convert_index_strings_freeform { + my ( $self, $search ) = @_; + while ( my ( $zeb, $es ) = each %index_field_convert ) { + $search =~ s/\b$zeb(?:,[\w-]*)?:/$es:/g; + } + return $search; +} + =head2 _modify_string_by_type my $str = $self->_modify_string_by_type(%index_field); @@ -545,25 +567,6 @@ sub _modify_string_by_type { return $str; } -=head2 _convert_index_strings_freeform - - my $search = $self->_convert_index_strings_freeform($search); - -This is similar to L<_convert_index_strings>, however it'll search out the -things to change within the string. So it can handle strings such as -C<(su:foo) AND (su:bar)>, converting the C appropriately. - -=cut - -sub _convert_index_strings_freeform { - my ( $self, $search ) = @_; - - while ( my ( $zeb, $es ) = each %index_field_convert ) { - $search =~ s/\b$zeb:/$es:/g; - } - return $search; -} - =head2 _join_queries my $query_str = $self->_join_queries(@query_parts); diff --git a/Koha/SearchEngine/Elasticsearch/Search.pm b/Koha/SearchEngine/Elasticsearch/Search.pm index a9adcba3b6..26f0dff46d 100644 --- a/Koha/SearchEngine/Elasticsearch/Search.pm +++ b/Koha/SearchEngine/Elasticsearch/Search.pm @@ -124,7 +124,7 @@ sub count { A search interface somewhat compatible with LgetRecords>. Anything that is returned in the query created by build_query_compat will probably -get ignored here. +get ignored here, along with some other things (like C<@servers>.) =cut diff --git a/catalogue/search.pl b/catalogue/search.pl index fe5d45d329..6cd9bfb7a3 100755 --- a/catalogue/search.pl +++ b/catalogue/search.pl @@ -154,6 +154,8 @@ use C4::Search::History; use Koha::LibraryCategories; use Koha::Virtualshelves; +use Koha::SearchEngine::Search; +use Koha::SearchEngine::QueryBuilder; use URI::Escape; @@ -203,30 +205,6 @@ if($cgi->cookie("holdfor")){ ); } -## URI Re-Writing -# Deprecated, but preserved because it's interesting :-) -# The same thing can be accomplished with mod_rewrite in -# a more elegant way -# -#my $rewrite_flag; -#my $uri = $cgi->url(-base => 1); -#my $relative_url = $cgi->url(-relative=>1); -#$uri.="/".$relative_url."?"; -#warn "URI:$uri"; -#my @cgi_params_list = $cgi->param(); -#my $url_params = $cgi->Vars; -# -#for my $each_param_set (@cgi_params_list) { -# $uri.= join "", map "\&$each_param_set=".$_, split("\0",$url_params->{$each_param_set}) if $url_params->{$each_param_set}; -#} -#warn "New URI:$uri"; -# Only re-write a URI if there are params or if it already hasn't been re-written -#unless (($cgi->param('r')) || (!$cgi->param()) ) { -# print $cgi->redirect( -uri=>$uri."&r=1", -# -cookie => $cookie); -# exit; -#} - # load the branches my $branches = GetBranches(); @@ -295,6 +273,9 @@ foreach my $advanced_srch_type (@advanced_search_types) { } } $template->param(advancedsearchesloop => \@advancedsearchesloop); +my $types = C4::Context->preference("AdvancedSearchTypes") || "itemtypes"; +my $advancedsearchesloop = prepare_adv_search_types($types); +$template->param(advancedsearchesloop => $advancedsearchesloop); # The following should only be loaded if we're bringing up the advanced search template if ( $template_type eq 'advsearch' ) { @@ -486,8 +467,19 @@ 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 $builder = Koha::SearchEngine::QueryBuilder->new(); +my $searcher = Koha::SearchEngine::Search->new({index => 'biblios'}); + +my @results; + ## I. BUILD THE QUERY -( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$query_type) = buildQuery(\@operators,\@operands,\@indexes,\@limits,\@sort_by,$scan,$lang); +( + $error, $query, $simple_query, $query_cgi, + $query_desc, $limit, $limit_cgi, $limit_desc, + $query_type + ) + = $builder->build_query_compat( \@operators, \@operands, \@indexes, \@limits, + \@sort_by, $scan, $lang ); ## parse the query_cgi string and put it into a form suitable for s my @query_inputs; @@ -529,7 +521,12 @@ my $facets; # this object stores the faceted results that display on the left-ha my $results_hashref; eval { - ($error, $results_hashref, $facets) = getRecords($query,$simple_query,\@sort_by,\@servers,$results_per_page,$offset,$expanded_facet,$branches,$itemtypes,$query_type,$scan); + my $itemtypes = GetItemTypes; + ( $error, $results_hashref, $facets ) = $searcher->search_compat( + $query, $simple_query, \@sort_by, \@servers, + $results_per_page, $offset, $expanded_facet, $branches, + $itemtypes, $query_type, $scan + ); }; # This sorts the facets into alphabetical order @@ -767,3 +764,86 @@ $template->param( ); output_html_with_http_headers $cgi, $cookie, $template->output; + + +=head2 prepare_adv_search_types + + my $type = C4::Context->preference("AdvancedSearchTypes") || "itemtypes"; + my @advanced_search_types = prepare_adv_search_types($type); + +Different types can be searched for in the advanced search. This takes the +system preference that defines these types and parses it into an arrayref for +the template. + +"itemtypes" is handled specially, as itemtypes aren't an authorised value. +It also accounts for the "item-level_itypes" system preference. + +=cut + +sub prepare_adv_search_types { + my ($types) = @_; + + my @advanced_search_types = split( /\|/, $types ); + + # the index parameter is different for item-level itemtypes + my $itype_or_itemtype = + ( C4::Context->preference("item-level_itypes") ) ? 'itype' : 'itemtype'; + my $itemtypes = GetItemTypes; + + my ( $cnt, @result ); + foreach my $advanced_srch_type (@advanced_search_types) { + $advanced_srch_type =~ s/^\s*//; + $advanced_srch_type =~ s/\s*$//; + if ( $advanced_srch_type eq 'itemtypes' ) { + + # itemtype is a special case, since it's not defined in authorized values + my @itypesloop; + foreach my $thisitemtype ( + sort { + $itemtypes->{$a}->{'description'} + cmp $itemtypes->{$b}->{'description'} + } keys %$itemtypes + ) + { + my %row = ( + number => $cnt++, + ccl => "$itype_or_itemtype,phr", + code => $thisitemtype, + description => $itemtypes->{$thisitemtype}->{'description'}, + imageurl => getitemtypeimagelocation( + 'intranet', $itemtypes->{$thisitemtype}->{'imageurl'} + ), + ); + push @itypesloop, \%row; + } + my %search_code = ( + advanced_search_type => $advanced_srch_type, + code_loop => \@itypesloop + ); + push @result, \%search_code; + } + else { + # covers all the other cases: non-itemtype authorized values + my $advsearchtypes = GetAuthorisedValues($advanced_srch_type); + my @authvalueloop; + for my $thisitemtype (@$advsearchtypes) { + my %row = ( + number => $cnt++, + ccl => $advanced_srch_type, + code => $thisitemtype->{authorised_value}, + description => $thisitemtype->{'lib'}, + imageurl => getitemtypeimagelocation( + 'intranet', $thisitemtype->{'imageurl'} + ), + ); + push @authvalueloop, \%row; + } + my %search_code = ( + advanced_search_type => $advanced_srch_type, + code_loop => \@authvalueloop + ); + push @result, \%search_code; + } + } + return \@result; +} -- 2.39.5