Bug 12478: Change the commit count to 5k
[koha.git] / misc / search_tools / rebuild_elastic_search.pl
1 #!/usr/bin/perl
2
3 # This inserts records from a Koha database into elastic search
4
5 # Copyright 2014 Catalyst IT
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 3 of the License, or (at your option) any later
12 # version.
13 #
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License along
19 # with Koha; if not, write to the Free Software Foundation, Inc.,
20 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22 =head1 NAME
23
24 rebuild_elastic_search.pl - inserts records from a Koha database into Elasticsearch
25
26 =head1 SYNOPSIS
27
28 B<rebuild_elastic_search.pl>
29 [B<-c|--commit>=C<count>]
30 [B<-v|--verbose>]
31 [B<-h|--help>]
32 [B<--man>]
33
34 =head1 DESCRIPTION
35
36 =head1 OPTIONS
37
38 =over
39
40 =item B<-c|--commit>=C<count>
41
42 Specify how many records will be batched up before they're added to Elasticsearch.
43 Higher should be faster, but will cause more RAM usage. Default is 5000.
44
45 =item B<-d|--delete>
46
47 Delete the index and recreate it before indexing.
48
49 =item B<-a|--authorities>
50
51 Index the authorities only. Combining this with B<-b> is the same as
52 specifying neither and so both get indexed.
53
54 =item B<-b|--biblios>
55
56 Index the biblios only. Combining this with B<-a> is the same as
57 specifying neither and so both get indexed.
58
59 =item B<-bn|--bnumber>
60
61 Only index the supplied biblionumber, mostly for testing purposes. May be
62 repeated. This also applies to authorities via authid, so if you're using it,
63 you probably only want to do one or the other at a time.
64
65 =item B<-v|--verbose>
66
67 By default, this program only emits warnings and errors. This makes it talk
68 more. Add more to make it even more wordy, in particular when debugging.
69
70 =item B<-h|--help>
71
72 Help!
73
74 =item B<--man>
75
76 Full documentation.
77
78 =cut
79
80 use autodie;
81 use Getopt::Long;
82 use Koha::Authority;
83 use Koha::Biblio;
84 use Koha::ElasticSearch::Indexer;
85 use MARC::Field;
86 use MARC::Record;
87 use Modern::Perl;
88 use Pod::Usage;
89
90 use Data::Dumper; # TODO remove
91
92 my $verbose = 0;
93 my $commit = 5000;
94 my ($delete, $help, $man);
95 my ($index_biblios, $index_authorities);
96 my (@biblionumbers);
97
98 GetOptions(
99     'c|commit=i'       => \$commit,
100     'd|delete'         => \$delete,
101     'a|authorities' => \$index_authorities,
102     'b|biblios' => \$index_biblios,
103     'bn|bnumber=i' => \@biblionumbers,
104     'v|verbose!'       => \$verbose,
105     'h|help'           => \$help,
106     'man'              => \$man,
107 );
108
109 # Default is to do both
110 unless ($index_authorities || $index_biblios) {
111     $index_authorities = $index_biblios = 1;
112 }
113
114 pod2usage(1) if $help;
115 pod2usage( -exitstatus => 0, -verbose => 2 ) if $man;
116
117 my $next;
118 if ($index_biblios) {
119     _log(1, "Indexing biblios\n");
120     if (@biblionumbers) {
121         $next = sub {
122             my $r = shift @biblionumbers;
123             return () unless defined $r;
124             return ($r, Koha::Biblio->get_marc_biblio($r, item_data => 1));
125         };
126     } else {
127         my $records = Koha::Biblio->get_all_biblios_iterator();
128         $next = sub {
129             $records->next();
130         }
131     }
132     do_reindex($next, $Koha::ElasticSearch::BIBLIOS_INDEX);
133 }
134 if ($index_authorities) {
135     _log(1, "Indexing authorities\n");
136     if (@biblionumbers) {
137         $next = sub {
138             my $r = shift @biblionumbers;
139             return () unless defined $r;
140             my $a = Koha::Authority->get_from_authid($r);
141             return ($r, $a->record);
142         };
143     } else {
144         my $records = Koha::Authority->get_all_authorities_iterator();
145         $next = sub {
146             $records->next();
147         }
148     }
149     do_reindex($next, $Koha::ElasticSearch::AUTHORITIES_INDEX);
150 }
151
152 sub do_reindex {
153     my ( $next, $index_name ) = @_;
154
155     my $indexer = Koha::ElasticSearch::Indexer->new( { index => $index_name } );
156     if ($delete) {
157
158         # We know it's safe to not recreate the indexer because update_index
159         # hasn't been called yet.
160         $indexer->drop_index();
161     }
162
163     my $count        = 0;
164     my $commit_count = $commit;
165     my ( @id_buffer, @commit_buffer );
166     while ( my $record = $next->() ) {
167         my $id     = $record->idnumber;
168         my $record = $record->record;
169         _log( 1, "$id\n" );
170         $count++;
171
172         push @id_buffer,     $id;
173         push @commit_buffer, $record;
174         if ( !( --$commit_count ) ) {
175             _log( 2, "Committing...\n" );
176             $indexer->update_index( \@id_buffer, \@commit_buffer );
177             $commit_count  = $commit;
178             @id_buffer     = ();
179             @commit_buffer = ();
180         }
181     }
182
183     # There are probably uncommitted records
184     $indexer->update_index( \@id_buffer, \@commit_buffer );
185     _log( 1, "$count records indexed.\n" );
186 }
187
188 # Output progress information.
189 #
190 #   _log($level, $msg);
191 #
192 # Will output $msg if the verbosity setting is set to $level or more. Will
193 # not include a trailing newline.
194 sub _log {
195     my ($level, $msg) = @_;
196
197     print $msg if ($verbose <= $level);
198 }