File Coverage

blib/lib/Plucene/Search/IndexSearcher.pm
Criterion Covered Total %
statement 62 67 92.5
branch 11 18 61.1
condition 10 15 66.6
subroutine 19 20 95.0
pod 7 7 100.0
total 109 127 85.8


line stmt bran cond sub pod time code
1             package Plucene::Search::IndexSearcher;
2              
3             =head1 NAME
4              
5             Plucene::Search::IndexSearcher - The index searcher
6              
7             =head1 SYNOPSIS
8              
9             # isa Plucene::Search::Searcher
10              
11             my $searcher = Plucene::Search::IndexSearcher
12             ->new(Plucene::Index::Reader $reader);
13              
14             my Plucene::Index::Reader $reader = $searcher->reader;
15             my Plucene::Document $doc = $reader->doc($id);
16              
17             $searcher->close;
18            
19             =head1 DESCRIPTION
20              
21             Search over an IndexReader
22              
23             =head1 METHODS
24              
25             =cut
26              
27 16     16   3864 use strict;
  16         37  
  16         751  
28 16     16   94 use warnings;
  16         38  
  16         539  
29              
30 16     16   4836 use Bit::Vector::Minimal;
  16         3953  
  16         466  
31 16     16   105 use Carp;
  16         47  
  16         1090  
32              
33 16     16   3291 use Plucene::Index::Reader;
  16         54  
  16         420  
34 16     16   6404 use Plucene::Search::HitCollector;
  16         44  
  16         465  
35 16     16   9372 use Plucene::Search::Query;
  16         47  
  16         131  
36 16     16   9935 use Plucene::Search::TopDocs;
  16         52  
  16         133  
37              
38 16     16   516 use base 'Plucene::Search::Searcher';
  16         34  
  16         9263  
39              
40             =head2 new
41              
42             my $searcher = Plucene::Search::IndexSearcher
43             ->new(Plucene::Index::Reader $reader);
44              
45             This will create a new Searcher object with the passed Plucene::Index::Reader
46             or subclass thereof.
47            
48             =cut
49              
50             sub new {
51 177     177 1 2181 my ($self, $thing) = @_;
52 177 100 66     6965 if (not ref $thing and -d $thing) {
53 176         1783 $thing = Plucene::Index::Reader->open($thing);
54             }
55 177 100       1762 croak "Don't know how to turn $thing into an index reader"
56             unless UNIVERSAL::isa($thing, "Plucene::Index::Reader");
57 176         1985 bless { reader => $thing }, $self;
58             }
59              
60             =head2 reader
61              
62             my Plucene::Index::Reader $reader = $searcher->reader;
63              
64             This will return the reader this searcher was made with.
65              
66             =head2 search_top
67              
68             The top search results.
69              
70             =head2 doc
71              
72             my Plucene::Document $doc = $reader->doc($id);
73              
74             This will return the Plucene::Document $id.
75              
76             =head2 doc_freq / max_doc
77              
78             get / set these
79              
80             =cut
81              
82 198     198 1 759 sub doc_freq { shift->reader->doc_freq(@_) }
83 198     198 1 2101 sub max_doc { shift->reader->max_doc(@_) }
84              
85 505     505 1 3098 sub reader { shift->{reader} }
86              
87 108     108 1 38284 sub doc { shift->reader->document(@_); }
88              
89             sub search_top {
90 176     176 1 2613 my ($self, $query, $filter, $n_docs) = @_;
91 176         1454 my $scorer = Plucene::Search::Query->scorer($query, $self, $self->{reader});
92 176 50       860 return Plucene::Search::TopDocs->new({ total_hits => 0, score_docs => [] })
93             unless $scorer;
94 176   66     692 my $bits = $filter && $filter->bits($self->{reader});
95              
96             # This is the hitqueue class, essentially
97             tie my @hq, "Tie::Array::Sorted", sub {
98 234     234   2099 my ($hit_a, $hit_b) = @_;
99 234   66     1232 return ($hit_a->{score} <=> $hit_b->{score})
100             || ($hit_b->{doc} <=> $hit_a->{doc});
101 176         3087 };
102 176         2126 my $total_hits = 0; # Dunno why this is an array in Java
103              
104             # This is where it turns ugly
105             $scorer->score(
106             Plucene::Search::HitCollector->new(
107 176         432 collect => do {
108 176         327 my $min_score = 0;
109             sub {
110 261     261   512 my ($self, $doc, $score) = @_;
111             return
112 261 100 100     1668 if $score == 0
      33        
113             || ($bits && !$bits->get($doc));
114 259         481 $total_hits++;
115 259 50       766 if ($score >= $min_score) {
116 259         1773 push @hq, { doc => $doc, score => $score };
117 259 50       9091 if (@hq > $n_docs) {
118 0         0 shift @hq;
119 0         0 $min_score = $hq[0]->{score};
120             }
121             }
122             }
123 176         2498 }
124             ),
125             $self->{reader}->max_doc
126             );
127              
128 176         6208 my @array = @hq; # Copy out of tied array
129 176         4960 return Plucene::Search::TopDocs->new({
130             total_hits => $total_hits,
131             score_docs => \@array
132             });
133             }
134              
135             sub _search_hc {
136 2     2   5 my ($self, $query, $filter, $results) = @_;
137 2         4 my $collector = $results;
138 2 50       7 if ($filter) {
139 0         0 my $bits = $filter->bits($self->{reader});
140             $collector = Plucene::Search::HitCollector->new(
141             collect => sub {
142 0 0   0   0 $results->collect(@_) if $bits->get($_[0]);
143 0         0 });
144             }
145              
146 2         21 my $scorer = Plucene::Search::Query->scorer($query, $self, $self->{reader});
147 2 50       8 return unless $scorer;
148 2         8 $scorer->score($collector, $self->{reader}->max_doc);
149             }
150              
151             =head2 close
152              
153             This will close the reader(s) associated with the searcher.
154              
155             =cut
156              
157 1     1 1 13 sub close { shift->{reader}->close }
158              
159             1;