Bug 11137: fix certain types of searches run using QueryParser
[koha.git] / Koha / QueryParser / Driver / PQF.pm
blob8181cd3dd14170c2ede1e419e8abce8c7b243ae4
1 package Koha::QueryParser::Driver::PQF;
3 # This file is part of Koha.
5 # Copyright 2012 C & P Bibliography Services
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use base qw(OpenILS::QueryParser Class::Accessor);
22 use strict;
23 use warnings;
25 use Module::Load::Conditional qw(can_load);
26 use Koha::QueryParser::Driver::PQF::Util;
27 use Koha::QueryParser::Driver::PQF::query_plan;
28 use Koha::QueryParser::Driver::PQF::query_plan::facet;
29 use Koha::QueryParser::Driver::PQF::query_plan::filter;
30 use Koha::QueryParser::Driver::PQF::query_plan::modifier;
31 use Koha::QueryParser::Driver::PQF::query_plan::node;
32 use Koha::QueryParser::Driver::PQF::query_plan::node::atom;
33 use Koha::QueryParser::Driver::PQF::query_plan::node::atom;
36 =head1 NAME
38 Koha::QueryParser::Driver::PQF - QueryParser driver for PQF
40 =head1 SYNOPSIS
42 use Koha::QueryParser::Driver::PQF;
43 my $QParser = Koha::QueryParser::Driver::PQF->new(%args);
45 =head1 DESCRIPTION
47 Main entrypoint into the QueryParser PQF driver. PQF is the Prefix Query
48 Language, the syntax used to serialize Z39.50 queries.
50 =head1 ACCESSORS
52 In order to simplify Bib-1 attribute mapping, this driver uses Class::Accessor
53 for accessing the following maps:
55 =over 4
57 =item B<bib1_field_map> - search class/field Bib-1 mappings
59 =item B<bib1_modifier_map> - search modifier mappings
61 =item B<bib1_filter_map> - search filter mappings
63 =item B<bib1_relevance_bump_map> - relevance bump mappings
65 =back
67 =cut
69 __PACKAGE__->mk_accessors(qw(bib1_field_map bib1_modifier_map bib1_filter_map bib1_relevance_bump_map));
71 =head1 FUNCTIONS
73 =cut
75 =head2 get
77 Overridden accessor method for Class::Accessor. (Do not call directly)
79 =cut
81 sub get {
82 my $self = shift;
83 return $self->_map(@_);
86 =head2 set
88 Overridden mutator method for Class::Accessor. (Do not call directly)
90 =cut
92 sub set {
93 my $self = shift;
94 return $self->_map(@_);
97 =head2 add_bib1_field_map
99 $QParser->add_bib1_field_map($class => $field => $server => \%attributes);
101 $QParser->add_bib1_field_map('author' => 'personal' => 'biblioserver' =>
102 { '1' => '1003' });
104 Adds a search field<->bib1 attribute mapping for the specified server. The
105 %attributes hash contains maps Bib-1 Attributes to the appropropriate
106 values. Not all attributes must be specified.
108 =cut
110 sub add_bib1_field_map {
111 my ($self, $class, $field, $server, $attributes) = @_;
113 $self->add_search_field( $class => $field );
114 return $self->_add_field_mapping($self->bib1_field_map, $class, $field, $server, $attributes);
117 =head2 add_bib1_modifier_map
119 $QParser->add_bib1_modifier_map($name => $server => \%attributes);
121 $QParser->add_bib1_modifier_map('ascending' => 'biblioserver' =>
122 { '7' => '1' });
124 Adds a search modifier<->bib1 attribute mapping for the specified server. The
125 %attributes hash contains maps Bib-1 Attributes to the appropropriate
126 values. Not all attributes must be specified.
128 =cut
130 sub add_bib1_modifier_map {
131 my ($self, $name, $server, $attributes) = @_;
133 $self->add_search_modifier( $name );
135 return $self->_add_mapping($self->bib1_modifier_map, $name, $server, $attributes);
138 =head2 add_bib1_filter_map
140 $QParser->add_bib1_filter_map($name => $server => \%attributes);
142 $QParser->add_bib1_filter_map('date' => 'biblioserver' =>
143 { 'callback' => &_my_callback });
145 Adds a search filter<->bib1 attribute mapping for the specified server. The
146 %attributes hash maps Bib-1 Attributes to the appropropriate values and
147 provides a callback for the filter. Not all attributes must be specified.
149 =cut
151 sub add_bib1_filter_map {
152 my ($self, $name, $server, $attributes) = @_;
154 $self->add_search_filter( $name, $attributes->{'callback'} );
156 return $self->_add_mapping($self->bib1_filter_map, $name, $server, $attributes);
159 =head2 add_relevance_bump
161 $QParser->add_relevance_bump($class, $field, $server, $multiplier, $active);
162 $QParser->add_relevance_bump('title' => 'exact' => 'biblioserver' => 34, 1);
164 Add a relevance bump to the specified field. When searching for a class without
165 any fields, all the relevance bumps for the specified class will be 'OR'ed
166 together.
168 =cut
170 sub add_relevance_bump {
171 my ($self, $class, $field, $server, $multiplier, $active) = @_;
172 my $attributes = { '9' => $multiplier, '2' => '102', 'active' => $active };
174 $self->add_search_field( $class => $field );
175 return $self->_add_field_mapping($self->bib1_relevance_bump_map, $class, $field, $server, $attributes);
179 =head2 target_syntax
181 my $pqf = $QParser->target_syntax($server, [$query]);
182 my $pqf = $QParser->target_syntax('biblioserver', 'author|personal:smith');
183 print $pqf; # assuming all the indexes are configured,
184 # prints '@attr 1=1003 @attr 4=6 "smith"'
186 Transforms the current or specified query into a PQF query string for the
187 specified server.
189 =cut
191 sub target_syntax {
192 my ($self, $server, $query) = @_;
193 my $pqf = '';
194 $self->parse($query) if $query;
195 warn "QP query for $server: " . $self->query . "\n" if $self->debug;
196 $pqf = $self->parse_tree->target_syntax($server);
197 warn "PQF query: $pqf\n" if $self->debug;
198 $pqf =~ s/ +/ /g;
199 $pqf =~ s/^ //;
200 $pqf =~ s/ $//;
201 return $pqf;
204 =head2 date_filter_target_callback
206 $QParser->add_bib1_filter_map($server, { 'target_syntax_callback' => \&Koha::QueryParser::Driver::PQF::date_filter_target_callback, '1' => 'pubdate' });
208 Callback for date filters. Note that although the first argument is the QParser
209 object, this is technically not an object-oriented routine. This has no
210 real-world implications.
212 =cut
214 sub date_filter_target_callback {
215 my ($QParser, $filter, $params, $negate, $server) = @_;
216 my $attr_string = $QParser->bib1_mapping_by_name( 'filter', $filter, $server )->{'attr_string'};
217 my $pqf = '';
218 foreach my $datespec (@$params) {
219 my $datepqf = ' ';
220 if ($datespec) {
221 if ($datespec =~ m/(.*)-(.*)/) {
222 if ($1) {
223 $datepqf .= $attr_string . ' @attr 2=4 "' . $1 . '"';
225 if ($2) {
226 $datepqf .= $attr_string . ' @attr 2=2 "' . $2 . '"';
227 $datepqf = ' @and ' . $datepqf if $1;
229 } else {
230 $datepqf .= $attr_string . ' "' . $datespec . '"';
233 $pqf = ' @or ' . ($negate ? '@not @attr 1=_ALLRECORDS @attr 2=103 "" ' : '') . $pqf if $pqf;
234 $pqf .= $datepqf;
236 return $pqf;
239 =head2 _map
241 return $self->_map('bib1_field_map', $map);
243 Retrieves or sets a map.
245 =cut
247 sub _map {
248 my ($self, $name, $map) = @_;
249 $self->custom_data->{$name} ||= {};
250 $self->custom_data->{$name} = $map if ($map);
251 return $self->custom_data->{$name};
254 =head2 _add_mapping
256 return $self->_add_mapping($map, $name, $server, $attributes)
258 Adds a mapping. Note that this is not used for mappings relating to fields.
260 =cut
262 sub _add_mapping {
263 my ($self, $map, $name, $server, $attributes) = @_;
265 my $attr_string = Koha::QueryParser::Driver::PQF::Util::attributes_to_attr_string($attributes);
266 $attributes->{'attr_string'} = $attr_string;
268 $map->{'by_name'}{$name}{$server} = $attributes;
269 $map->{'by_attr'}{$server}{$attr_string} = { 'name' => $name, %$attributes };
271 return $map;
274 =head2 _add_field_mapping
276 return $self->_add_field_mapping($map, $class, $field, $server, $attributes)
278 Adds a mapping for field-related data.
280 =cut
282 sub _add_field_mapping {
283 my ($self, $map, $class, $field, $server, $attributes) = @_;
284 my $attr_string = Koha::QueryParser::Driver::PQF::Util::attributes_to_attr_string($attributes);
285 $attributes->{'attr_string'} = $attr_string;
287 $map->{'by_name'}{$class}{$field}{$server} = $attributes;
288 $map->{'by_attr'}{$server}{$attr_string} = { 'classname' => $class, 'field' => $field, %$attributes };
289 return $map;
293 =head2 bib1_mapping_by_name
295 my $attributes = $QParser->bib1_mapping_by_name($type, $name[, $subname], $server);
296 my $attributes = $QParser->bib1_mapping_by_name('field', 'author', 'personal', 'biblioserver');
297 my $attributes = $QParser->bib1_mapping_by_name('filter', 'pubdate', 'biblioserver');
299 Retrieve the Bib-1 attribute set associated with the specified mapping.
300 =cut
302 sub bib1_mapping_by_name {
303 my $server = pop;
304 my ($self, $type, $name, $field) = @_;
306 return unless ($server && $name);
307 return unless ($type eq 'field' || $type eq 'modifier' || $type eq 'filter' || $type eq 'relevance_bump');
308 if ($type eq 'field' || $type eq 'relevance_bump') {
309 # Unfortunately field is a special case thanks to the class->field hierarchy
310 return $self->_map('bib1_' . $type . '_map')->{'by_name'}{$name}{$field}{$server} if $field;
311 return $self->_map('bib1_' . $type . '_map')->{'by_name'}{$name};
312 } else {
313 return $self->_map('bib1_' . $type . '_map')->{'by_name'}{$name}{$server};
317 =head2 bib1_mapping_by_attr
319 my $field = $QParser->bib1_mapping_by_attr($type, $server, \%attr);
320 my $field = $QParser->bib1_mapping_by_attr('field', 'biblioserver', {'1' => '1004'});
321 print $field->{'classname'}; # prints "author"
322 print $field->{'field'}; # prints "personal"
324 Retrieve the search field/modifier/filter used for the specified Bib-1 attribute set.
326 =cut
328 sub bib1_mapping_by_attr {
329 my ($self, $type, $server, $attributes) = @_;
330 return unless ($server && $attributes);
332 my $attr_string = Koha::QueryParser::Driver::PQF::Util::attributes_to_attr_string($attributes);
334 return $self->bib1_mapping_by_attr_string($type, $server, $attr_string);
337 =head2 bib1_mapping_by_attr_string
339 my $field = $QParser->bib1_mapping_by_attr_string($type, $server, $attr_string);
340 my $field = $QParser->bib1_mapping_by_attr_string('field', 'biblioserver', '@attr 1=1004');
341 print $field->{'classname'}; # prints "author"
342 print $field->{'field'}; # prints "personal"
344 Retrieve the search field/modifier/filter used for the specified Bib-1 attribute string
345 (i.e. PQF snippet).
347 =cut
349 sub bib1_mapping_by_attr_string {
350 my ($self, $type, $server, $attr_string) = @_;
351 return unless ($server && $attr_string);
352 return unless ($type eq 'field' || $type eq 'modifier' || $type eq 'filter' || $type eq 'relevance_bump');
354 return $self->_map('bib1_' . $type . '_map')->{'by_attr'}{$server}{$attr_string};
357 =head2 clear_all_configuration
359 $QParser->clear_all_configuration
361 Clear all configuration. This is a highly destructive method. You may
362 not want to use it.
364 =cut
366 sub clear_all_configuration {
367 my ($self) = @_;
368 %OpenILS::QueryParser::parser_config = (
369 'OpenILS::QueryParser' => {
370 filters => [],
371 modifiers => [],
372 operators => {
373 'and' => '&&',
374 'or' => '||',
375 float_start => '{{',
376 float_end => '}}',
377 group_start => '(',
378 group_end => ')',
379 required => '+',
380 disallowed => '-',
381 modifier => '#',
382 negated => '!'
386 return $self;
389 =head2 clear_all_mappings
391 $QParser->clear_all_mappings
393 Clear all bib-1 mappings.
395 =cut
397 sub clear_all_mappings {
398 my ($self) = @_;
400 foreach my $name (qw(field modifier filter relevance_bump)) {
401 $self->custom_data->{'bib1_' . $name . '_map'} = { };
403 return $self;
407 =head2 _canonicalize_field_map
409 Convert a field map into its canonical form for serialization. Used only for
410 fields and relevance bumps.
412 =cut
414 sub _canonicalize_field_map {
415 my ( $map, $aliases ) = @_;
416 my $canonical_map = {};
418 foreach my $class ( keys %{ $map->{'by_name'} } ) {
419 $canonical_map->{$class} ||= {};
420 foreach my $field ( keys %{ $map->{'by_name'}->{$class} } ) {
421 my $field_map = {
422 'index' => $field,
423 'label' => ucfirst($field),
424 'enabled' => '1',
426 foreach
427 my $server ( keys %{ $map->{'by_name'}->{$class}->{$field} } )
429 $field_map->{'bib1_mapping'} ||= {};
430 $field_map->{'bib1_mapping'}->{$server} =
431 $map->{'by_name'}->{$class}->{$field}->{$server};
432 delete $field_map->{'bib1_mapping'}->{$server}->{'attr_string'}
433 if defined(
434 $field_map->{'bib1_mapping'}->{$server}
435 ->{'attr_string'}
438 if ($aliases) {
439 $field_map->{'aliases'} = [];
440 foreach my $alias ( @{ $aliases->{$class}->{$field} } ) {
441 push @{ $field_map->{'aliases'} },
442 $alias;
445 $canonical_map->{$class}->{$field} = $field_map;
448 return $canonical_map;
451 =head2 _canonicalize_map
453 Convert a map into its canonical form for serialization. Not used for fields.
455 =cut
457 sub _canonicalize_map {
458 my ($map) = @_;
459 my $canonical_map = {};
461 foreach my $name ( keys %{ $map->{'by_name'} } ) {
462 $canonical_map->{$name} = {
463 'label' => ucfirst($name),
464 'enabled' => 1,
465 'bib1_mapping' => {}
467 foreach my $server ( keys %{ $map->{'by_name'}->{$name} } ) {
468 $canonical_map->{$name}->{'bib1_mapping'}->{$server} =
469 $map->{'by_name'}->{$name}->{$server};
470 delete $canonical_map->{$name}->{'bib1_mapping'}->{$server}
471 ->{'attr_string'}
472 if defined(
473 $canonical_map->{$name}->{'bib1_mapping'}->{$server}
474 ->{'attr_string'}
478 return $canonical_map;
481 =head2 serialize_mappings
483 my $yaml = $QParser->serialize_mappings;
484 my $json = $QParser->serialize_mappings('json');
486 Serialize Bib-1 mappings to YAML or JSON.
488 =cut
490 sub serialize_mappings {
491 my ( $self, $format ) = @_;
492 $format ||= 'yaml';
493 my $config;
495 $config->{'field_mappings'} =
496 _canonicalize_field_map( $self->bib1_field_map,
497 $self->search_field_aliases );
498 $config->{'modifier_mappings'} =
499 _canonicalize_map( $self->bib1_modifier_map );
500 $config->{'filter_mappings'} = _canonicalize_map( $self->bib1_filter_map );
501 $config->{'relevance_bumps'} =
502 _canonicalize_field_map( $self->bib1_relevance_bump_map );
504 if ( $format eq 'json' && can_load( modules => { 'JSON' => undef } ) ) {
505 return JSON::to_json($config);
507 elsif ( can_load( modules => { 'YAML::Any' => undef } ) ) {
508 return YAML::Any::Dump($config);
510 return;
513 =head2 initialize
515 $QParser->initialize( { 'bib1_field_mappings' => \%bib1_field_mappings,
516 'search_field_alias_mappings' => \%search_field_alias_mappings,
517 'bib1_modifier_mappings' => \%bib1_modifier_mappings,
518 'bib1_filter_mappings' => \%bib1_filter_mappings,
519 'relevance_bumps' => \%relevance_bumps });
521 Initialize the QueryParser mapping tables based on the provided configuration.
522 This method was written to play nice with YAML configuration files loaded by load_config.
524 =cut
526 sub initialize {
527 my ( $self, $args ) = @_;
529 my $field_mappings = $args->{'field_mappings'};
530 my $modifier_mappings = $args->{'modifier_mappings'};
531 my $filter_mappings = $args->{'filter_mappings'};
532 my $relbumps = $args->{'relevance_bumps'};
533 my ( $server, $bib1_mapping );
534 foreach my $class ( keys %$field_mappings ) {
535 foreach my $field ( keys %{ $field_mappings->{$class} } ) {
536 if ( $field_mappings->{$class}->{$field}->{'enabled'} ) {
537 while ( ( $server, $bib1_mapping ) =
538 each
539 %{ $field_mappings->{$class}->{$field}->{'bib1_mapping'} } )
541 $self->add_bib1_field_map(
542 $class => $field => $server => $bib1_mapping );
544 foreach my $alias (
545 @{ $field_mappings->{$class}->{$field}->{'aliases'} } )
547 $self->add_search_field_alias( $class => $field => $alias );
552 foreach my $modifier ( keys %$modifier_mappings ) {
553 if ( $modifier_mappings->{$modifier}->{'enabled'} ) {
554 while ( ( $server, $bib1_mapping ) =
555 each %{ $modifier_mappings->{$modifier}->{'bib1_mapping'} } )
557 $self->add_bib1_modifier_map(
558 $modifier => $server => $bib1_mapping );
562 foreach my $filter ( keys %$filter_mappings ) {
563 if ( $filter_mappings->{$filter}->{'enabled'} ) {
564 while ( ( $server, $bib1_mapping ) =
565 each %{ $filter_mappings->{$filter}->{'bib1_mapping'} } )
567 if ( $bib1_mapping->{'target_syntax_callback'} eq
568 'date_filter_target_callback' )
570 $bib1_mapping->{'target_syntax_callback'} =
571 \&Koha::QueryParser::Driver::PQF::date_filter_target_callback;
573 $self->add_bib1_filter_map(
574 $filter => $server => $bib1_mapping );
578 foreach my $class ( keys %$relbumps ) {
579 foreach my $field ( keys %{ $relbumps->{$class} } ) {
580 if ( $relbumps->{$class}->{$field}->{'enabled'} ) {
581 while ( ( $server, $bib1_mapping ) =
582 each %{ $relbumps->{$class}->{$field}->{'bib1_mapping'} } )
584 $self->add_relevance_bump(
585 $class => $field => $server => $bib1_mapping,
592 return $self;
595 =head2 load_config
597 $QParser->load_config($file_name);
599 Load a YAML file with a parser configuration. The YAML file should match the following format:
602 field_mappings:
603 author:
605 aliases:
606 - au
607 bib1_mapping:
608 biblioserver:
609 1: 1003
610 enabled: 1
611 index: ''
612 label: ''
613 conference:
614 aliases:
615 - conference
616 - cfn
617 bib1_mapping:
618 biblioserver:
619 1: 1006
620 enabled: 1
621 index: conference
622 label: Conference
623 filter_mappings:
624 acqdate:
625 bib1_mapping:
626 biblioserver:
627 1: Date-of-acquisition
628 4: 4
629 target_syntax_callback: date_filter_target_callback
630 enabled: 1
631 label: Acqdate
632 modifier_mappings:
633 AuthidAsc:
634 bib1_mapping:
635 authorityserver:
636 "": 0
637 1: Local-Number
638 7: 1
639 op: "@or"
640 enabled: 1
641 label: AuthidAsc
644 =cut
646 sub load_config {
647 my ($self, $file) = @_;
648 require YAML::Any;
649 return unless ($file && -f $file);
650 my $config = YAML::Any::LoadFile($file);
651 return unless ($config);
652 $self->initialize($config);
653 return 1;
656 =head2 TEST_SETUP
658 $QParser->TEST_SETUP
660 This routine initializes the QueryParser driver with a reasonable set of
661 defaults. This is intended only for testing. Although such test stubs are
662 generally not included in Koha, this type of test stub is used by other
663 QueryParser implementations, and it seems sensible to maintain consistency
664 as much as possible.
666 =cut
668 sub TEST_SETUP {
669 my ($self) = @_;
671 $self->default_search_class( 'keyword' );
673 $self->add_bib1_field_map('keyword' => 'abstract' => 'biblioserver' => { '1' => '62' } );
674 $self->add_search_field_alias( 'keyword' => 'abstract' => 'ab' );
675 $self->add_bib1_field_map('keyword' => '' => 'biblioserver' => { '1' => '1016' } );
676 $self->add_search_field_alias( 'keyword' => '' => 'kw' );
677 $self->add_bib1_field_map('author' => '' => 'biblioserver' => { '1' => '1003' } );
678 $self->add_search_field_alias( 'author' => '' => 'au' );
679 $self->add_bib1_field_map('author' => 'personal' => 'biblioserver' => { '1' => '1004' } );
680 $self->add_bib1_field_map('author' => 'corporate' => 'biblioserver' => { '1' => '1005' } );
681 $self->add_search_field_alias( 'author' => 'corporate' => 'cpn' );
682 $self->add_bib1_field_map('author' => 'conference' => 'biblioserver' => { '1' => '1006' } );
683 $self->add_search_field_alias( 'author' => 'conference' => 'cfn' );
684 $self->add_bib1_field_map('keyword' => 'local-classification' => 'biblioserver' => { '1' => '20' } );
685 $self->add_search_field_alias( 'keyword' => 'local-classification' => 'lcn' );
686 $self->add_search_field_alias( 'keyword' => 'local-classification' => 'callnum' );
687 $self->add_bib1_field_map('keyword' => 'bib-level' => 'biblioserver' => { '1' => '1021' } );
688 $self->add_bib1_field_map('keyword' => 'code-institution' => 'biblioserver' => { '1' => '56' } );
689 $self->add_bib1_field_map('keyword' => 'language' => 'biblioserver' => { '1' => '54' } );
690 $self->add_search_field_alias( 'keyword' => 'language' => 'ln' );
691 $self->add_bib1_field_map('keyword' => 'record-type' => 'biblioserver' => { '1' => '1001' } );
692 $self->add_search_field_alias( 'keyword' => 'record-type' => 'rtype' );
693 $self->add_search_field_alias( 'keyword' => 'record-type' => 'mc-rtype' );
694 $self->add_search_field_alias( 'keyword' => 'record-type' => 'mus' );
695 $self->add_bib1_field_map('keyword' => 'content-type' => 'biblioserver' => { '1' => '1034' } );
696 $self->add_search_field_alias( 'keyword' => 'content-type' => 'ctype' );
697 $self->add_bib1_field_map('keyword' => 'lc-card-number' => 'biblioserver' => { '1' => '9' } );
698 $self->add_search_field_alias( 'keyword' => 'lc-card-number' => 'lc-card' );
699 $self->add_bib1_field_map('keyword' => 'local-number' => 'biblioserver' => { '1' => '12' } );
700 $self->add_search_field_alias( 'keyword' => 'local-number' => 'sn' );
701 $self->add_bib1_filter_map( 'biblioserver', 'copydate', { 'target_syntax_callback' => \&Koha::QueryParser::Driver::PQF::date_filter_target_callback, '1' => '30', '4' => '4' });
702 $self->add_bib1_filter_map( 'biblioserver', 'pubdate', { 'target_syntax_callback' => \&Koha::QueryParser::Driver::PQF::date_filter_target_callback, '1' => 'pubdate', '4' => '4' });
703 $self->add_bib1_filter_map( 'biblioserver', 'acqdate', { 'target_syntax_callback' => \&Koha::QueryParser::Driver::PQF::date_filter_target_callback, '1' => 'Date-of-acquisition', '4' => '4' });
704 $self->add_bib1_field_map('keyword' => 'isbn' => 'biblioserver' => { '1' => '7' } );
705 $self->add_search_field_alias( 'keyword' => 'isbn' => 'nb' );
706 $self->add_bib1_field_map('keyword' => 'issn' => 'biblioserver' => { '1' => '8' } );
707 $self->add_search_field_alias( 'keyword' => 'issn' => 'ns' );
708 $self->add_bib1_field_map('keyword' => 'identifier-standard' => 'biblioserver' => { '1' => '1007' } );
709 $self->add_search_field_alias( 'keyword' => 'identifier-standard' => 'ident' );
710 $self->add_bib1_field_map('keyword' => 'upc' => 'biblioserver' => { '1' => 'UPC' } );
711 $self->add_search_field_alias( 'keyword' => 'upc' => 'upc' );
712 $self->add_bib1_field_map('keyword' => 'ean' => 'biblioserver' => { '1' => 'EAN' } );
713 $self->add_search_field_alias( 'keyword' => 'ean' => 'ean' );
714 $self->add_bib1_field_map('keyword' => 'music' => 'biblioserver' => { '1' => 'Music-number' } );
715 $self->add_search_field_alias( 'keyword' => 'music' => 'music' );
716 $self->add_bib1_field_map('keyword' => 'stock-number' => 'biblioserver' => { '1' => '1028' } );
717 $self->add_search_field_alias( 'keyword' => 'stock-number' => 'stock-number' );
718 $self->add_bib1_field_map('keyword' => 'material-type' => 'biblioserver' => { '1' => '1031' } );
719 $self->add_search_field_alias( 'keyword' => 'material-type' => 'material-type' );
720 $self->add_bib1_field_map('keyword' => 'place-publication' => 'biblioserver' => { '1' => '59' } );
721 $self->add_search_field_alias( 'keyword' => 'place-publication' => 'pl' );
722 $self->add_bib1_field_map('keyword' => 'personal-name' => 'biblioserver' => { '1' => 'Personal-name' } );
723 $self->add_search_field_alias( 'keyword' => 'personal-name' => 'pn' );
724 $self->add_bib1_field_map('keyword' => 'publisher' => 'biblioserver' => { '1' => '1018' } );
725 $self->add_search_field_alias( 'keyword' => 'publisher' => 'pb' );
726 $self->add_bib1_field_map('keyword' => 'note' => 'biblioserver' => { '1' => '63' } );
727 $self->add_search_field_alias( 'keyword' => 'note' => 'nt' );
728 $self->add_bib1_field_map('keyword' => 'record-control-number' => 'biblioserver' => { '1' => '1045' } );
729 $self->add_search_field_alias( 'keyword' => 'record-control-number' => 'rcn' );
730 $self->add_bib1_field_map('subject' => '' => 'biblioserver' => { '1' => '21' } );
731 $self->add_search_field_alias( 'subject' => '' => 'su' );
732 $self->add_search_field_alias( 'subject' => '' => 'su-to' );
733 $self->add_search_field_alias( 'subject' => '' => 'su-geo' );
734 $self->add_search_field_alias( 'subject' => '' => 'su-ut' );
735 $self->add_bib1_field_map('subject' => 'name-personal' => 'biblioserver' => { '1' => '1009' } );
736 $self->add_search_field_alias( 'subject' => 'name-personal' => 'su-na' );
737 $self->add_bib1_field_map('title' => '' => 'biblioserver' => { '1' => '4' } );
738 $self->add_search_field_alias( 'title' => '' => 'ti' );
739 $self->add_bib1_field_map('title' => 'cover' => 'biblioserver' => { '1' => '36' } );
740 $self->add_search_field_alias( 'title' => 'cover' => 'title-cover' );
741 $self->add_bib1_field_map('keyword' => 'host-item' => 'biblioserver' => { '1' => '1033' } );
742 $self->add_bib1_field_map('keyword' => 'video-mt' => 'biblioserver' => { '1' => 'Video-mt' } );
743 $self->add_bib1_field_map('keyword' => 'graphics-type' => 'biblioserver' => { '1' => 'Graphic-type' } );
744 $self->add_bib1_field_map('keyword' => 'graphics-support' => 'biblioserver' => { '1' => 'Graphic-support' } );
745 $self->add_bib1_field_map('keyword' => 'type-of-serial' => 'biblioserver' => { '1' => 'Type-Of-Serial' } );
746 $self->add_bib1_field_map('keyword' => 'regularity-code' => 'biblioserver' => { '1' => 'Regularity-code' } );
747 $self->add_bib1_field_map('keyword' => 'material-type' => 'biblioserver' => { '1' => 'Material-type' } );
748 $self->add_bib1_field_map('keyword' => 'literature-code' => 'biblioserver' => { '1' => 'Literature-Code' } );
749 $self->add_bib1_field_map('keyword' => 'biography-code' => 'biblioserver' => { '1' => 'Biography-code' } );
750 $self->add_bib1_field_map('keyword' => 'illustration-code' => 'biblioserver' => { '1' => 'Illustration-code' } );
751 $self->add_bib1_field_map('title' => 'series' => 'biblioserver' => { '1' => '5' } );
752 $self->add_search_field_alias( 'title' => 'series' => 'title-series' );
753 $self->add_search_field_alias( 'title' => 'series' => 'se' );
754 $self->add_bib1_field_map('title' => 'uniform' => 'biblioserver' => { '1' => 'Title-uniform' } );
755 $self->add_search_field_alias( 'title' => 'uniform' => 'title-uniform' );
756 $self->add_bib1_field_map('subject' => 'authority-number' => 'biblioserver' => { '1' => 'Koha-Auth-Number' } );
757 $self->add_search_field_alias( 'subject' => 'authority-number' => 'an' );
758 $self->add_bib1_field_map('keyword' => 'control-number' => 'biblioserver' => { '1' => '9001' } );
759 $self->add_bib1_field_map('keyword' => 'biblionumber' => 'biblioserver' => { '1' => '9002', '5' => '100' } );
760 $self->add_bib1_field_map('keyword' => 'totalissues' => 'biblioserver' => { '1' => '9003' } );
761 $self->add_bib1_field_map('keyword' => 'cn-bib-source' => 'biblioserver' => { '1' => '9004' } );
762 $self->add_bib1_field_map('keyword' => 'cn-bib-sort' => 'biblioserver' => { '1' => '9005' } );
763 $self->add_bib1_field_map('keyword' => 'itemtype' => 'biblioserver' => { '1' => '9006' } );
764 $self->add_search_field_alias( 'keyword' => 'itemtype' => 'mc-itemtype' );
765 $self->add_bib1_field_map('keyword' => 'cn-class' => 'biblioserver' => { '1' => '9007' } );
766 $self->add_bib1_field_map('keyword' => 'cn-item' => 'biblioserver' => { '1' => '9008' } );
767 $self->add_bib1_field_map('keyword' => 'cn-prefix' => 'biblioserver' => { '1' => '9009' } );
768 $self->add_bib1_field_map('keyword' => 'cn-suffix' => 'biblioserver' => { '1' => '9010' } );
769 $self->add_bib1_field_map('keyword' => 'suppress' => 'biblioserver' => { '1' => '9011' } );
770 $self->add_bib1_field_map('keyword' => 'id-other' => 'biblioserver' => { '1' => '9012' } );
771 $self->add_bib1_field_map('keyword' => 'date-entered-on-file' => 'biblioserver' => { '1' => 'date-entered-on-file' } );
772 $self->add_bib1_field_map('keyword' => 'extent' => 'biblioserver' => { '1' => 'Extent' } );
773 $self->add_bib1_field_map('keyword' => 'llength' => 'biblioserver' => { '1' => 'llength' } );
774 $self->add_bib1_field_map('keyword' => 'summary' => 'biblioserver' => { '1' => 'Summary' } );
775 $self->add_bib1_field_map('keyword' => 'withdrawn' => 'biblioserver' => { '1' => '8001' } );
776 $self->add_bib1_field_map('keyword' => 'lost' => 'biblioserver' => { '1' => '8002' } );
777 $self->add_bib1_field_map('keyword' => 'classification-source' => 'biblioserver' => { '1' => '8003' } );
778 $self->add_bib1_field_map('keyword' => 'materials-specified' => 'biblioserver' => { '1' => '8004' } );
779 $self->add_bib1_field_map('keyword' => 'damaged' => 'biblioserver' => { '1' => '8005' } );
780 $self->add_bib1_field_map('keyword' => 'restricted' => 'biblioserver' => { '1' => '8006' } );
781 $self->add_bib1_field_map('keyword' => 'cn-sort' => 'biblioserver' => { '1' => '8007' } );
782 $self->add_bib1_field_map('keyword' => 'notforloan' => 'biblioserver' => { '1' => '8008', '4' => '109' } );
783 $self->add_bib1_field_map('keyword' => 'ccode' => 'biblioserver' => { '1' => '8009' } );
784 $self->add_search_field_alias( 'keyword' => 'ccode' => 'mc-ccode' );
785 $self->add_bib1_field_map('keyword' => 'itemnumber' => 'biblioserver' => { '1' => '8010' } );
786 $self->add_bib1_field_map('keyword' => 'homebranch' => 'biblioserver' => { '1' => 'homebranch' } );
787 $self->add_search_field_alias( 'keyword' => 'homebranch' => 'branch' );
788 $self->add_bib1_field_map('keyword' => 'holdingbranch' => 'biblioserver' => { '1' => '8012' } );
789 $self->add_bib1_field_map('keyword' => 'location' => 'biblioserver' => { '1' => '8013' } );
790 $self->add_search_field_alias( 'keyword' => 'location' => 'mc-loc' );
791 $self->add_bib1_field_map('keyword' => 'acqsource' => 'biblioserver' => { '1' => '8015' } );
792 $self->add_bib1_field_map('keyword' => 'coded-location-qualifier' => 'biblioserver' => { '1' => '8016' } );
793 $self->add_bib1_field_map('keyword' => 'price' => 'biblioserver' => { '1' => '8017' } );
794 $self->add_bib1_field_map('keyword' => 'stocknumber' => 'biblioserver' => { '1' => '1062' } );
795 $self->add_search_field_alias( 'keyword' => 'stocknumber' => 'inv' );
796 $self->add_bib1_field_map('keyword' => 'stack' => 'biblioserver' => { '1' => '8018' } );
797 $self->add_bib1_field_map('keyword' => 'issues' => 'biblioserver' => { '1' => '8019' } );
798 $self->add_bib1_field_map('keyword' => 'renewals' => 'biblioserver' => { '1' => '8020' } );
799 $self->add_bib1_field_map('keyword' => 'reserves' => 'biblioserver' => { '1' => '8021' } );
800 $self->add_bib1_field_map('keyword' => 'local-classification' => 'biblioserver' => { '1' => '8022' } );
801 $self->add_bib1_field_map('keyword' => 'barcode' => 'biblioserver' => { '1' => '8023' } );
802 $self->add_search_field_alias( 'keyword' => 'barcode' => 'bc' );
803 $self->add_bib1_field_map('keyword' => 'onloan' => 'biblioserver' => { '1' => '8024' } );
804 $self->add_bib1_field_map('keyword' => 'datelastseen' => 'biblioserver' => { '1' => '8025' } );
805 $self->add_bib1_field_map('keyword' => 'datelastborrowed' => 'biblioserver' => { '1' => '8026' } );
806 $self->add_bib1_field_map('keyword' => 'copynumber' => 'biblioserver' => { '1' => '8027' } );
807 $self->add_bib1_field_map('keyword' => 'uri' => 'biblioserver' => { '1' => '8028' } );
808 $self->add_bib1_field_map('keyword' => 'replacementprice' => 'biblioserver' => { '1' => '8029' } );
809 $self->add_bib1_field_map('keyword' => 'replacementpricedate' => 'biblioserver' => { '1' => '8030' } );
810 $self->add_bib1_field_map('keyword' => 'itype' => 'biblioserver' => { '1' => '8031' } );
811 $self->add_search_field_alias( 'keyword' => 'itype' => 'mc-itype' );
812 $self->add_bib1_field_map('keyword' => 'ff8-22' => 'biblioserver' => { '1' => '8822' } );
813 $self->add_bib1_field_map('keyword' => 'ff8-23' => 'biblioserver' => { '1' => '8823' } );
814 $self->add_bib1_field_map('keyword' => 'ff8-34' => 'biblioserver' => { '1' => '8834' } );
815 # Audience
816 $self->add_bib1_field_map('keyword' => 'audience' => 'biblioserver' => { '1' => '8822' } );
817 $self->add_search_field_alias( 'keyword' => 'audience' => 'aud' );
819 # Content and Literary form
820 $self->add_bib1_field_map('keyword' => 'fiction' => 'biblioserver' => { '1' => '8833' } );
821 $self->add_search_field_alias( 'keyword' => 'fiction' => 'fic' );
822 $self->add_bib1_field_map('keyword' => 'biography' => 'biblioserver' => { '1' => '8834' } );
823 $self->add_search_field_alias( 'keyword' => 'biography' => 'bio' );
825 # Format
826 $self->add_bib1_field_map('keyword' => 'format' => 'biblioserver' => { '1' => '8823' } );
827 # format used as a limit FIXME: needed?
828 $self->add_bib1_field_map('keyword' => 'l-format' => 'biblioserver' => { '1' => '8703' } );
830 $self->add_bib1_field_map('keyword' => 'illustration-code' => 'biblioserver' => { '1' => 'Illustration-code ' } );
832 # Lexile Number
833 $self->add_bib1_field_map('keyword' => 'lex' => 'biblioserver' => { '1' => '9903 r=r' } );
835 #Accelerated Reader Level
836 $self->add_bib1_field_map('keyword' => 'arl' => 'biblioserver' => { '1' => '9904 r=r' } );
838 #Accelerated Reader Point
839 $self->add_bib1_field_map('keyword' => 'arp' => 'biblioserver' => { '1' => '9013 r=r' } );
841 # Curriculum
842 $self->add_bib1_field_map('keyword' => 'curriculum' => 'biblioserver' => { '1' => '9658' } );
844 ## Statuses
845 $self->add_bib1_field_map('keyword' => 'popularity' => 'biblioserver' => { '1' => 'issues' } );
847 ## Type Limits
848 $self->add_bib1_field_map('keyword' => 'dt-bks' => 'biblioserver' => { '1' => '8700' } );
849 $self->add_bib1_field_map('keyword' => 'dt-vis' => 'biblioserver' => { '1' => '8700' } );
850 $self->add_bib1_field_map('keyword' => 'dt-sr' => 'biblioserver' => { '1' => '8700' } );
851 $self->add_bib1_field_map('keyword' => 'dt-cf' => 'biblioserver' => { '1' => '8700' } );
852 $self->add_bib1_field_map('keyword' => 'dt-map' => 'biblioserver' => { '1' => '8700' } );
854 $self->add_bib1_field_map('keyword' => 'name' => 'biblioserver' => { '1' => '1002' } );
855 $self->add_bib1_field_map('keyword' => 'item' => 'biblioserver' => { '1' => '9520' } );
856 $self->add_bib1_field_map('keyword' => 'host-item-number' => 'biblioserver' => { '1' => '8911' } );
857 $self->add_search_field_alias( 'keyword' => 'host-item-number' => 'hi' );
859 $self->add_bib1_field_map('keyword' => 'alwaysmatch' => 'biblioserver' => { '1' => '_ALLRECORDS', '2' => '103' } );
860 $self->add_bib1_field_map('subject' => 'complete' => 'biblioserver' => { '1' => '21', '3' => '1', '4' => '1', '5' => '100', '6' => '3' } );
862 $self->add_bib1_modifier_map('relevance' => 'biblioserver' => { '2' => '102' } );
863 $self->add_bib1_modifier_map('title-sort-za' => 'biblioserver' => { '7' => '2', '1' => '36', '' => '0', 'op' => '@or' } );
864 $self->add_bib1_modifier_map('title-sort-az' => 'biblioserver' => { '7' => '1', '1' => '36', '' => '0', 'op' => '@or' } );
865 $self->add_bib1_modifier_map('relevance_dsc' => 'biblioserver' => { '2' => '102' } );
866 $self->add_bib1_modifier_map('title_dsc' => 'biblioserver' => { '7' => '2', '1' => '4', '' => '0', 'op' => '@or' } );
867 $self->add_bib1_modifier_map('title_asc' => 'biblioserver' => { '7' => '1', '1' => '4', '' => '0', 'op' => '@or' } );
868 $self->add_bib1_modifier_map('author_asc' => 'biblioserver' => { '7' => '2', '1' => '1003', '' => '0', 'op' => '@or' } );
869 $self->add_bib1_modifier_map('author_dsc' => 'biblioserver' => { '7' => '1', '1' => '1003', '' => '0', 'op' => '@or' } );
870 $self->add_bib1_modifier_map('popularity_asc' => 'biblioserver' => { '7' => '2', '1' => '9003', '' => '0', 'op' => '@or' } );
871 $self->add_bib1_modifier_map('popularity_dsc' => 'biblioserver' => { '7' => '1', '1' => '9003', '' => '0', 'op' => '@or' } );
872 $self->add_bib1_modifier_map('call_number_asc' => 'biblioserver' => { '7' => '2', '1' => '8007', '' => '0', 'op' => '@or' } );
873 $self->add_bib1_modifier_map('call_number_dsc' => 'biblioserver' => { '7' => '1', '1' => '8007', '' => '0', 'op' => '@or' } );
874 $self->add_bib1_modifier_map('pubdate_asc' => 'biblioserver' => { '7' => '2', '1' => '31', '' => '0', 'op' => '@or' } );
875 $self->add_bib1_modifier_map('pubdate_dsc' => 'biblioserver' => { '7' => '1', '1' => '31', '' => '0', 'op' => '@or' } );
876 $self->add_bib1_modifier_map('acqdate_asc' => 'biblioserver' => { '7' => '2', '1' => '32', '' => '0', 'op' => '@or' } );
877 $self->add_bib1_modifier_map('acqdate_dsc' => 'biblioserver' => { '7' => '1', '1' => '32', '' => '0', 'op' => '@or' } );
879 $self->add_bib1_modifier_map('title_za' => 'biblioserver' => { '7' => '2', '1' => '4', '' => '0', 'op' => '@or' } );
880 $self->add_bib1_modifier_map('title_az' => 'biblioserver' => { '7' => '1', '1' => '4', '' => '0', 'op' => '@or' } );
881 $self->add_bib1_modifier_map('author_za' => 'biblioserver' => { '7' => '2', '1' => '1003', '' => '0', 'op' => '@or' } );
882 $self->add_bib1_modifier_map('author_az' => 'biblioserver' => { '7' => '1', '1' => '1003', '' => '0', 'op' => '@or' } );
883 $self->add_bib1_modifier_map('ascending' => 'biblioserver' => { '7' => '1' } );
884 $self->add_bib1_modifier_map('descending' => 'biblioserver' => { '7' => '2' } );
886 $self->add_bib1_field_map('title' => 'exacttitle' => 'biblioserver' => { '1' => '4', '4' => '1', '6' => '3' } );
887 $self->add_search_field_alias( 'title' => 'exacttitle' => 'ti,ext' );
888 $self->add_bib1_field_map('author' => 'exactauthor' => 'biblioserver' => { '1' => '1003', '4' => '1', '6' => '3' } );
889 $self->add_search_field_alias( 'author' => 'exactauthor' => 'au,ext' );
891 $self->add_bib1_field_map('subject' => 'headingmain' => 'authorityserver' => { '1' => 'Heading-Main' } );
892 $self->add_bib1_field_map('subject' => 'heading' => 'authorityserver' => { '1' => 'Heading' } );
893 $self->add_bib1_field_map('subject' => 'matchheading' => 'authorityserver' => { '1' => 'Match-heading' } );
894 $self->add_bib1_field_map('subject' => 'seefrom' => 'authorityserver' => { '1' => 'Match-heading-see-from' } );
895 $self->add_bib1_field_map('subject' => '' => 'authorityserver' => { '1' => 'Match-heading' } );
896 $self->add_bib1_field_map('keyword' => 'alwaysmatch' => 'authorityserver' => { '1' => '_ALLRECORDS', '2' => '103' } );
897 $self->add_bib1_field_map('keyword' => 'match' => 'authorityserver' => { '1' => 'Match' } );
898 $self->add_bib1_field_map('keyword' => 'thesaurus' => 'authorityserver' => { '1' => 'Subject-heading-thesaurus' } );
899 $self->add_bib1_field_map('keyword' => 'authtype' => 'authorityserver' => { '1' => 'authtype', '5' => '100' } );
900 $self->add_bib1_field_map('keyword' => '' => 'authorityserver' => { '1' => 'Any' } );
901 $self->add_search_field_alias( 'subject' => 'headingmain' => 'mainmainentry' );
902 $self->add_search_field_alias( 'subject' => 'heading' => 'mainentry' );
903 $self->add_search_field_alias( 'subject' => 'heading' => 'he' );
904 $self->add_search_field_alias( 'subject' => 'matchheading' => 'match-heading' );
905 $self->add_search_field_alias( 'keyword' => '' => 'any' );
906 $self->add_search_field_alias( 'keyword' => 'match' => 'match' );
907 $self->add_search_field_alias( 'subject' => 'seefrom' => 'see-from' );
908 $self->add_search_field_alias( 'keyword' => 'thesaurus' => 'thesaurus' );
909 $self->add_search_field_alias( 'keyword' => 'alwaysmatch' => 'all' );
910 $self->add_search_field_alias( 'keyword' => 'authtype' => 'authtype' );
911 $self->add_search_field_alias( 'keyword' => 'authtype' => 'at' );
913 $self->add_bib1_field_map('subject' => 'start' => 'authorityserver' => { '3' => '2', '4' => '1', '5' => '1' } );
914 $self->add_bib1_field_map('subject' => 'exact' => 'authorityserver' => { '4' => '1', '5' => '100', '6' => '3' } );
916 $self->add_bib1_modifier_map('HeadingAsc' => 'authorityserver' => { '7' => '1', '1' => 'Heading', '' => '0', 'op' => '@or' } );
917 $self->add_bib1_modifier_map('HeadingDsc' => 'authorityserver' => { '7' => '2', '1' => 'Heading', '' => '0', 'op' => '@or' } );
918 $self->add_bib1_modifier_map('AuthidAsc' => 'authorityserver' => { '7' => '1', '1' => 'Local-Number', '' => '0', 'op' => '@or' } );
919 $self->add_bib1_modifier_map('AuthidDsc' => 'authorityserver' => { '7' => '2', '1' => 'Local-Number', '' => '0', 'op' => '@or' } );
920 $self->add_bib1_modifier_map('Relevance' => 'authorityserver' => { '2' => '102' } );
922 return $self;