Bug 12478: Move mapping attributes to the join table
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Mon, 12 Oct 2015 15:46:16 +0000 (16:46 +0100)
committerTomas Cohen Arazi <tomascohen@theke.io>
Tue, 26 Apr 2016 13:01:09 +0000 (10:01 -0300)
To make things consistent, the attributes of the mappings (sort,
suggestible, facet) should be moved to the join tables
(search_marc_to_field).
Indeed the search_marc_map could represent a mapping for several search
fields with different attributes. Before this change it was not
possible.

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Jesse Weaver <jweaver@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>

Koha/ElasticSearch.pm
Koha/Objects.pm
Koha/SearchField.pm
installer/data/mysql/atomicupdate/elastic_search.perl [new file with mode: 0644]

index e91d5b8..d56c344 100644 (file)
@@ -374,29 +374,38 @@ sub _foreach_mapping {
     my ( $self, $sub ) = @_;
 
     # TODO use a caching framework here
-    my $database = Koha::Database->new();
-    my $schema   = $database->schema();
-    my $rs =
-      $schema->resultset('SearchMarcMap')
-      ->search( { index_name => $self->index } );
-    for my $row ( $rs->all ) {
-        my $marc_type = $row->marc_type;
-        my $marc_field = $row->marc_field;
-        my $facet = $row->facet;
-        my $suggestible = $row->suggestible;
-        my $search_field = $row->search_fields();
-        my $sort = $row->sort();
-        for my $sf ( $search_field->all ) {
-            $sub->(
-                $sf->name,
-                $sf->type,
-                $facet,
-                $suggestible,
-                $sort,
-                $marc_type,
-                $marc_field,
-            );
+    my $search_fields = Koha::Database->schema->resultset('SearchField')->search(
+        {
+            'search_marc_map.index_name' => $self->index,
+        },
+        {   join => { search_marc_to_fields => 'search_marc_map' },
+            '+select' => [
+                'search_marc_to_fields.facet',
+                'search_marc_to_fields.suggestible',
+                'search_marc_to_fields.sort',
+                'search_marc_map.marc_type',
+                'search_marc_map.marc_field',
+            ],
+            '+as'     => [
+                'facet',
+                'suggestible',
+                'sort',
+                'marc_type',
+                'marc_field',
+            ],
         }
+    );
+
+    while ( my $search_field = $search_fields->next ) {
+        $sub->(
+            $search_field->name,
+            $search_field->type,
+            $search_field->get_column('facet'),
+            $search_field->get_column('suggestible'),
+            $search_field->get_column('sort'),
+            $search_field->get_column('marc_type'),
+            $search_field->get_column('marc_field'),
+        );
     }
 }
 
index 8bf15f6..6c03ff5 100644 (file)
@@ -89,6 +89,24 @@ sub find {
     return $object;
 }
 
+=head3 Koha::Objects->find_or_create();
+
+my $object = Koha::Objects->find_or_create( $attrs );
+
+=cut
+
+sub find_or_create {
+    my ( $self, $params ) = @_;
+
+    my $result = $self->_resultset->find_or_create($params);
+
+    return unless $result;
+
+    my $object = $self->object_class->_new_from_dbic($result);
+
+    return $object;
+}
+
 =head3 Koha::Objects->search();
 
 my @objects = Koha::Objects->search($params);
index 72eb9c0..98c3252 100644 (file)
@@ -33,6 +33,11 @@ Koha::SearchField - Koha SearchField Object class
 
 =cut
 
+sub add_to_search_marc_maps {
+    my ( $self, $search_field, $params ) = @_;
+    return $self->_result()->add_to_search_marc_maps($search_field->_result, $params);
+}
+
 =head3 type
 
 =cut
diff --git a/installer/data/mysql/atomicupdate/elastic_search.perl b/installer/data/mysql/atomicupdate/elastic_search.perl
new file mode 100644 (file)
index 0000000..e8bc20e
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+use Modern::Perl;
+
+use C4::Context;
+use YAML::Syck;
+
+use Koha::SearchMarcMaps;
+use Koha::SearchFields;
+
+my $dbh = C4::Context->dbh;
+
+$dbh->do(q|DROP TABLE IF EXISTS search_marc_to_field|);
+$dbh->do(q|DROP TABLE IF EXISTS search_marc_map|);
+$dbh->do(q|DROP TABLE IF EXISTS search_field|);
+
+# This specifies the fields that will be stored in the search engine.
+$dbh->do(q|
+    CREATE TABLE `search_field` (
+      `id` int(11) NOT NULL AUTO_INCREMENT,
+      `name` varchar(255) NOT NULL COMMENT 'the name of the field as it will be stored in the search engine',
+      `label` varchar(255) NOT NULL COMMENT 'the human readable name of the field, for display',
+      `type` ENUM('string', 'date', 'number', 'boolean', 'sum') NOT NULL COMMENT 'what type of data this holds, relevant when storing it in the search engine',
+      PRIMARY KEY (`id`),
+      UNIQUE KEY (`name`)
+    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
+|);
+
+# This contains a MARC field specifier for a given index, marc type, and marc
+# field.
+$dbh->do(q|
+    CREATE TABLE `search_marc_map` (
+        id int(11) NOT NULL AUTO_INCREMENT,
+        index_name ENUM('biblios','authorities') NOT NULL COMMENT 'what storage index this map is for',
+        marc_type ENUM('marc21', 'unimarc', 'normarc') NOT NULL COMMENT 'what MARC type this map is for',
+        marc_field VARCHAR(255) NOT NULL COMMENT 'the MARC specifier for this field',
+        PRIMARY KEY(`id`),
+        unique key( index_name, marc_field, marc_type),
+        INDEX (`index_name`)
+    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
+|);
+
+# This joins the two search tables together. We can have any combination:
+# one marc field could have many search fields (maybe you want one value
+# to go to 'author' and 'corporate-author) and many marc fields could go
+# to one search field (e.g. all the various author fields going into
+# 'author'.)
+#
+# a note about the sort field:
+# * if all the entries for a mapping are 'null', nothing special is done with that mapping.
+# * if any of the entries are not null, then a __sort field is created in ES for this mapping. In this case:
+#   * any mapping with sort == false WILL NOT get copied into a __sort field
+#   * any mapping with sort == true or is null WILL get copied into a __sort field
+#   * any sorts on the field name will be applied to $fieldname.'__sort' instead.
+# this means that we can have search for author that includes 1xx, 245$c, and 7xx, but the sort only applies to 1xx.
+$dbh->do(q|
+    CREATE TABLE `search_marc_to_field` (
+        search_marc_map_id int(11) NOT NULL,
+        search_field_id int(11) NOT NULL,
+        facet boolean DEFAULT FALSE COMMENT 'true if a facet field should be generated for this',
+        suggestible boolean DEFAULT FALSE COMMENT 'true if this field can be used to generate suggestions for browse',
+        sort boolean DEFAULT NULL COMMENT 'true/false creates special sort handling, null doesn''t',
+        PRIMARY KEY(search_marc_map_id, search_field_id),
+        FOREIGN KEY(search_marc_map_id) REFERENCES search_marc_map(id) ON DELETE CASCADE ON UPDATE CASCADE,
+        FOREIGN KEY(search_field_id) REFERENCES search_field(id) ON DELETE CASCADE ON UPDATE CASCADE
+    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
+|);
+
+my $mappings_yaml = C4::Context->config('intranetdir') . '/admin/searchengine/elasticsearch/mappings.yaml';
+my $indexes = LoadFile( $mappings_yaml );
+
+while ( my ( $index_name, $fields ) = each %$indexes ) {
+    while ( my ( $field_name, $data ) = each %$fields ) {
+        my $field_type = $data->{type};
+        my $field_label = $data->{label};
+        my $mappings = $data->{mappings};
+        my $search_field = Koha::SearchFields->find_or_create({ name => $field_name, label => $field_label, type => $field_type }, { key => 'name' });
+        for my $mapping ( @$mappings ) {
+            my $marc_field = Koha::SearchMarcMaps->find_or_create({ index_name => $index_name, marc_type => $mapping->{marc_type}, marc_field => $mapping->{marc_field} });
+            $search_field->add_to_search_marc_maps($marc_field, { facet => $mapping->{facet}, suggestible => $mapping->{suggestible}, sort => $mapping->{sort} } );
+        }
+    }
+}