File Coverage

blib/lib/Catmandu/Store/ElasticSearch.pm
Criterion Covered Total %
statement 12 21 57.1
branch 0 2 0.0
condition n/a
subroutine 4 7 57.1
pod 1 2 50.0
total 17 32 53.1


line stmt bran cond sub pod time code
1             package Catmandu::Store::ElasticSearch;
2              
3 1     1   1220 use Catmandu::Sane;
  1         95542  
  1         5  
4 1     1   233 use Moo;
  1         1  
  1         6  
5 1     1   802 use Search::Elasticsearch;
  1         21201  
  1         50  
6 1     1   825 use Catmandu::Store::ElasticSearch::Bag;
  1         4  
  1         376  
7              
8             with 'Catmandu::Store';
9              
10             =head1 NAME
11              
12             Catmandu::Store::ElasticSearch - A searchable store backed by Elasticsearch
13              
14             =cut
15              
16             our $VERSION = '0.0304';
17              
18             =head1 SYNOPSIS
19              
20             use Catmandu::Store::ElasticSearch;
21              
22             my $store = Catmandu::Store::ElasticSearch->new(index_name => 'catmandu');
23              
24             my $obj1 = $store->bag->add({ name => 'Patrick' });
25              
26             printf "obj1 stored as %s\n" , $obj1->{_id};
27              
28             # Force an id in the store
29             my $obj2 = $store->bag->add({ _id => 'test123' , name => 'Nicolas' });
30              
31             # Commit all changes
32             $store->bag->commit;
33              
34             my $obj3 = $store->bag->get('test123');
35              
36             $store->bag->delete('test123');
37              
38             $store->bag->delete_all;
39              
40             # All bags are iterators
41             $store->bag->each(sub { ... });
42             $store->bag->take(10)->each(sub { ... });
43              
44             # Some stores can be searched
45             my $hits = $store->bag->search(query => 'name:Patrick');
46              
47             # Catmandu::Store::ElasticSearch supports CQL...
48             my $hits = $store->bag->search(cql_query => 'name any "Patrick"');
49              
50             =cut
51              
52             has index_name => (is => 'ro', required => 1);
53             has index_settings => (is => 'ro', lazy => 1, default => sub { +{} });
54             has index_mappings => (is => 'ro', lazy => 1, default => sub { +{} });
55             has _es_args => (is => 'rw', lazy => 1, default => sub { +{} });
56             has es => (is => 'lazy');
57              
58             sub _build_es {
59 0     0     my ($self) = @_;
60 0           my $es = Search::Elasticsearch->new($self->_es_args);
61 0 0         unless ($es->indices->exists(index => $self->index_name)) {
62 0           $es->indices->create(
63             index => $self->index_name,
64             body => {
65             settings => $self->index_settings,
66             mappings => $self->index_mappings,
67             },
68             );
69             }
70 0           $es;
71             }
72              
73             sub BUILD {
74 0     0 0   my ($self, $args) = @_;
75 0           $self->_es_args($args);
76             }
77              
78             sub drop {
79 0     0 1   my ($self) = @_;
80 0           $self->es->indices->delete(index => $self->index_name);
81             }
82              
83             =head1 METHODS
84              
85             =head2 new(index_name => $name)
86              
87             =head2 new(index_name => $name , bags => { data => { cql_mapping => \%mapping } })
88              
89             =head2 new(index_name => $name , index_mapping => $mapping)
90              
91             Create a new Catmandu::Store::ElasticSearch store connected to index $name.
92              
93             The store supports CQL searches when a cql_mapping is provided. This hash
94             contains a translation of CQL fields into Elasticsearch searchable fields.
95              
96             # Example mapping
97             $cql_mapping = {
98             title => {
99             op => {
100             'any' => 1 ,
101             'all' => 1 ,
102             '=' => 1 ,
103             '<>' => 1 ,
104             'exact' => {field => [qw(mytitle.exact myalttitle.exact)]}
105             } ,
106             sort => 1,
107             field => 'mytitle',
108             cb => ['Biblio::Search', 'normalize_title']
109             }
110             }
111              
112             The CQL mapping above will support for the 'title' field the CQL operators: any, all, =, <> and exact.
113              
114             For all the operators the 'title' field will be mapping into the Elasticsearch field 'mytitle', except
115             for the 'exact' operator. In case of 'exact' we will search both the 'mytitle.exact' and 'myalttitle.exact'
116             fields.
117              
118             The CQL mapping allows for sorting on the 'title' field. If, for instance, we would like to use a special
119             Elasticsearch field for sorting we could have written "sort => { field => 'mytitle.sort' }".
120              
121             The CQL has an optional callback field 'cb' which contains a reference to subroutines to rewrite or
122             augment the search query. In this case, in the Biblio::Search package there is a normalize_title
123             subroutine which returns a string or an ARRAY of string with augmented title(s). E.g.
124              
125             package Biblio::Search;
126              
127             sub normalize_title {
128             my ($self,$title) = @_;
129             my $new_title =~ s{[^A-Z0-9]+}{}g;
130             $new_title;
131             }
132              
133             1;
134              
135             Optionally, index_mappings contain Elasticsearch schema mappings. E.g.
136              
137             # The 'data' index can ony contain one field 'title' of type 'string'
138             index_mappings => {
139             data => {
140             dynamic => 'strict',
141             properties => {
142             title => { type => 'string' }
143             }
144             }
145             }
146              
147             =head2 drop
148              
149             Deletes the Elasticsearch index backing this store. Calling functions after
150             this may fail until this class is reinstantiated, creating a new index.
151              
152             =head1 COMPATIBILITY
153              
154             This store expects version 1.0 or higher of the Elasticsearch server.
155              
156             =head1 ERROR HANDLING
157              
158             Error handling can be activated by specifying an error handling callback for index when creating
159             a store. E.g. to create an error handler for the bag 'data' index use:
160              
161             my $store = Catmandu::Store::ElasticSearch->new(
162             index_name => 'catmandu'
163             bags => { data => { on_error => \&error_handler } }
164             });
165              
166             sub error_handler {
167             my ($action,$response,$i) = @_;
168             }
169              
170             =head1 SEE ALSO
171              
172             L
173              
174             =head1 AUTHOR
175              
176             Nicolas Steenlant, C<< >>
177              
178             =head1 CONTRIBUTORS
179              
180             =over 4
181              
182             =item Dave Sherohman, C<< dave.sherohman at ub.lu.se >>
183              
184             =item Robin Sheat, C<< robin at kallisti.net.nz >>
185              
186             =item Patrick Hochstenbach, C<< patrick.hochstenbach at ugent.be >>
187              
188             =back
189              
190             =head1 LICENSE AND COPYRIGHT
191              
192             This program is free software; you can redistribute it and/or modify it
193             under the terms of either: the GNU General Public License as published
194             by the Free Software Foundation; or the Artistic License.
195              
196             See http://dev.perl.org/licenses/ for more information.
197              
198             =cut
199              
200             1;