From 7d1efe64c2cb48484f01e990558bf7bd1085ef52 Mon Sep 17 00:00:00 2001 From: miker Date: Fri, 7 Mar 2008 04:05:19 +0000 Subject: [PATCH] shiny new search method based on staged search stored proc git-svn-id: svn://svn.open-ils.org/ILS/trunk@8892 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../Application/Storage/Publisher/metabib.pm | 214 +++++++++++++++++- 1 file changed, 210 insertions(+), 4 deletions(-) diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm index 2b54ac49f6..b0ea6db445 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/metabib.pm @@ -1915,10 +1915,6 @@ sub biblio_search_multi_class_fts { $ou = actor::org_unit->search( { parent_ou => undef } )->next->id; } - if (!defined($args{org_unit})) { - die "No target organizational unit passed to ".$self->api_name; - } - if (! scalar( keys %{$args{searches}} )) { die "No search arguments were passed to ".$self->api_name; } @@ -2309,6 +2305,216 @@ __PACKAGE__->register_method( cachable => 1, ); +# XXX factored most of the PG dependant stuff out of here... need to find a way to do "dependants". +sub staged_fts { + my $self = shift; + my $client = shift; + my %args = @_; + + my $ou = $args{org_unit}; + my $pref_lang = $args{prefered_language} || 'eng'; # XXX not used currently + my $limit = $args{limit} || 10; + my $offset = $args{offset} || 0; + + if (!$ou) { + $ou = actor::org_unit->search( { parent_ou => undef } )->next->id; + } + + if (! scalar( keys %{$args{searches}} )) { + die "No search arguments were passed to ".$self->api_name; + } + + my (@statuses,@types,@forms,@lang,@aud,@lit_form,@vformats); + + if ($args{available}) { + @statuses = (0,7); + } + + if (my $s = $args{statuses}) { + $s = [$s] if (!ref($s)); + @statuses = @$s; + } + + if (my $a = $args{audience}) { + $a = [$a] if (!ref($a)); + @aud = @$a; + } + + if (my $l = $args{language}) { + $l = [$l] if (!ref($l)); + @lang = @$l; + } + + if (my $f = $args{lit_form}) { + $f = [$f] if (!ref($f)); + @lit_form = @$f; + } + + if (my $f = $args{item_form}) { + $f = [$f] if (!ref($f)); + @forms = @$f; + } + + if (my $t = $args{item_type}) { + $t = [$t] if (!ref($t)); + @types = @$t; + } + + if (my $v = $args{vr_format}) { + $v = [$v] if (!ref($v)); + @vformats = @$v; + } + + # XXX legacy format and item type support + if ($args{format}) { + my ($t, $f) = split '-', $args{format}; + @types = split '', $t; + @forms = split '', $f; + } + + my %stored_proc_search_args; + for my $search_group (sort keys %{$args{searches}}) { + (my $search_group_name = $search_group) =~ s/\|/_/gso; + my ($search_class,$search_field) = split /\|/, $search_group; + $log->debug("Searching class [$search_class] and field [$search_field]",DEBUG); + + if ($search_field) { + unless ( config::metabib_field->search( field_class => $search_class, name => $search_field )->next ) { + $log->warn("Requested class [$search_class] or field [$search_field] does not exist!"); + return undef; + } + } + + my $class = $_cdbi->{$search_class}; + my $search_table = $class->table; + + my ($index_col) = $class->columns('FTS'); + $index_col ||= 'value'; + + + my $fts = OpenILS::Application::Storage::FTS->compile( + $search_class => $args{searches}{$search_group}{term}, + $search_group_name.'.value', + "$search_group_name.$index_col" + ); + $fts->sql_where_clause; # this builds the ranks for us + + my @fts_ranks = $fts->fts_rank; + my @fts_queries = $fts->fts_query; + my @phrases = map { lc($_) } $fts->phrases; + my @words = map { lc($_) } $fts->words; + + $stored_proc_search_args{$search_group} = { + fts_rank => \@fts_ranks, + fts_query => \@fts_query, + phrase => \@phrases, + word => \@words, + }; + + } + + my $param_search_ou = $ou; + my $param_depth = $args{depth}; $param_depth ||= 'NULL' + my $param_searches = OpenSRF::Utils::JSON->perl2JSON( \%stored_proc_search_args ); $param_searches =~ s/\$//go; $param_searches = '$$'.$param_searches.'$$'; + my $param_statuses = '$${' . join(',', map { s/\$//go } @statuses) . '}$$'; + my $param_audience = '$${' . join(',', map { s/\$//go } @aud) . '}$$'; + my $param_language = '$${' . join(',', map { s/\$//go } @lang) . '}$$'; + my $param_lit_form = '$${' . join(',', map { s/\$//go } @lit_form) . '}$$'; + my $param_types = '$${' . join(',', map { s/\$//go } @types) . '}$$'; + my $param_forms = '$${' . join(',', map { s/\$//go } @forms) . '}$$'; + my $param_vformats = '$${' . join(',', map { s/\$//go } @vformats) . '}$$'; + my $param_sort = $args{'sort'}; $param_sort =~ s/\$//go; $param_sort = '$$'.$param_sort.'$$'; + my $param_sort_desc = (defined($args{sort_dir}) && $args{sort_dir} =~ /^d/io ? "'t'" : "'f'"); + my $metarecord = ($self->api_name =~ /metabib/o) ? "'t'" : "'f'"); + my $staff = ($self->api_name =~ /staff/o) ? "'t'" : "'f'"); + my $param_rel_limit = $args{core_limit}; $param_rel_limit ||= 'NULL'; + my $param_chk_limit = $args{check_limit}; $param_chk_limit ||= 'NULL'; + my $param_skip_chk = $args{skip_check}; $param_skip_chk ||= 'NULL'; + + my $sth = metabib::metarecord_source_map->db_Main->prepare(<<" SQL"); + SELECT * + FROM search.staged_fts( + $param_search_ou, + $param_depth, + $param_searches, + $param_statuses, + $param_audience, + $param_language, + $param_lit_form, + $param_types, + $param_forms, + $param_vformats, + $param_sort, + $param_sort_desc, + $metarecord, + $staff, + $param_rel_limit, + $param_chk_limit, + $param_skip_chk + ); + SQL + + my $recs = $sth->fetchall_arrayref({}); + my $summary_row = pop @$recs; + + my $total = $$summary_row{total}; + my $checked = $$summary_row{checked}; + my $visible = $$summary_row{visible}; + my $deleted = $$summary_row{deleted}; + my $excluded = $$summary_row{excluded}; + + my $estimate = $visible; + if ( $total > $checked ) { + my $deleted_ratio = $deleted / $checked; + my $exclution_ratio = $excluded / $checked; + my $delete_adjusted_total = $total - ( $total * $deleted_ratio ); + + $estimate = $$summary_row{estimated_hit_count} = int($delete_adjusted_total - ( $delete_adjusted_total * $exclution_ratio )); + } + + delete $$summary_row{id}; + delete $$summary_row{rel}; + delete $$summary_row{record}; + + $client->respond( $summary_row ); + + $log->debug("Search yielded ".scalar(@$recs)." checked, visible results with an approximate visible total of $estimate.",DEBUG); + + for my $rec (@$recs[$offset .. $offset + $limit - 1]) { + $client->respond( $rec ); + } + return undef; +} +__PACKAGE__->register_method( + api_name => "open-ils.storage.biblio.multiclass.staged.search_fts", + method => 'staged_fts', + api_level => 1, + stream => 1, + cachable => 1, +); +__PACKAGE__->register_method( + api_name => "open-ils.storage.biblio.multiclass.staged.search_fts.staff", + method => 'staged_fts', + api_level => 1, + stream => 1, + cachable => 1, +); +__PACKAGE__->register_method( + api_name => "open-ils.storage.metabib.multiclass.staged.search_fts", + method => 'staged_fts', + api_level => 1, + stream => 1, + cachable => 1, +); +__PACKAGE__->register_method( + api_name => "open-ils.storage.metabib.multiclass.staged.search_fts.staff", + method => 'staged_fts', + api_level => 1, + stream => 1, + cachable => 1, +); + + sub xref_count { my $self = shift; my $client = shift; -- 2.43.2