View | Details | Raw Unified | Return to bug 17255
Collapse All | Expand All

(-)a/Koha/SearchEngine/Elasticsearch.pm (-29 / +62 lines)
Lines 115-120 sub get_elasticsearch_params { Link Here
115
      if ( !$es->{index_name} );
115
      if ( !$es->{index_name} );
116
    # Append the name of this particular index to our namespace
116
    # Append the name of this particular index to our namespace
117
    $es->{index_name} .= '_' . $self->index;
117
    $es->{index_name} .= '_' . $self->index;
118
119
    $es->{key_prefix} = 'es_';
118
    return $es;
120
    return $es;
119
}
121
}
120
122
Lines 145-151 sub get_elasticsearch_settings { Link Here
145
                    analyser_standard => {
147
                    analyser_standard => {
146
                        tokenizer => 'standard',
148
                        tokenizer => 'standard',
147
                        filter    => ['lowercase'],
149
                        filter    => ['lowercase'],
148
                    }
150
                    },
151
                    default => {
152
                        tokenizer => 'keyword',
153
                        filter    => ['lowercase'],
154
                    },
149
                },
155
                },
150
            }
156
            }
151
        }
157
        }
Lines 174-184 sub get_elasticsearch_mappings { Link Here
174
                    include_in_all => JSON::false,
180
                    include_in_all => JSON::false,
175
                    type           => "string",
181
                    type           => "string",
176
                },
182
                },
177
                '_all.phrase' => {
178
                    search_analyzer => "analyser_phrase",
179
                    index_analyzer  => "analyser_phrase",
180
                    type            => "string",
181
                },
182
            }
183
            }
183
        }
184
        }
184
    };
185
    };
