Bug 12478 - pile of elasticsearch code
[koha.git] / Koha / ElasticSearch / Indexer.pm
1 package Koha::ElasticSearch::Indexer;
2
3 # Copyright 2013 Catalyst IT
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 3 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 use Carp;
21 use Modern::Perl;
22 use base qw(Koha::ElasticSearch);
23 use Data::Dumper;
24
25 # For now just marc, but we can do anything here really
26 use Catmandu::Importer::MARC;
27 use Catmandu::Store::ElasticSearch;
28
29 Koha::ElasticSearch::Indexer->mk_accessors(qw( store ));
30
31 =head1 NAME
32
33 Koha::ElasticSearch::Indexer - handles adding new records to the index
34
35 =head1 SYNOPSIS
36
37     my $indexer = Koha::ElasticSearch::Indexer->new({ index => 'biblios' });
38     $indexer->delete_index();
39     $indexer->update_index(\@biblionumbers, \@records);
40
41 =head1 FUNCTIONS
42
43 =cut
44
45 =head2 $indexer->update_index($biblionums, $records);
46
47 C<$biblionums> is an arrayref containing the biblionumbers for the records.
48
49 C<$records> is an arrayref containing the L<MARC::Record>s themselves.
50
51 The values in the arrays must match up, and the 999$c value in the MARC record
52 will be rewritten using the values in C<$biblionums> to ensure they are correct.
53 If C<$biblionums> is C<undef>, this won't happen, but you should be sure that
54 999$c is correct on your own then.
55
56 Note that this will modify the original record if C<$biblionums> is supplied.
57 If that's a problem, clone them first.
58
59 =cut
60
61 sub update_index {
62     my ($self, $biblionums, $records) = @_;
63
64     if ($biblionums) {
65         $self->_sanitise_records($biblionums, $records);
66     }
67
68     my $from    = $self->_convert_marc_to_json($records);
69     if ( !$self->store ) {
70         my $params  = $self->get_elasticsearch_params();
71         $self->store(
72             Catmandu::Store::ElasticSearch->new(
73                 %$params,
74                 index_settings => $self->get_elasticsearch_settings(),
75                 index_mappings => $self->get_elasticsearch_mappings(),
76                 #trace_calls => 1,
77             )
78         );
79     }
80     $self->store->bag->add_many($from);
81     $self->store->bag->commit;
82     return 1;
83 }
84
85 =head2 $indexer->delete_index();
86
87 Deletes the index from the elasticsearch server. Calling C<update_index>
88 after this will recreate it again.
89
90 =cut
91
92 sub delete_index {
93     my ($self) = @_;
94
95     if (!$self->store) {
96         # If this index doesn't exist, this will create it. Then it'll be
97         # deleted. That's not the end of the world however.
98         my $params  = $self->get_elasticsearch_params();
99         $self->store(
100             Catmandu::Store::ElasticSearch->new(
101                 %$params,
102                 index_settings => $self->get_elasticsearch_settings(),
103                 index_mappings => $self->get_elasticsearch_mappings(),
104                 #trace_calls => 1,
105             )
106         );
107     }
108     $self->store->drop();
109     $self->store(undef);
110 }
111
112 sub _sanitise_records {
113     my ($self, $biblionums, $records) = @_;
114
115     confess "Unequal number of values in \$biblionums and \$records." if (@$biblionums != @$records);
116
117     my $c = @$biblionums;
118     for (my $i=0; $i<$c; $i++) {
119         my $bibnum = $biblionums->[$i];
120         my $rec = $records->[$i];
121         # I've seen things you people wouldn't believe. Attack ships on fire
122         # off the shoulder of Orion. I watched C-beams glitter in the dark near
123         # the Tannhauser gate. MARC records where 999$c doesn't match the
124         # biblionumber column. All those moments will be lost in time... like
125         # tears in rain...
126         $rec->delete_fields($rec->field('999'));
127         $rec->append_fields(MARC::Field->new('999','','','c' => $bibnum, 'd' => $bibnum));
128     }
129 }
130
131 sub _convert_marc_to_json {
132     my $self    = shift;
133     my $records = shift;
134     my $importer =
135       Catmandu::Importer::MARC->new( records => $records, id => '999c' );
136     my $fixer = Catmandu::Fix->new( fixes => $self->get_fixer_rules() );
137     $importer = $fixer->fix($importer);
138     return $importer;
139 }
140
141 1;
142
143 __END__
144
145 =head1 AUTHOR
146
147 =over 4
148
149 =item Chris Cormack C<< <chrisc@catalyst.net.nz> >>
150
151 =item Robin Sheat C<< <robin@catalyst.net.nz> >>
152
153 =back
154
155 =cut