3 |
use strict; |
use strict; |
4 |
use warnings; |
use warnings; |
5 |
use base qw( Class::Accessor ); |
use base qw( Class::Accessor ); |
6 |
Grep::Search->mk_accessors( qw( invindexer create index_path ) ); |
Grep::Search->mk_accessors( qw( invindexer create index_path hits ) ); |
7 |
|
|
8 |
use Data::Dump qw/dump/; |
use Data::Dump qw/dump/; |
9 |
use KinoSearch::InvIndexer; |
use KinoSearch::InvIndexer; |
22 |
|
|
23 |
my $search = Grep::Search->new(); |
my $search = Grep::Search->new(); |
24 |
|
|
25 |
|
my $search = Grep::Search->new( create => 1 ); |
26 |
|
|
27 |
|
=head2 invindexer |
28 |
|
|
29 |
|
Accessor to call any method defined on L<KinoSearch::InvIndexer> |
30 |
|
|
31 |
|
$search->invindexer->delete_by_term( 'id', 42 ); |
32 |
|
|
33 |
=cut |
=cut |
34 |
|
|
35 |
sub log { Jifty->web->log } |
sub log { Jifty->web->log } |
42 |
|
|
43 |
$self->index_path( $index_path ); |
$self->index_path( $index_path ); |
44 |
|
|
45 |
if (! -e "$index_path") { |
if ( ! -e "$index_path" || $self->create ) { |
46 |
$self->log->debug("Creating new index $index_path"); |
$self->log->debug("Creating new index $index_path"); |
47 |
$self->invindexer( KinoSearch::InvIndexer->new( invindex => Grep::Search::Schema->clobber( $index_path ) ) ); |
$self->invindexer( KinoSearch::InvIndexer->new( invindex => Grep::Search::Schema->clobber( $index_path ) ) ); |
48 |
} else { |
} else { |
103 |
|
|
104 |
next if (! defined($v) || $v eq ''); |
next if (! defined($v) || $v eq ''); |
105 |
|
|
106 |
$v =~ s/<[^>]+>/ /gs; |
eval { $v =~ s/<[^>]+>/ /gs; }; |
107 |
|
if ($@) { |
108 |
|
Jifty->log->error("can't strip html from $c in item ", $i->id); |
109 |
|
next; |
110 |
|
} |
111 |
|
|
112 |
if ( defined( $pk->{$c} ) ) { |
if ( defined( $pk->{$c} ) ) { |
113 |
$doc->{ $c } = $v; |
$doc->{ $c } = $v; |
125 |
$self->invindexer->add_doc( $doc ); |
$self->invindexer->add_doc( $doc ); |
126 |
|
|
127 |
$self->log->debug("added ", $i->id, " for user $uid to index"); |
$self->log->debug("added ", $i->id, " for user $uid to index"); |
128 |
|
|
129 |
|
return 1; |
130 |
} |
} |
131 |
|
|
132 |
=head2 collection |
=head2 collection |
133 |
|
|
134 |
|
Return C<Grep::Model::ItemCollection> which is result of C<search query> |
135 |
|
|
136 |
my $ItemCollection = $search->collection( 'search query' ); |
my $ItemCollection = $search->collection( 'search query' ); |
137 |
|
|
138 |
|
=head2 hits |
139 |
|
|
140 |
|
Return number of results from last C<collection> call |
141 |
|
|
142 |
|
my $num_results = $search->hits; |
143 |
|
|
144 |
=cut |
=cut |
145 |
|
|
146 |
sub collection { |
sub collection { |
152 |
invindex => Grep::Search::Schema->open( $self->index_path ), ); |
invindex => Grep::Search::Schema->open( $self->index_path ), ); |
153 |
$self->log->debug("$searcher created"); |
$self->log->debug("$searcher created"); |
154 |
|
|
155 |
my $full_q = "($q) AND _owner_id:" . Jifty->web->current_user->id; |
my $full_q = "($q)"; |
156 |
|
|
157 |
|
my $uid = Jifty->web->current_user->id; |
158 |
|
$full_q .= ' AND _owner_id:' . $uid if (defined $uid); |
159 |
|
|
160 |
$self->log->debug("searching for '$q' using $full_q"); |
$self->log->debug("searching for '$q' using $full_q"); |
161 |
|
|
162 |
|
my $query_parser = KinoSearch::QueryParser->new( |
163 |
|
schema => Grep::Search::Schema->new, |
164 |
|
fields => [ qw/ title link content summary category author / ], |
165 |
|
); |
166 |
|
$query_parser->set_heed_colons(1); # enable field:value AND/OR/NOT syntax |
167 |
|
my $query = $query_parser->parse( $full_q ); |
168 |
my $hits = $searcher->search( |
my $hits = $searcher->search( |
169 |
query => $full_q, |
query => $query, |
170 |
# offset => $offset, |
# offset => $offset, |
171 |
# num_wanted => $hits_per_page, |
# num_wanted => $hits_per_page, |
172 |
); |
); |
173 |
|
|
174 |
my $num_hits = $hits->total_hits; |
$self->hits( $hits->total_hits ); |
175 |
|
|
176 |
$self->log->debug("found $num_hits results"); |
$self->log->debug("found ", $self->hits, " results"); |
177 |
|
|
178 |
my $collection = Grep::Model::ItemCollection->new(); |
my $collection = Grep::Model::ItemCollection->new(); |
179 |
|
|
180 |
my @results; |
my @results; |
181 |
|
|
182 |
my $i = 0; |
my $i = 0; |
183 |
while ( my $hit = $hits->fetch_hit_hashref ) { |
while ( my $hit = $hits->fetch_hit ) { |
184 |
|
|
185 |
my $score = $hit->{score}; |
my $score = $hit->{score}; |
186 |
my $title = $hit->{title}; |
my $title = $hit->{title}; |
187 |
my $id = $hit->{id}; |
my $id = $hit->{id}; |
188 |
|
|
189 |
$self->log->debug("result $i $score $title"); |
$self->log->debug("result $i [$id] $title $score"); |
190 |
|
|
191 |
my $item = Grep::Model::Item->new(); |
my $item = Grep::Model::Item->new(); |
192 |
my ($ok,$msg) = $item->load_by_cols( id => $id ); |
my ($ok,$msg) = $item->load_by_cols( id => $id ); |
221 |
|
|
222 |
undef $self; |
undef $self; |
223 |
|
|
224 |
return; |
return 1; |
225 |
} |
} |
226 |
|
|
|
=cut |
|
|
|
|
227 |
=head2 snippet |
=head2 snippet |
228 |
|
|
229 |
my $short = $self->snippet( 50, $text ); |
my $short = $self->snippet( 50, $text ); |
248 |
package Grep::Search::KeywordField; |
package Grep::Search::KeywordField; |
249 |
use base qw( KinoSearch::Schema::FieldSpec ); |
use base qw( KinoSearch::Schema::FieldSpec ); |
250 |
sub analyzed { 0 } |
sub analyzed { 0 } |
251 |
|
#sub indexed { 1 } |
252 |
|
#sub stored { 1 } |
253 |
|
sub vectorized { 0 } |
254 |
|
|
255 |
package Grep::Search::Schema; |
package Grep::Search::Schema; |
256 |
|
|
257 |
=head1 NAME |
=head1 NAME |
258 |
|
|
259 |
Grep::Search::Schema - data definition |
Grep::Search::Schema - schema definition for full-text search |
260 |
|
|
261 |
=cut |
=cut |
262 |
|
|
278 |
summary => 'KinoSearch::Schema::FieldSpec', |
summary => 'KinoSearch::Schema::FieldSpec', |
279 |
category => 'KinoSearch::Schema::FieldSpec', |
category => 'KinoSearch::Schema::FieldSpec', |
280 |
author => 'KinoSearch::Schema::FieldSpec', |
author => 'KinoSearch::Schema::FieldSpec', |
281 |
issued => 'Grep::Search::KeywordField', |
created_on => 'Grep::Search::KeywordField', |
282 |
modified => 'Grep::Search::KeywordField', |
last_update => 'Grep::Search::KeywordField', |
283 |
|
|
284 |
_owner_id => 'Grep::Search::KeywordField', |
_owner_id => 'Grep::Search::KeywordField', |
285 |
); |
); |