Lines 44-88
Koha::SearchEngine::Elasticsearch::Indexer - handles adding new records to the i
Link Here
|
44 |
$indexer->drop_index(); |
44 |
$indexer->drop_index(); |
45 |
$indexer->update_index(\@biblionumbers, \@records); |
45 |
$indexer->update_index(\@biblionumbers, \@records); |
46 |
|
46 |
|
47 |
=head1 FUNCTIONS |
|
|
48 |
|
47 |
|
49 |
=head2 $indexer->update_index($biblionums, $records); |
48 |
=head1 CONSTANTS |
50 |
|
49 |
|
51 |
C<$biblionums> is an arrayref containing the biblionumbers for the records. |
50 |
=over 4 |
52 |
|
51 |
|
53 |
C<$records> is an arrayref containing the L<MARC::Record>s themselves. |
52 |
=item C<Koha::SearchEngine::Elasticsearch::Indexer::INDEX_STATUS_OK> |
54 |
|
53 |
|
55 |
The values in the arrays must match up, and the 999$c value in the MARC record |
54 |
Represents an index state where index is created and in a working state. |
56 |
will be rewritten using the values in C<$biblionums> to ensure they are correct. |
|
|
57 |
If C<$biblionums> is C<undef>, this won't happen, but you should be sure that |
58 |
999$c is correct on your own then. |
59 |
|
55 |
|
60 |
Note that this will modify the original record if C<$biblionums> is supplied. |
56 |
=item C<Koha::SearchEngine::Elasticsearch::Indexer::INDEX_STATUS_REINDEX_REQUIRED> |
61 |
If that's a problem, clone them first. |
57 |
|
|
|
58 |
Not currently used, but could be useful later, for example if can detect when new field or mapping added. |
59 |
|
60 |
=item C<Koha::SearchEngine::Elasticsearch::Indexer::INDEX_STATUS_RECREATE_REQUIRED> |
61 |
|
62 |
Representings an index state where index needs to be recreated and is not in a working state. |
63 |
|
64 |
=back |
62 |
|
65 |
|
63 |
=cut |
66 |
=cut |
64 |
|
67 |
|
65 |
use constant { |
68 |
use constant { |
66 |
INDEX_STATUS_OK => 0, |
69 |
INDEX_STATUS_OK => 0, |
67 |
INDEX_STATUS_REINDEX_REQUIRED => 1, # Not currently used, but could be useful later, for example if can detect when new field or mapping added |
70 |
INDEX_STATUS_REINDEX_REQUIRED => 1, |
68 |
INDEX_STATUS_RECREATE_REQUIRED => 2, |
71 |
INDEX_STATUS_RECREATE_REQUIRED => 2, |
69 |
}; |
72 |
}; |
70 |
|
73 |
|
|
|
74 |
=head1 FUNCTIONS |
75 |
|
76 |
=head2 update_index($biblionums, $records) |
77 |
|
78 |
try { |
79 |
$self->update_index($biblionums, $records); |
80 |
} catch { |
81 |
die("Something whent wrong trying to update index:" . $_[0]); |
82 |
} |
83 |
|
84 |
Converts C<MARC::Records> C<$records> to Elasticsearch documents and perform |
85 |
an update request for these records on the Elasticsearch index. |
86 |
|
87 |
The values in the arrays must match up, and the 999$c value in the MARC record |
88 |
will be rewritten using the values in C<$biblionums> to ensure they are correct. |
89 |
If C<$biblionums> is C<undef>, this won't happen, so in that case you should make |
90 |
sure that 999$c is correct. |
91 |
|
92 |
Note that this will modify the original record if C<$biblionums> is supplied. |
93 |
If that's a problem, clone them first. |
94 |
|
95 |
=over 4 |
96 |
|
97 |
=item C<$biblionums> |
98 |
|
99 |
Arrayref of biblio numbers for the C<$records>, the order must be the same |
100 |
as C<$records>. |
101 |
|
102 |
=item C<$records> |
103 |
|
104 |
Arrayref of C<MARC::Record>s. |
105 |
|
106 |
=back |
107 |
|
108 |
=cut |
109 |
|
71 |
sub update_index { |
110 |
sub update_index { |
72 |
my ($self, $biblionums, $records) = @_; |
111 |
my ($self, $biblionums, $records) = @_; |
73 |
|
112 |
|
74 |
# TODO should have a separate path for dealing with a large number |
|
|
75 |
# of records at once where we use the bulk update functions in ES. |
76 |
if ($biblionums) { |
113 |
if ($biblionums) { |
77 |
$self->_sanitise_records($biblionums, $records); |
114 |
$self->_sanitise_records($biblionums, $records); |
78 |
} |
115 |
} |
79 |
|
116 |
|
80 |
$self->bulk_index($records); |
|
|
81 |
return 1; |
82 |
} |
83 |
|
84 |
sub bulk_index { |
85 |
my ($self, $records) = @_; |
86 |
my $conf = $self->get_elasticsearch_params(); |
117 |
my $conf = $self->get_elasticsearch_params(); |
87 |
my $elasticsearch = $self->get_elasticsearch(); |
118 |
my $elasticsearch = $self->get_elasticsearch(); |
88 |
my $documents = $self->marc_records_to_documents($records); |
119 |
my $documents = $self->marc_records_to_documents($records); |
Lines 108-134
sub bulk_index {
Link Here
|
108 |
return 1; |
139 |
return 1; |
109 |
} |
140 |
} |
110 |
|
141 |
|
111 |
sub index_status_ok { |
142 |
=head2 set_index_status_ok |
112 |
my ($self, $set) = @_; |
143 |
|
113 |
return defined $set ? |
144 |
Convenience method for setting index status to C<INDEX_STATUS_OK>. |
114 |
$self->index_status(INDEX_STATUS_OK) : |
145 |
|
115 |
$self->index_status == INDEX_STATUS_OK; |
146 |
=cut |
|
|
147 |
|
148 |
sub set_index_status_ok { |
149 |
my ($self) = @_; |
150 |
$self->index_status(INDEX_STATUS_OK); |
116 |
} |
151 |
} |
117 |
|
152 |
|
118 |
sub index_status_reindex_required { |
153 |
=head2 is_index_status_ok |
119 |
my ($self, $set) = @_; |
154 |
|
120 |
return defined $set ? |
155 |
Convenience method for checking if index status is C<INDEX_STATUS_OK>. |
121 |
$self->index_status(INDEX_STATUS_REINDEX_REQUIRED) : |
156 |
|
122 |
$self->index_status == INDEX_STATUS_REINDEX_REQUIRED; |
157 |
=cut |
|
|
158 |
|
159 |
sub is_index_status_ok { |
160 |
my ($self) = @_; |
161 |
return $self->index_status == INDEX_STATUS_OK; |
123 |
} |
162 |
} |
124 |
|
163 |
|
125 |
sub index_status_recreate_required { |
164 |
=head2 set_index_status_reindex_required |
126 |
my ($self, $set) = @_; |
165 |
|
127 |
return defined $set ? |
166 |
Convenience method for setting index status to C<INDEX_REINDEX_REQUIRED>. |
128 |
$self->index_status(INDEX_STATUS_RECREATE_REQUIRED) : |
167 |
|
129 |
$self->index_status == INDEX_STATUS_RECREATE_REQUIRED; |
168 |
=cut |
|
|
169 |
|
170 |
sub set_index_status_reindex_required { |
171 |
my ($self) = @_; |
172 |
$self->index_status(INDEX_STATUS_REINDEX_REQUIRED); |
130 |
} |
173 |
} |
131 |
|
174 |
|
|
|
175 |
=head2 is_index_status_reindex_required |
176 |
|
177 |
Convenience method for checking if index status is C<INDEX_STATUS_REINDEX_REQUIRED>. |
178 |
|
179 |
=cut |
180 |
|
181 |
sub is_index_status_reindex_required { |
182 |
my ($self) = @_; |
183 |
return $self->index_status == INDEX_STATUS_REINDEX_REQUIRED; |
184 |
} |
185 |
|
186 |
=head2 set_index_status_recreate_required |
187 |
|
188 |
Convenience method for setting index status to C<INDEX_STATUS_RECREATE_REQUIRED>. |
189 |
|
190 |
=cut |
191 |
|
192 |
sub set_index_status_recreate_required { |
193 |
my ($self) = @_; |
194 |
$self->index_status(INDEX_STATUS_RECREATE_REQUIRED); |
195 |
} |
196 |
|
197 |
=head2 is_index_status_recreate_required |
198 |
|
199 |
Convenience method for checking if index status is C<INDEX_STATUS_RECREATE_REQUIRED>. |
200 |
|
201 |
=cut |
202 |
|
203 |
sub is_index_status_recreate_required { |
204 |
my ($self) = @_; |
205 |
return $self->index_status == INDEX_STATUS_RECREATE_REQUIRED; |
206 |
} |
207 |
|
208 |
=head2 index_status($status) |
209 |
|
210 |
Will either set the current index status to C<$status> and return C<$status>, |
211 |
or return the current index status if called with no arguments. |
212 |
|
213 |
=over 4 |
214 |
|
215 |
=item C<$status> |
216 |
|
217 |
Optional argument. If passed will set current index status to C<$status> if C<$status> is |
218 |
a valid status. See L</CONSTANTS>. |
219 |
|
220 |
=back |
221 |
|
222 |
=cut |
223 |
|
132 |
sub index_status { |
224 |
sub index_status { |
133 |
my ($self, $status) = @_; |
225 |
my ($self, $status) = @_; |
134 |
my $key = 'ElasticsearchIndexStatus_' . $self->index; |
226 |
my $key = 'ElasticsearchIndexStatus_' . $self->index; |
Lines 150-155
sub index_status {
Link Here
|
150 |
} |
242 |
} |
151 |
} |
243 |
} |
152 |
|
244 |
|
|
|
245 |
=head2 update_mappings |
246 |
|
247 |
Generate Elasticsearch mappings from mappings stored in database and |
248 |
perform a request to update Elasticsearch index mappings. Will throw an |
249 |
error and set index status to C<INDEX_STATUS_RECREATE_REQUIRED> if update |
250 |
failes. |
251 |
|
252 |
=cut |
253 |
|
153 |
sub update_mappings { |
254 |
sub update_mappings { |
154 |
my ($self) = @_; |
255 |
my ($self) = @_; |
155 |
my $conf = $self->get_elasticsearch_params(); |
256 |
my $conf = $self->get_elasticsearch_params(); |
Lines 166-200
sub update_mappings {
Link Here
|
166 |
} |
267 |
} |
167 |
); |
268 |
); |
168 |
} catch { |
269 |
} catch { |
169 |
$self->index_status_recreate_required(1); |
270 |
$self->set_index_status_recreate_required(); |
170 |
my $reason = $_[0]->{vars}->{body}->{error}->{reason}; |
271 |
my $reason = $_[0]->{vars}->{body}->{error}->{reason}; |
171 |
Koha::Exceptions::Exception->throw( |
272 |
Koha::Exceptions::Exception->throw( |
172 |
error => "Unable to update mappings for index \"$conf->{index_name}\". Reason was: \"$reason\". Index needs to be recreated and reindexed", |
273 |
error => "Unable to update mappings for index \"$conf->{index_name}\". Reason was: \"$reason\". Index needs to be recreated and reindexed", |
173 |
); |
274 |
); |
174 |
}; |
275 |
}; |
175 |
} |
276 |
} |
176 |
$self->index_status_ok(1); |
277 |
$self->set_index_status_ok(); |
177 |
} |
278 |
} |
178 |
|
279 |
|
179 |
=head2 $indexer->update_index_background($biblionums, $records) |
280 |
=head2 update_index_background($biblionums, $records) |
180 |
|
281 |
|
181 |
This has exactly the same API as C<update_index_background> however it'll |
282 |
This has exactly the same API as C<update_index> however it'll |
182 |
return immediately. It'll start a background process that does the adding. |
283 |
return immediately. It'll start a background process that does the adding. |
183 |
|
284 |
|
184 |
If it fails to add to Elasticsearch then it'll add to a queue that will cause |
285 |
If it fails to add to Elasticsearch then it'll add to a queue that will cause |
185 |
it to be updated by a regular index cron job in the future. |
286 |
it to be updated by a regular index cron job in the future. |
186 |
|
287 |
|
|
|
288 |
=cut |
289 |
|
187 |
# TODO implement in the future - I don't know the best way of doing this yet. |
290 |
# TODO implement in the future - I don't know the best way of doing this yet. |
188 |
# If fork: make sure process group is changed so apache doesn't wait for us. |
291 |
# If fork: make sure process group is changed so apache doesn't wait for us. |
189 |
|
292 |
|
190 |
=cut |
|
|
191 |
|
192 |
sub update_index_background { |
293 |
sub update_index_background { |
193 |
my $self = shift; |
294 |
my $self = shift; |
194 |
$self->update_index(@_); |
295 |
$self->update_index(@_); |
195 |
} |
296 |
} |
196 |
|
297 |
|
197 |
=head2 $indexer->delete_index($biblionums) |
298 |
=head2 delete_index($biblionums) |
198 |
|
299 |
|
199 |
C<$biblionums> is an arrayref of biblionumbers to delete from the index. |
300 |
C<$biblionums> is an arrayref of biblionumbers to delete from the index. |
200 |
|
301 |
|
Lines 206-212
sub delete_index {
Link Here
|
206 |
if ( !$self->store ) { |
307 |
if ( !$self->store ) { |
207 |
my $params = $self->get_elasticsearch_params(); |
308 |
my $params = $self->get_elasticsearch_params(); |
208 |
$self->store( |
309 |
$self->store( |
209 |
Catmandu::Store::ElasticSearch->new( |
310 |
Catmandu::Store::Elasticsearch->new( |
210 |
%$params, |
311 |
%$params, |
211 |
index_settings => $self->get_elasticsearch_settings(), |
312 |
index_settings => $self->get_elasticsearch_settings(), |
212 |
index_mappings => $self->get_elasticsearch_mappings(), |
313 |
index_mappings => $self->get_elasticsearch_mappings(), |
Lines 217-239
sub delete_index {
Link Here
|
217 |
$self->store->bag->commit; |
318 |
$self->store->bag->commit; |
218 |
} |
319 |
} |
219 |
|
320 |
|
220 |
=head2 $indexer->delete_index_background($biblionums) |
321 |
=head2 delete_index_background($biblionums) |
221 |
|
322 |
|
222 |
Identical to L<delete_index>, this will return immediately and start a |
323 |
Identical to L</delete_index($biblionums)> |
223 |
background process to do the actual deleting. |
|
|
224 |
|
324 |
|
225 |
=cut |
325 |
=cut |
226 |
|
326 |
|
227 |
# TODO implement in the future |
327 |
# TODO: Should be made async |
228 |
|
|
|
229 |
sub delete_index_background { |
328 |
sub delete_index_background { |
230 |
my $self = shift; |
329 |
my $self = shift; |
231 |
$self->delete_index(@_); |
330 |
$self->delete_index(@_); |
232 |
} |
331 |
} |
233 |
|
332 |
|
234 |
=head2 $indexer->drop_index(); |
333 |
=head2 drop_index |
235 |
|
334 |
|
236 |
Drops the index from the elasticsearch server. |
335 |
Drops the index from the Elasticsearch server. |
237 |
|
336 |
|
238 |
=cut |
337 |
=cut |
239 |
|
338 |
|
Lines 243-252
sub drop_index {
Link Here
|
243 |
my $conf = $self->get_elasticsearch_params(); |
342 |
my $conf = $self->get_elasticsearch_params(); |
244 |
my $elasticsearch = $self->get_elasticsearch(); |
343 |
my $elasticsearch = $self->get_elasticsearch(); |
245 |
$elasticsearch->indices->delete(index => $conf->{index_name}); |
344 |
$elasticsearch->indices->delete(index => $conf->{index_name}); |
246 |
$self->index_status_recreate_required(1); |
345 |
$self->set_index_status_recreate_required(); |
247 |
} |
346 |
} |
248 |
} |
347 |
} |
249 |
|
348 |
|
|
|
349 |
=head2 create_index |
350 |
|
351 |
Creates the index (including mappings) on the Elasticsearch server. |
352 |
|
353 |
=cut |
354 |
|
250 |
sub create_index { |
355 |
sub create_index { |
251 |
my ($self) = @_; |
356 |
my ($self) = @_; |
252 |
my $conf = $self->get_elasticsearch_params(); |
357 |
my $conf = $self->get_elasticsearch_params(); |
Lines 261-266
sub create_index {
Link Here
|
261 |
$self->update_mappings(); |
366 |
$self->update_mappings(); |
262 |
} |
367 |
} |
263 |
|
368 |
|
|
|
369 |
=head2 index_exists |
370 |
|
371 |
Checks if index has been created on the ElasticSearch server. Returns C<1> or the |
372 |
empty string to indicate whether index exists or not. |
373 |
|
374 |
=cut |
375 |
|
264 |
sub index_exists { |
376 |
sub index_exists { |
265 |
my ($self) = @_; |
377 |
my ($self) = @_; |
266 |
my $conf = $self->get_elasticsearch_params(); |
378 |
my $conf = $self->get_elasticsearch_params(); |