|
Lines 56-64
sub new {
Link Here
|
| 56 |
} |
56 |
} |
| 57 |
|
57 |
|
| 58 |
sub handle_hit { |
58 |
sub handle_hit { |
| 59 |
my ( $self, $index, $server, $marcrecord ) = @_; |
59 |
my ( $self, $index, $server, $hit ) = @_; |
| 60 |
|
60 |
|
| 61 |
my $record = Koha::MetadataRecord->new( { schema => 'marc', record => $marcrecord } ); |
61 |
my $record = Koha::MetadataRecord->new( { schema => 'marc', record => $hit->{record} } ); |
| 62 |
|
62 |
|
| 63 |
my %fetch = ( |
63 |
my %fetch = ( |
| 64 |
title => 'biblio.title', |
64 |
title => 'biblio.title', |
|
Lines 79-93
sub handle_hit {
Link Here
|
| 79 |
$metadata->{date} //= $metadata->{date2}; |
79 |
$metadata->{date} //= $metadata->{date2}; |
| 80 |
|
80 |
|
| 81 |
push @{ $self->{results} }, { |
81 |
push @{ $self->{results} }, { |
|
|
82 |
%$hit, |
| 82 |
server => $server, |
83 |
server => $server, |
| 83 |
index => $index, |
84 |
index => $index, |
| 84 |
record => $marcrecord, |
|
|
| 85 |
metadata => $metadata, |
85 |
metadata => $metadata, |
| 86 |
}; |
86 |
}; |
| 87 |
} |
87 |
} |
| 88 |
|
88 |
|
| 89 |
sub search { |
89 |
sub search { |
| 90 |
my ( $self, $server_ids, $query ) = @_; |
90 |
my ( $self, $server_ids, $terms ) = @_; |
| 91 |
|
91 |
|
| 92 |
my $resultset_expiry = 300; |
92 |
my $resultset_expiry = 300; |
| 93 |
|
93 |
|
|
Lines 142-148
sub search {
Link Here
|
| 142 |
} |
142 |
} |
| 143 |
} |
143 |
} |
| 144 |
|
144 |
|
| 145 |
$select->add( $self->_start_worker( $server, $query ) ); |
145 |
$select->add( $self->_start_worker( $server, $terms ) ); |
| 146 |
} |
146 |
} |
| 147 |
|
147 |
|
| 148 |
# Handle these while the servers are searching |
148 |
# Handle these while the servers are searching |
|
Lines 182-189
sub search {
Link Here
|
| 182 |
return $stats; |
182 |
return $stats; |
| 183 |
} |
183 |
} |
| 184 |
|
184 |
|
|
|
185 |
our $_pqf_mapping = { |
| 186 |
author => '1=1004', |
| 187 |
'cn-dewey' => '1=13', |
| 188 |
'cn-lc' => '1=16', |
| 189 |
date => '1=30', |
| 190 |
isbn => '1=7', |
| 191 |
issn => '1=8', |
| 192 |
keyword => '1=1016', |
| 193 |
lccn => '1=9', |
| 194 |
'local-number' => '1=12', |
| 195 |
'music-identifier' => '1=51', |
| 196 |
'standard-identifier' => '1=1007', |
| 197 |
subject => '1=21', |
| 198 |
title => '1=4', |
| 199 |
}; |
| 200 |
|
| 201 |
our $_batch_db_mapping = { |
| 202 |
author => 'import_biblios.author', |
| 203 |
isbn => 'import_biblios.isbn', |
| 204 |
issn => 'import_biblios.issn', |
| 205 |
'local-number' => 'import_biblios.control_number', |
| 206 |
title => 'import_biblios.title', |
| 207 |
}; |
| 208 |
|
| 209 |
our $_batch_db_text_columns = { |
| 210 |
author => 1, |
| 211 |
keyword => 1, |
| 212 |
title => 1, |
| 213 |
}; |
| 214 |
|
| 215 |
sub _pqf_query_from_terms { |
| 216 |
my ( $terms ) = @_; |
| 217 |
|
| 218 |
my $query; |
| 219 |
|
| 220 |
while ( my ( $index, $value ) = each %$terms ) { |
| 221 |
$value =~ s/"/\\"/; |
| 222 |
|
| 223 |
my $term = '@attr ' . $_pqf_mapping->{$index} . ' "' . $value . '"'; |
| 224 |
|
| 225 |
if ( $query ) { |
| 226 |
$query = '@and ' . $query . ' ' . $term; |
| 227 |
} else { |
| 228 |
$query = $term; |
| 229 |
} |
| 230 |
} |
| 231 |
|
| 232 |
return $query; |
| 233 |
} |
| 234 |
|
| 235 |
sub _db_query_get_match_conditions { |
| 236 |
my ( $index, $value ) = @_; |
| 237 |
|
| 238 |
if ( $value =~ /\*/ ) { |
| 239 |
$value =~ s/\*/%/; |
| 240 |
return { -like => $value }; |
| 241 |
} elsif ( $_batch_db_text_columns->{$index} ) { |
| 242 |
return map +{ -regexp => '[[:<:]]' . $_ . '[[:>:]]' }, split( /\s+/, $value ); |
| 243 |
} else { |
| 244 |
return $value; |
| 245 |
} |
| 246 |
} |
| 247 |
|
| 248 |
sub _batch_db_query_from_terms { |
| 249 |
my ( $import_batch_id, $terms ) = @_; |
| 250 |
|
| 251 |
my @db_terms; |
| 252 |
|
| 253 |
while ( my ( $index, $value ) = each %$terms ) { |
| 254 |
if ( $index eq 'keyword' ) { |
| 255 |
my @term; |
| 256 |
|
| 257 |
while ( my ( $index, $db_column ) = each %$_batch_db_mapping ) { |
| 258 |
push @term, { $db_column => [ _db_query_get_match_conditions( $index, $value ) ] }; |
| 259 |
} |
| 260 |
|
| 261 |
# These are implicitly joined with OR because the arrayref doesn't start with -and |
| 262 |
push @db_terms, \@term; |
| 263 |
} elsif ( $_batch_db_mapping->{$index} ) { |
| 264 |
push @db_terms, $_batch_db_mapping->{$index} => [ -and => _db_query_get_match_conditions( $index, $value ) ]; |
| 265 |
} else { |
| 266 |
# No such index, we should fail |
| 267 |
return undef; |
| 268 |
} |
| 269 |
} |
| 270 |
|
| 271 |
return { |
| 272 |
-and => [ |
| 273 |
import_batch_id => $import_batch_id, |
| 274 |
@db_terms |
| 275 |
], |
| 276 |
}, |
| 277 |
} |
| 278 |
|
| 185 |
sub _start_worker { |
279 |
sub _start_worker { |
| 186 |
my ( $self, $server, $query ) = @_; |
280 |
my ( $self, $server, $terms ) = @_; |
| 187 |
pipe my $readfh, my $writefh; |
281 |
pipe my $readfh, my $writefh; |
| 188 |
|
282 |
|
| 189 |
# Accessing the cache or Koha database after the fork is risky, so get any resources we need |
283 |
# Accessing the cache or Koha database after the fork is risky, so get any resources we need |
|
Lines 207-212
sub _start_worker {
Link Here
|
| 207 |
my $connection; |
301 |
my $connection; |
| 208 |
my ( $num_hits, $num_fetched, $hits, $results ); |
302 |
my ( $num_hits, $num_fetched, $hits, $results ); |
| 209 |
|
303 |
|
|
|
304 |
my $pqf_query = _pqf_query_from_terms( $terms ); |
| 305 |
|
| 210 |
eval { |
306 |
eval { |
| 211 |
if ( $server->{type} eq 'z3950' ) { |
307 |
if ( $server->{type} eq 'z3950' ) { |
| 212 |
my $zoptions = ZOOM::Options->new(); |
308 |
my $zoptions = ZOOM::Options->new(); |
|
Lines 220-285
sub _start_worker {
Link Here
|
| 220 |
$connection = ZOOM::Connection->create($zoptions); |
316 |
$connection = ZOOM::Connection->create($zoptions); |
| 221 |
|
317 |
|
| 222 |
$connection->connect( $server->{host}, $server->{port} ); |
318 |
$connection->connect( $server->{host}, $server->{port} ); |
| 223 |
$results = $connection->search_pqf( $query ); # Starts the search |
319 |
$results = $connection->search_pqf( $pqf_query ); # Starts the search |
| 224 |
} elsif ( $server->{type} eq 'koha' ) { |
320 |
} elsif ( $server->{type} eq 'koha' ) { |
| 225 |
$connection = C4::Context->Zconn( $server->{extra} ); |
321 |
$connection = C4::Context->Zconn( $server->{extra} ); |
| 226 |
$results = $connection->search_pqf( $query ); # Starts the search |
322 |
$results = $connection->search_pqf( $pqf_query ); # Starts the search |
| 227 |
} elsif ( $server->{type} eq 'batch' ) { |
323 |
} elsif ( $server->{type} eq 'batch' ) { |
| 228 |
$server->{encoding} = 'utf-8'; |
324 |
$server->{encoding} = 'utf-8'; |
| 229 |
} |
325 |
} |
| 230 |
}; |
326 |
}; |
| 231 |
if ($@) { |
327 |
if ($@) { |
| 232 |
store_fd { |
328 |
store_fd { |
| 233 |
error => $connection ? $connection->exception() : $@, |
329 |
error => $connection ? $connection->exception()->message() : $@, |
| 234 |
server => $server, |
330 |
server => $server, |
| 235 |
}, $writefh; |
331 |
}, $writefh; |
| 236 |
exit; |
332 |
exit; |
| 237 |
} |
333 |
} |
| 238 |
|
334 |
|
|
|
335 |
my $error; |
| 239 |
if ( $server->{type} eq 'batch' ) { |
336 |
if ( $server->{type} eq 'batch' ) { |
| 240 |
# TODO: actually handle PQF |
|
|
| 241 |
$query =~ s/@\w+ (?:\d+=\d+ )?//g; |
| 242 |
$query =~ s/"//g; |
| 243 |
|
| 244 |
my $schema = Koha::Database->new->schema; |
337 |
my $schema = Koha::Database->new->schema; |
| 245 |
$schema->storage->debug(1); |
338 |
my $db_query = _batch_db_query_from_terms( $server->{extra}, $terms ); |
| 246 |
my $match_condition = [ map +{ -like => '%' . $_ . '%' }, split( /\s+/, $query ) ]; |
339 |
|
| 247 |
$hits = [ $schema->resultset('ImportRecord')->search( |
340 |
if ( $db_query ) { |
| 248 |
{ |
341 |
$hits = [ $schema->resultset('ImportRecord')->search( |
| 249 |
import_batch_id => $server->{extra}, |
342 |
$db_query, |
| 250 |
-or => [ |
343 |
{ |
| 251 |
{ 'import_biblios.title' => $match_condition }, |
344 |
columns => [ 'import_record_id', { record => 'marc' } ], |
| 252 |
{ 'import_biblios.author' => $match_condition }, |
345 |
join => [ 'import_biblios' ], |
| 253 |
{ 'import_biblios.isbn' => $match_condition }, |
346 |
offset => $self->{offset}, |
| 254 |
{ 'import_biblios.issn' => $match_condition }, |
347 |
result_class => 'DBIx::Class::ResultClass::HashRefInflator', |
| 255 |
], |
348 |
rows => $self->{fetch}, |
| 256 |
}, |
349 |
} |
| 257 |
{ |
350 |
)->all ]; |
| 258 |
join => [ qw( import_biblios ) ], |
351 |
|
| 259 |
rows => $self->{fetch}, |
352 |
$num_hits = $num_fetched = scalar @$hits; |
| 260 |
} |
353 |
} else { |
| 261 |
)->get_column( 'marc' )->all ]; |
354 |
$error = "Invalid search"; |
| 262 |
|
355 |
} |
| 263 |
$num_hits = $num_fetched = scalar @$hits; |
|
|
| 264 |
} else { |
356 |
} else { |
| 265 |
$num_hits = $results->size; |
357 |
$num_hits = $results->size; |
| 266 |
$num_fetched = ( $self->{offset} + $self->{fetch} ) < $num_hits ? $self->{fetch} : $num_hits; |
358 |
$num_fetched = ( $self->{offset} + $self->{fetch} ) < $num_hits ? $self->{fetch} : $num_hits; |
| 267 |
|
359 |
|
| 268 |
$hits = [ map { $_->raw() } @{ $results->records( $self->{offset}, $num_fetched, 1 ) } ]; |
360 |
$hits = [ map +{ record => $_->raw() }, @{ $results->records( $self->{offset}, $num_fetched, 1 ) } ]; |
|
|
361 |
|
| 362 |
$error = $connection->exception()->message() if ( !@$hits && $connection && $connection->exception() ); |
| 269 |
} |
363 |
} |
| 270 |
|
364 |
|
| 271 |
if ( !@$hits && $connection && $connection->exception() ) { |
365 |
if ( $error ) { |
| 272 |
store_fd { |
366 |
store_fd { |
| 273 |
error => $connection->exception(), |
367 |
error => $error, |
| 274 |
server => $server, |
368 |
server => $server, |
| 275 |
}, $writefh; |
369 |
}, $writefh; |
| 276 |
exit; |
370 |
exit; |
| 277 |
} |
371 |
} |
| 278 |
|
372 |
|
| 279 |
if ( $server->{type} eq 'koha' ) { |
373 |
if ( $server->{type} eq 'koha' ) { |
| 280 |
$hits = [ map { C4::Search::new_record_from_zebra( $server->{extra}, $_ ) } @$hits ]; |
374 |
$hits = [ map +{ %$_, record => C4::Search::new_record_from_zebra( $server->{extra}, $_->{record} ) }, @$hits ]; |
| 281 |
} else { |
375 |
} else { |
| 282 |
$hits = [ map { $self->_import_record( $_, $marcflavour, $server->{encoding} ? $server->{encoding} : "iso-5426" ) } @$hits ]; |
376 |
$hits = [ map +{ %$_, record => $self->_import_record( $_->{record}, $marcflavour, $server->{encoding} ? $server->{encoding} : "iso-5426" ) }, @$hits ]; |
| 283 |
} |
377 |
} |
| 284 |
|
378 |
|
| 285 |
store_fd { |
379 |
store_fd { |