Lines 188-193 sub get_elasticsearch_mappings { Link Here
188
        sub {
189
        sub {
189
            my ( $name, $type, $facet, $suggestible, $sort, $marc_type ) = @_;
190
            my ( $name, $type, $facet, $suggestible, $sort, $marc_type ) = @_;
190
            return if $marc_type ne $marcflavour;
191
            return if $marc_type ne $marcflavour;
192
191
            # TODO if this gets any sort of complexity to it, it should
193
            # TODO if this gets any sort of complexity to it, it should
192
            # be broken out into its own function.
194
            # be broken out into its own function.
193
195
Lines 197-221 sub get_elasticsearch_mappings { Link Here
197
              $type eq 'boolean'
199
              $type eq 'boolean'
198
              ? 'boolean'
200
              ? 'boolean'
199
              : 'string';
201
              : 'string';
200
            $mappings->{data}{properties}{$name} = {
202
201
                search_analyzer => "analyser_standard",
203
            if ($es_type eq 'boolean') {
202
                index_analyzer  => "analyser_standard",
204
                $mappings->{data}{properties}{$name} = _elasticsearch_mapping_for_boolean( $name, $es_type, $facet, $suggestible, $sort, $marc_type );
203
                type            => $es_type,
205
                return; #Boolean cannot have facets nor sorting nor suggestions
204
                fields          => {
206
            } else {
205
                    phrase => {
207
                $mappings->{data}{properties}{$name} = _elasticsearch_mapping_for_default( $name, $es_type, $facet, $suggestible, $sort, $marc_type );
206
                        search_analyzer => "analyser_phrase",
208
            }
207
                        index_analyzer  => "analyser_phrase",
209
208
                        type            => "string",
209
                        copy_to         => "_all.phrase",
210
                    },
211
                    raw => {
212
                        "type" => "string",
213
                        "index" => "not_analyzed",
214
                    }
215
                },
216
            };
217
            $mappings->{data}{properties}{$name}{null_value} = 0
218
              if $type eq 'boolean';
219
            if ($facet) {
210
            if ($facet) {
220
                $mappings->{data}{properties}{ $name . '__facet' } = {
211
                $mappings->{data}{properties}{ $name . '__facet' } = {
221
                    type  => "string",
212
                    type  => "string",
Lines 225-231 sub get_elasticsearch_mappings { Link Here
225
            if ($suggestible) {
216
            if ($suggestible) {
226
                $mappings->{data}{properties}{ $name . '__suggestion' } = {
217
                $mappings->{data}{properties}{ $name . '__suggestion' } = {
227
                    type => 'completion',
218
                    type => 'completion',
228
                    index_analyzer => 'simple',
219
                    analyzer => 'simple',
229
                    search_analyzer => 'simple',
220
                    search_analyzer => 'simple',
230
                };
221
                };
231
            }
222
            }
Lines 234-246 sub get_elasticsearch_mappings { Link Here
234
            if (defined $sort) {
225
            if (defined $sort) {
235
                $mappings->{data}{properties}{ $name . '__sort' } = {
226
                $mappings->{data}{properties}{ $name . '__sort' } = {
236
                    search_analyzer => "analyser_phrase",
227
                    search_analyzer => "analyser_phrase",
237
                    index_analyzer  => "analyser_phrase",
228
                    analyzer  => "analyser_phrase",
238
                    type            => "string",
229
                    type            => "string",
239
                    include_in_all  => JSON::false,
230
                    include_in_all  => JSON::false,
240
                    fields          => {
231
                    fields          => {
241
                        phrase => {
232
                        phrase => {
242
                            search_analyzer => "analyser_phrase",
233
                            search_analyzer => "analyser_phrase",
243
                            index_analyzer  => "analyser_phrase",
234
                            analyzer  => "analyser_phrase",
244
                            type            => "string",
235
                            type            => "string",
245
                        },
236
                        },
246
                    },
237
                    },
Lines 253-258 sub get_elasticsearch_mappings { Link Here
253
    return $mappings;
244
    return $mappings;
254
}
245
}
255
246
247
=head2 _elasticsearch_mapping_for_*
248
249
Get the ES mappings for the given data type or a special mapping case
250
251
Receives the same parameters from the $self->_foreach_mapping() dispatcher
252
253
=cut
254
255
sub _elasticsearch_mapping_for_boolean {
256
    my ( $name, $type, $facet, $suggestible, $sort, $marc_type ) = @_;
257
258
    return {
259
        type            => $type,
260
        null_value      => 0,
261
    };
262
}
263
264
sub _elasticsearch_mapping_for_default {
265
    my ( $name, $type, $facet, $suggestible, $sort, $marc_type ) = @_;
266
267
    return {
268
        search_analyzer => "analyser_standard",
269
        analyzer        => "analyser_standard",
270
        type            => $type,
271
        fields          => {
272
            phrase => {
273
                search_analyzer => "analyser_phrase",
274
                analyzer        => "analyser_phrase",
275
                type            => "string",
276
            },
277
            raw => {
278
                type    => "string",
279
                index   => "not_analyzed",
280
            }
281
        },
282
    };
283
}
284
256
sub reset_elasticsearch_mappings {
285
sub reset_elasticsearch_mappings {
257
    my $mappings_yaml = C4::Context->config('intranetdir') . '/admin/searchengine/elasticsearch/mappings.yaml';
286
    my $mappings_yaml = C4::Context->config('intranetdir') . '/admin/searchengine/elasticsearch/mappings.yaml';
258
    my $indexes = LoadFile( $mappings_yaml );
287
    my $indexes = LoadFile( $mappings_yaml );
Lines 294-299 sub get_fixer_rules { Link Here
294
323
295
    my $marcflavour = lc C4::Context->preference('marcflavour');
324
    my $marcflavour = lc C4::Context->preference('marcflavour');
296
    my @rules;
325
    my @rules;
326
297
    $self->_foreach_mapping(
327
    $self->_foreach_mapping(
298
        sub {
328
        sub {
299
            my ( $name, $type, $facet, $suggestible, $sort, $marc_type, $marc_field ) = @_;
329
            my ( $name, $type, $facet, $suggestible, $sort, $marc_type, $marc_field ) = @_;
Lines 311-317 sub get_fixer_rules { Link Here
311
            }
341
            }
312
            if ($suggestible) {
342
            if ($suggestible) {
313
                push @rules,
343
                push @rules,
314
"marc_map('$marc_field','${name}__suggestion.input.\$append', $options)";
344
                    #"marc_map('$marc_field','${name}__suggestion.input.\$append', $options)"; #must not have nested data structures in .input
345
                    "marc_map('$marc_field','${name}__suggestion.input.\$append')";
315
            }
346
            }
316
            if ( $type eq 'boolean' ) {
347
            if ( $type eq 'boolean' ) {
317
348
Lines 334-339 sub get_fixer_rules { Link Here
334
            }
365
            }
335
        }
366
        }
336
    );
367
    );
368
369
    push @rules, "move_field(_id,es_id)"; #Also you must set the Catmandu::Store::ElasticSearch->new(key_prefix: 'es_');
337
    return \@rules;
370
    return \@rules;
338
}
371
}
339
372
(-)a/Koha/SearchEngine/Elasticsearch/Indexer.pm (-1 / +2 lines)
Lines 24-30 use Data::Dumper; Link Here
24
24
25
# For now just marc, but we can do anything here really
25
# For now just marc, but we can do anything here really
26
use Catmandu::Importer::MARC;
26
use Catmandu::Importer::MARC;
27
use Catmandu::Store::Elasticsearch;
27
use Catmandu::Store::ElasticSearch;
28
28
29
Koha::SearchEngine::Elasticsearch::Indexer->mk_accessors(qw( store ));
29
Koha::SearchEngine::Elasticsearch::Indexer->mk_accessors(qw( store ));
30
30
Lines 77-82 sub update_index { Link Here
77
            )
77
            )
78
        );
78
        );
79
    }
79
    }
80
    my $array_ref = $from->to_array;
80
    $self->store->bag->add_many($from);
81
    $self->store->bag->add_many($from);
81
    $self->store->bag->commit;
82
    $self->store->bag->commit;
82
    return 1;
83
    return 1;
(-)a/Koha/SearchEngine/Elasticsearch/QueryBuilder.pm (-2 / +2 lines)
Lines 111-117 sub build_query { Link Here
111
111
112
    # See _convert_facets in Search.pm for how these get turned into
112
    # See _convert_facets in Search.pm for how these get turned into
113
    # things that Koha can use.
113
    # things that Koha can use.
114
    $res->{facets} = {
114
    $res->{aggregations} = {
115
        author   => { terms => { field => "author__facet" } },
115
        author   => { terms => { field => "author__facet" } },
116
        subject  => { terms => { field => "subject__facet" } },
116
        subject  => { terms => { field => "subject__facet" } },
117
        itype    => { terms => { field => "itype__facet" } },
117
        itype    => { terms => { field => "itype__facet" } },
Lines 120-126 sub build_query { Link Here
120
        se       => { terms => { field => "se__facet" } },
120
        se       => { terms => { field => "se__facet" } },
121
    };
121
    };
122
    if ( my $ef = $options{expanded_facet} ) {
122
    if ( my $ef = $options{expanded_facet} ) {
123
        $res->{facets}{$ef}{terms}{size} = C4::Context->preference('FacetMaxCount');
123
        $res->{aggregations}{$ef}{terms}{size} = C4::Context->preference('FacetMaxCount');
124
    };
124
    };
125
    return $res;
125
    return $res;
126
}
126
}
(-)a/Koha/SearchEngine/Elasticsearch/Search.pm (-7 / +6 lines)
Lines 167-173 sub search_compat { Link Here
167
    my %result;
167
    my %result;
168
    $result{biblioserver}{hits} = $results->total;
168
    $result{biblioserver}{hits} = $results->total;
169
    $result{biblioserver}{RECORDS} = \@records;
169
    $result{biblioserver}{RECORDS} = \@records;
170
    return (undef, \%result, $self->_convert_facets($results->{facets}, $expanded_facet));
170
    return (undef, \%result, $self->_convert_facets($results->{aggregations}, $expanded_facet));
171
}
171
}
172
172
173
=head2 search_auth_compat
173
=head2 search_auth_compat
Lines 430-444 sub _convert_facets { Link Here
430
            type_id    => $type . '_id',
430
            type_id    => $type . '_id',
431
            expand     => $type,
431
            expand     => $type,
432
            expandable => ( $type ne $exp_facet )
432
            expandable => ( $type ne $exp_facet )
433
              && ( @{ $data->{terms} } > $limit ),
433
              && ( @{ $data->{buckets} } > $limit ),
434
            "type_label_$type_to_label{$type}{label}" => 1,
434
            "type_label_$type_to_label{$type}{label}" => 1,
435
            type_link_value                    => $type,
435
            type_link_value                    => $type,
436
            order      => $type_to_label{$type}{order},
436
            order      => $type_to_label{$type}{order},
437
        };
437
        };
438
        $limit = @{ $data->{terms} } if ( $limit > @{ $data->{terms} } );
438
        $limit = @{ $data->{buckets} } if ( $limit > @{ $data->{buckets} } );
439
        foreach my $term ( @{ $data->{terms} }[ 0 .. $limit - 1 ] ) {
439
        foreach my $term ( @{ $data->{buckets} }[ 0 .. $limit - 1 ] ) {
440
            my $t = $term->{term};
440
            my $t = $term->{key};
441
            my $c = $term->{count};
441
            my $c = $term->{doc_count};
442
            my $label;
442
            my $label;
443
            if ( exists( $special{$type} ) ) {
443
            if ( exists( $special{$type} ) ) {
444
                $label = $special{$type}->{$t} // $t;
444
                $label = $special{$type}->{$t} // $t;
445
- 

Return to bug 17255