File Coverage

blib/lib/KinoSearch1/Search/Hits.pm
Criterion Covered Total %
statement 56 56 100.0
branch 17 22 77.2
condition 2 3 66.6
subroutine 13 13 100.0
pod 6 6 100.0
total 94 100 94.0


line stmt bran cond sub pod time code
1             package KinoSearch1::Search::Hits;
2 18     18   26778 use strict;
  18         106  
  18         639  
3 18     18   96 use warnings;
  18         38  
  18         591  
4 18     18   684 use KinoSearch1::Util::ToolSet;
  18         37  
  18         3407  
5 18     18   107 use base qw( KinoSearch1::Util::Class );
  18         47  
  18         2548  
6              
7             BEGIN {
8 18     18   172 __PACKAGE__->init_instance_vars(
9             # params/members
10             searcher => undef,
11             query => undef,
12             filter => undef,
13             sort_spec => undef,
14             num_docs => undef,
15              
16             # members
17             weight => undef,
18             highlighter => undef,
19              
20             hit_docs => undef,
21             total_hits => undef,
22             );
23              
24 18         151 __PACKAGE__->ready_get(qw( hit_docs ));
25             }
26              
27 18     18   13712 use KinoSearch1::Highlight::Highlighter;
  18         67  
  18         710  
28 18     18   11571 use KinoSearch1::Search::HitCollector;
  18         65  
  18         10886  
29              
30             sub init_instance {
31 282     282 1 591 my $self = shift;
32              
33 282 50       1122 croak("required parameter 'query' not supplied")
34             unless $self->{query};
35 282 50       880 croak("required parameter 'searcher' not supplied")
36             unless $self->{searcher};
37              
38             # turn the Query into a Weight (so the Query won't get mussed)
39 282         1830 $self->{weight} = $self->{searcher}->create_weight( $self->{query} );
40             }
41              
42             sub seek {
43 283     283 1 5985 my ( $self, $start_offset, $num_wanted ) = @_;
44 283 50       1061 croak('Usage: $hits->seek( START, NUM_TO_RETRIEVE );')
45             unless @_ = 3;
46              
47             # collect enough to satisfy both the offset and the num wanted
48 283         2800 my $collector = KinoSearch1::Search::HitQueueCollector->new(
49             size => $num_wanted + $start_offset, );
50              
51             # execute the search!
52 283         1935 $self->{searcher}->search_hit_collector(
53             hit_collector => $collector,
54             weight => $self->{weight},
55             filter => $self->{filter},
56             sort_spec => $self->{sort_spec},
57             );
58 283         2016 $self->{total_hits} = $collector->get_total_hits;
59 283         1120 my $hit_queue = $collector->get_hit_queue;
60              
61             # turn the HitQueue into an array of Hit objects
62 283         2450 $self->{hit_docs}
63             = $hit_queue->hits( $start_offset, $num_wanted, $self->{searcher} );
64              
65             }
66              
67             sub total_hits {
68 271     271 1 2126 my $self = shift;
69 271 100       962 $self->seek( 0, 100 )
70             unless defined $self->{total_hits};
71 271         2899 return $self->{total_hits};
72             }
73              
74             sub fetch_hit {
75 4     4 1 12 my $self = shift;
76 4 100       13 $self->seek( 0, 100 )
77             unless defined $self->{total_hits};
78              
79 4         4 my $hit = shift @{ $self->{hit_docs} };
  4         7  
80 4 100       11 return unless defined $hit;
81 3         5 return $hit;
82             }
83              
84             sub fetch_hit_hashref {
85 47     47 1 3182 my $self = shift;
86 47 100       191 $self->seek( 0, 100 )
87             unless defined $self->{total_hits};
88              
89             # bail if there aren't any more *captured* hits
90 47         72 my $hit = shift @{ $self->{hit_docs} };
  47         123  
91 47 100       140 return unless defined $hit;
92              
93             # lazily fetch stored fields
94 46         202 my $hashref = $hit->get_field_values;
95              
96 46 50       164 if ( !exists $hashref->{score} ) {
97 46         189 $hashref->{score} = $hit->get_score;
98             }
99 46 100 66     188 if ( defined $self->{highlighter} and !exists $hashref->{excerpt} ) {
100 4         15 $hashref->{excerpt}
101             = $self->{highlighter}->generate_excerpt( $hit->get_doc );
102             }
103              
104 46         1619 return $hashref;
105             }
106              
107             my %create_excerpts_defaults = ( highlighter => undef, );
108              
109             sub create_excerpts {
110 3     3 1 2492 my $self = shift;
111 3 50       14 confess kerror() unless verify_args( \%create_excerpts_defaults, @_ );
112 3         14 my %args = ( %create_excerpts_defaults, @_ );
113              
114 3         9 $self->{highlighter} = $args{highlighter};
115 3         15 $self->{highlighter}->set_terms( [ $self->{query}->extract_terms ] );
116             }
117              
118             1;
119              
120             =head1 NAME
121              
122             KinoSearch1::Search::Hits - access search results
123              
124             =head1 SYNOPSIS
125              
126             my $hits = $searcher->search( query => $query );
127             $hits->seek( 0, 10 );
128             while ( my $hashref = $hits->fetch_hit_hashref ) {
129             print "

$hashref->{title} $hashref->{score}

\n";
130             }
131              
132             =head1 DESCRIPTION
133              
134             Hits objects are used to access the results of a search. By default, a hits
135             object provides access to the top 100 matches; the seek() method provides
136             finer-grained control.
137              
138             A classic application would be paging through hits. The first time, seek to a
139             START of 0, and retrieve 10 documents. If the user wants to see more -- and
140             there are more than 10 total hits -- seek to a START of 10, and retrieve 10
141             more documents. And so on.
142              
143             =head1 METHODS
144              
145             =head2 seek
146              
147             $hits->seek( START, NUM_TO_RETRIEVE );
148              
149             Position the Hits iterator at START, and capture NUM_TO_RETRIEVE docs.
150              
151             =head2 total_hits
152              
153             my $num_that_matched = $hits->total_hits;
154              
155             Return the total number of documents which matched the query used to produce
156             the Hits object. (This number is unlikely to match NUM_TO_RETRIEVE.)
157              
158             =head2 fetch_hit
159              
160             while ( my $hit = $hits->fetch_hit ) {
161             # ...
162             }
163              
164             Return the next hit as a KinoSearch1::Search::Hit object.
165              
166             =head2 fetch_hit_hashref
167              
168             while ( my $hashref = $hits->fetch_hit_hashref ) {
169             # ...
170             }
171              
172             Return the next hit as a hashref, with the field names as keys and the field
173             values as values. An entry for C will also be present, as will an
174             entry for C if create_excerpts() was called earlier. However, if the
175             document contains stored fields named "score" or "excerpt", they will not be
176             clobbered.
177              
178             =head2 create_excerpts
179              
180             my $highlighter = KinoSearch1::Highlight::Highlighter->new(
181             excerpt_field => 'bodytext',
182             );
183             $hits->create_excerpts( highlighter => $highlighter );
184              
185             Use the supplied highlighter to generate excerpts. See
186             L.
187              
188             =head1 COPYRIGHT
189              
190             Copyright 2005-2010 Marvin Humphrey
191              
192             =head1 LICENSE, DISCLAIMER, BUGS, etc.
193              
194             See L version 1.01.
195              
196             =cut
197