File Coverage

blib/lib/KinoSearch1/Searcher.pm
Criterion Covered Total %
statement 81 85 95.2
branch 15 22 68.1
condition 4 6 66.6
subroutine 23 24 95.8
pod 2 10 20.0
total 125 147 85.0


line stmt bran cond sub pod time code
1             package KinoSearch1::Searcher;
2 18     18   99107 use strict;
  18         262  
  18         778  
3 18     18   103 use warnings;
  18         39  
  18         546  
4 18     18   2053 use KinoSearch1::Util::ToolSet;
  18         42  
  18         2586  
5 18     18   107 use base qw( KinoSearch1::Search::Searchable );
  18         39  
  18         10699  
6              
7             BEGIN {
8 18     18   215 __PACKAGE__->init_instance_vars(
9             # params/members
10             invindex => undef,
11             analyzer => undef,
12             # members
13             reader => undef,
14             close_reader => 0, # not implemented yet
15             );
16 18         170 __PACKAGE__->ready_get(qw( reader ));
17             }
18              
19 18     18   4994 use KinoSearch1::Store::FSInvIndex;
  18         61  
  18         606  
20 18     18   5386 use KinoSearch1::Index::IndexReader;
  18         60  
  18         552  
21 18     18   12399 use KinoSearch1::Search::Hits;
  18         72  
  18         620  
22 18     18   116 use KinoSearch1::Search::HitCollector;
  18         36  
  18         331  
23 18     18   113 use KinoSearch1::Search::Similarity;
  18         30  
  18         389  
24 18     18   11678 use KinoSearch1::QueryParser::QueryParser;
  18         64  
  18         776  
25 18     18   140 use KinoSearch1::Search::BooleanQuery;
  18         45  
  18         405  
26 18     18   107 use KinoSearch1::Analysis::Analyzer;
  18         44  
  18         16544  
27              
28             sub init_instance {
29 39     39 1 78 my $self = shift;
30              
31 39   66     342 $self->{analyzer} ||= KinoSearch1::Analysis::Analyzer->new;
32 39         547 $self->{similarity} = KinoSearch1::Search::Similarity->new;
33 39         168 $self->{field_sims} = {};
34              
35 39 50       162 if ( !defined $self->{reader} ) {
36             # confirm or create an InvIndex object
37 39         69 my $invindex;
38 39 100 66     757 if ( blessed( $self->{invindex} )
    50          
39             and $self->{invindex}->isa('KinoSearch1::Store::InvIndex') )
40             {
41 36         79 $invindex = $self->{invindex};
42             }
43             elsif ( defined $self->{invindex} ) {
44 3         39 $invindex = $self->{invindex}
45             = KinoSearch1::Store::FSInvIndex->new(
46             create => $self->{create},
47             path => $self->{invindex},
48             );
49             }
50             else {
51 0         0 croak("valid 'reader' or 'invindex' must be supplied");
52             }
53              
54             # now that we have an invindex, get a reader for it
55 39         397 $self->{reader} = KinoSearch1::Index::IndexReader->new(
56             invindex => $self->{invindex} );
57             }
58             }
59              
60             my %search_args = (
61             query => undef,
62             filter => undef,
63             num_docs => undef,
64             );
65              
66             sub search {
67 282     282 1 13425 my $self = shift;
68 282 100       2247 my %args
69             = @_ == 1
70             ? ( %search_args, query => $_[0] )
71             : ( %search_args, @_ );
72 282 50       1395 confess kerror() unless verify_args( \%search_args, %args );
73              
74             # turn a query string into a query against all fields
75 282 100       1235 if ( !a_isa_b( $args{query}, 'KinoSearch1::Search::Query' ) ) {
76 41         221 $args{query} = $self->_prepare_simple_search( $args{query} );
77             }
78              
79 282         2226 return KinoSearch1::Search::Hits->new( searcher => $self, %args );
80             }
81              
82             sub get_field_names {
83 42     42 0 85 my $self = shift;
84 42         230 return $self->{reader}->get_field_names(@_);
85             }
86              
87             # Search for the query string against all indexed fields
88             sub _prepare_simple_search {
89 41     41   96 my ( $self, $query_string ) = @_;
90              
91 41         190 my $indexed_field_names = $self->get_field_names( indexed => 1 );
92 41         533 my $query_parser = KinoSearch1::QueryParser::QueryParser->new(
93             fields => $indexed_field_names,
94             analyzer => $self->{analyzer},
95             );
96 41         219 return $query_parser->parse($query_string);
97             }
98              
99             my %search_hit_collector_args = (
100             hit_collector => undef,
101             weight => undef,
102             filter => undef,
103             sort_spec => undef,
104             );
105              
106             sub search_hit_collector {
107 285     285 0 456 my $self = shift;
108 285 50       1038 confess kerror() unless verify_args( \%search_hit_collector_args, @_ );
109 285         2043 my %args = ( %search_hit_collector_args, @_ );
110              
111             # wrap the collector if there's a filter
112 285         656 my $collector = $args{hit_collector};
113 285 100       940 if ( defined $args{filter} ) {
114 1         7 $collector = KinoSearch1::Search::FilteredCollector->new(
115             filter_bits => $args{filter}->bits($self),
116             hit_collector => $args{hit_collector},
117             );
118             }
119              
120             # accumulate hits into the HitCollector if the query is valid
121 285         1548 my $scorer = $args{weight}->scorer( $self->{reader} );
122 285 100       1050 if ( defined $scorer ) {
123 253         1508 $scorer->score_batch(
124             hit_collector => $collector,
125             end => $self->{reader}->max_doc,
126             );
127             }
128             }
129              
130 48     48 0 254 sub fetch_doc { $_[0]->{reader}->fetch_doc( $_[1] ) }
131 557     557 0 2457 sub max_doc { shift->{reader}->max_doc }
132              
133             sub doc_freq {
134 1273     1273 0 1979 my ( $self, $term ) = @_;
135 1273         4312 return $self->{reader}->doc_freq($term);
136             }
137              
138             sub create_weight {
139 278     278 0 484 my ( $self, $query ) = @_;
140 278         1541 return $query->to_weight($self);
141             }
142              
143             sub rewrite {
144 279     279 0 434 my ( $self, $query ) = @_;
145 279         650 my $reader = $self->{reader};
146 279         764 while (1) {
147 279         1096 my $rewritten = $query->rewrite($reader);
148 279 50       1177 last if ( 0 + $rewritten == 0 + $query );
149 0         0 $query = $rewritten;
150             }
151 279         738 return $query;
152             }
153              
154             sub close {
155 0     0 0   my $self = shift;
156 0 0         $self->{reader}->close if $self->{close_reader};
157             }
158              
159             1;
160              
161             __END__