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