7 |
Catalyst::Model |
Catalyst::Model |
8 |
/; |
/; |
9 |
use WebPAC::Store 0.08; |
use WebPAC::Store 0.08; |
10 |
use WebPAC::Search::Estraier 0.05; |
use Search::Estraier 0.04; |
11 |
use File::Slurp; |
use File::Slurp; |
12 |
use Time::HiRes qw/time/; |
use Time::HiRes qw/time/; |
13 |
use Encode qw/encode decode from_to/; |
use Encode qw/encode decode from_to/; |
74 |
$est_cfg->{database} = $defaultnode; |
$est_cfg->{database} = $defaultnode; |
75 |
} |
} |
76 |
|
|
77 |
$self->{est} = new WebPAC::Search::Estraier( %{ $est_cfg } ); |
my $url = $est_cfg->{masterurl} . '/node/' . $est_cfg->{database}; |
78 |
|
|
79 |
|
$log->info("opening Hyper Estraier index $url as $est_cfg->{'user'}"); |
80 |
|
|
81 |
|
$self->{est_node} = Search::Estraier::Node->new( |
82 |
|
url => $url, |
83 |
|
user => $est_cfg->{user}, |
84 |
|
passwd => $est_cfg->{passwd}, |
85 |
|
); |
86 |
|
|
87 |
|
$log->fatal("can't create Search::Estraier::Node $url") unless ($self->{est_node}); |
88 |
|
|
89 |
# save config parametars in object |
# save config parametars in object |
90 |
foreach my $f (qw/db_path template_path hits_on_page webpac_encoding defaultdepth/) { |
foreach my $f (qw/db_path template_path hits_on_page webpac_encoding defaultdepth/) { |
111 |
"'" |
"'" |
112 |
); |
); |
113 |
|
|
114 |
$self->{databases} = $c->config->{databases} || $log->error("can't find databases in config"); |
$self->{databases} = $c->config->{databases} || $log->fatal("can't find databases in config"); |
115 |
|
|
116 |
# create Template toolkit instance |
# create Template toolkit instance |
117 |
$self->{'tt'} = Template->new( |
$self->{'tt'} = Template->new( |
169 |
|
|
170 |
my $query = $args->{phrase} || $log->warn("no query phrase") && return; |
my $query = $args->{phrase} || $log->warn("no query phrase") && return; |
171 |
|
|
|
$log->debug("search model query: '$query'"); |
|
|
if ($args->{add_attr}) { |
|
|
$log->debug(" + add_attr: " . |
|
|
join("','", @{ $args->{add_attr} }) |
|
|
); |
|
|
} |
|
|
|
|
172 |
my $template_filename = $args->{template} || $self->{template}; |
my $template_filename = $args->{template} || $self->{template}; |
173 |
|
|
174 |
$args->{max} ||= $self->{'hits_for_pager'}; |
$args->{max} ||= $self->{'hits_for_pager'}; |
187 |
$args->{depth} = $default; |
$args->{depth} = $default; |
188 |
$log->warn("using default search depth $default"); |
$log->warn("using default search depth $default"); |
189 |
} |
} |
190 |
|
$args->{depth} ||= 0; |
191 |
|
|
192 |
my @results = $self->{est}->search( %{ $args } ); |
$log->debug("searching for maximum $args->{max} results using depth $args->{depth} phrase: ", $query || '[none]'); |
193 |
|
|
194 |
$times->{est} += time() - $t; |
# |
195 |
|
# construct condition for Hyper Estraier |
196 |
|
# |
197 |
|
my $cond = Search::Estraier::Condition->new(); |
198 |
|
if ( ref($args->{add_attr}) eq 'ARRAY' ) { |
199 |
|
$log->debug("adding search attributes: " . join(", ", @{ $args->{add_attr} }) ); |
200 |
|
map { |
201 |
|
$cond->add_attr( $_ ); |
202 |
|
$log->debug(" + $_"); |
203 |
|
} @{ $args->{add_attr} }; |
204 |
|
}; |
205 |
|
|
206 |
|
$cond->set_phrase( $query ) if ($query); |
207 |
|
$cond->set_options( $args->{options} ) if ($args->{options}); |
208 |
|
$cond->set_order( $args->{order} ) if ($args->{order}); |
209 |
|
|
210 |
|
my $max = $args->{max} || 7; |
211 |
|
my $page = $args->{page} || 1; |
212 |
|
if ($page < 1) { |
213 |
|
$log->warn("page number $page < 1"); |
214 |
|
$page = 1; |
215 |
|
} |
216 |
|
|
217 |
|
$cond->set_max( $page * $max ); |
218 |
|
|
219 |
my $hits = $#results + 1; |
my $result = $self->{est_node}->search($cond, $args->{depth}); |
220 |
|
my $hits = $result->doc_num; |
221 |
|
|
222 |
|
$times->{est} += time() - $t; |
223 |
|
|
224 |
$log->debug( sprintf("search took %.6fs and returned $hits hits.", $times->{est}) ); |
$log->debug( sprintf("search took %.6fs and returned $hits hits.", $times->{est}) ); |
225 |
|
|
226 |
# just return results? |
$log->debug( "hints: " . Dumper($result->{hints}) ); |
|
return @results unless ($args->{'template'}); |
|
227 |
|
|
228 |
# |
# |
229 |
# construct HTML results |
# fetch results |
230 |
# |
# |
231 |
|
|
232 |
my @html_results; |
my @results; |
233 |
|
|
234 |
for my $i ( 0 .. $#results ) { |
for my $i ( (($page - 1) * $max) .. ( $hits - 1 ) ) { |
235 |
|
|
236 |
my ($database, $prefix, $id); |
$t = time(); |
237 |
if ( $results[$i]->{'@uri'} =~ m!/([^/]+)/([^/]+)/(\d+)$!) { |
|
238 |
($database, $prefix,$id) = ($1,$2,$3); |
#$log->debug("get_doc($i)"); |
239 |
} else { |
my $doc = $result->get_doc( $i ); |
240 |
$log->warn("can't decode database/prefix/id from " . $results[$i]->{'@uri'}); |
if (! $doc) { |
241 |
|
$log->warn("can't find result $i"); |
242 |
next; |
next; |
243 |
} |
} |
244 |
|
|
245 |
#$log->debug("load_ds( id => $id, prefix => '$prefix' )"); |
my $hash; |
|
|
|
|
$t = time(); |
|
246 |
|
|
247 |
my $ds = $self->{db}->load_ds( database => $database, prefix => $prefix, id => $id ); |
foreach my $attr (@{ $args->{get_attr} }) { |
248 |
if (! $ds) { |
my $val = $doc->attr( $attr ); |
249 |
$log->error("can't load_ds( ${database}/${prefix}/${id} )"); |
#$log->debug("attr $attr = ", $val || 'undef'); |
250 |
next; |
$hash->{$attr} = $val if (defined($val)); |
251 |
} |
} |
252 |
|
|
253 |
$times->{db} += time() - $t; |
$times->{hash} += time() - $t; |
254 |
|
|
255 |
#$log->debug( "ds = " . Dumper( \@html_results ) ); |
next unless ($hash); |
256 |
|
|
257 |
$t = time(); |
if (! $args->{'template'}) { |
258 |
|
push @results, $hash; |
259 |
|
} else { |
260 |
|
my ($database, $prefix, $id); |
261 |
|
|
262 |
my $html = $self->apply( |
if ( $hash->{'@uri'} =~ m!/([^/]+)/([^/]+)/(\d+)$!) { |
263 |
template => $template_filename, |
($database, $prefix,$id) = ($1,$2,$3); |
264 |
data => $ds, |
} else { |
265 |
record_uri => "${database}/${prefix}/${id}", |
$log->warn("can't decode database/prefix/id from " . $hash->{'@uri'}); |
266 |
config => $self->{databases}->{$database}, |
next; |
267 |
); |
} |
268 |
|
|
269 |
$times->{out} += time() - $t; |
#$log->debug("load_ds( id => $id, prefix => '$prefix' )"); |
270 |
|
|
271 |
$t = time(); |
$t = time(); |
272 |
|
|
273 |
|
my $ds = $self->{db}->load_ds( database => $database, prefix => $prefix, id => $id ); |
274 |
|
if (! $ds) { |
275 |
|
$log->error("can't load_ds( ${database}/${prefix}/${id} )"); |
276 |
|
next; |
277 |
|
} |
278 |
|
|
279 |
$html = decode($self->{webpac_encoding}, $html); |
$times->{db} += time() - $t; |
280 |
|
|
281 |
push @html_results, $html; |
#$log->debug( "ds = " . Dumper( \@html_results ) ); |
282 |
|
|
283 |
|
$t = time(); |
284 |
|
|
285 |
|
my $html = $self->apply( |
286 |
|
template => $template_filename, |
287 |
|
data => $ds, |
288 |
|
record_uri => "${database}/${prefix}/${id}", |
289 |
|
config => $self->{databases}->{$database}, |
290 |
|
); |
291 |
|
|
292 |
|
$times->{apply} += time() - $t; |
293 |
|
|
294 |
|
$t = time(); |
295 |
|
|
296 |
|
$html = decode($self->{webpac_encoding}, $html); |
297 |
|
|
298 |
|
$times->{decode} += time() - $t; |
299 |
|
|
300 |
|
push @results, $html; |
301 |
|
} |
302 |
|
|
303 |
} |
} |
304 |
|
|
305 |
#$log->debug( '@html_results = ' . Dumper( \@html_results ) ); |
#$log->debug( '@results = ' . Dumper( \@results ) ); |
306 |
|
|
307 |
$log->debug( sprintf( |
$log->debug( sprintf( |
308 |
"duration breakdown: store %.6fs, apply %.6fs, total: %.6fs", |
"duration breakdown: estraier %.6fs, hash %.6fs, store %.6fs, apply %.6fs, decode %.06f, total: %.6fs", |
309 |
$times->{db}, $times->{out}, time() - $search_start_t, |
$times->{est}, $times->{hash}, $times->{db}, $times->{apply}, $times->{decode}, time() - $search_start_t, |
310 |
) ); |
) ); |
311 |
|
|
312 |
return \@html_results; |
return \@results; |
313 |
} |
} |
314 |
|
|
315 |
=head2 record |
=head2 record |
442 |
my $log = $self->{log} || die "no log?"; |
my $log = $self->{log} || die "no log?"; |
443 |
|
|
444 |
foreach my $a (qw/template data/) { |
foreach my $a (qw/template data/) { |
445 |
$log->logconfess("need $a") unless ($args->{$a}); |
$log->fatal("need $a") unless ($args->{$a}); |
446 |
} |
} |
447 |
|
|
448 |
=head3 tt_filter_type |
=head3 tt_filter_type |
551 |
|
|
552 |
my $s; |
my $s; |
553 |
if ($s_el > 0) { |
if ($s_el > 0) { |
554 |
$s = $item->{'search'}->[$i] || die "can't find value $i for type search in field $search"; |
$s = $item->{'search'}->[$i] or warn "can't find value $i for type search in field $search"; |
555 |
} else { |
} else { |
556 |
$s = $item->{'search'}->[0]; |
$s = $item->{'search'}->[0]; |
557 |
} |
} |
558 |
#$s =~ s/([^\w.-])/sprintf("%%%02X",ord($1))/eg; |
#$s =~ s/([^\w.-])/sprintf("%%%02X",ord($1))/eg; |
559 |
$s = __quotemeta( $s ); |
$s = __quotemeta( $s ); |
560 |
|
|
561 |
my $d = $item->{'display'}->[$i] || die "can't find value $i for type display in field $display"; |
my $d = $item->{'display'}->[$i] or warn "can't find value $i for type display in field $display"; |
562 |
|
|
563 |
my $template_arg = ''; |
my $template_arg = ''; |
564 |
$template_arg = qq{,'$template'} if ($template); |
$template_arg = qq{,'$template'} if ($template); |