File Coverage

blib/lib/Metabrik/Client/Elasticsearch/Query.pm
Criterion Covered Total %
statement 9 223 4.0
branch 0 160 0.0
condition 0 73 0.0
subroutine 3 23 13.0
pod 1 20 5.0
total 13 499 2.6


line stmt bran cond sub pod time code
1             #
2             # $Id$
3             #
4             # client::elasticsearch::query Brik
5             #
6             package Metabrik::Client::Elasticsearch::Query;
7 2     2   849 use strict;
  2         5  
  2         56  
8 2     2   10 use warnings;
  2         4  
  2         52  
9              
10 2     2   11 use base qw(Metabrik::Client::Elasticsearch);
  2         3  
  2         4124  
11              
12             sub brik_properties {
13             return {
14 0     0 1   revision => '$Revision$',
15             tags => [ qw(unstable) ],
16             author => 'GomoR ',
17             license => 'http://opensource.org/licenses/BSD-3-Clause',
18             attributes => {
19             nodes => [ qw(node_list) ], # Inherited
20             index => [ qw(index) ], # Inherited
21             type => [ qw(type) ], # Inherited
22             from => [ qw(number) ], # Inherited
23             size => [ qw(count) ], # Inherited
24             client => [ qw(INTERNAL) ],
25             },
26             attributes_default => {
27             index => '*',
28             type => '*',
29             },
30             commands => {
31             create_client => [ ],
32             reset_client => [ ],
33             query => [ qw(query index|OPTIONAL type|OPTIONAL hash|OPTIONAL) ],
34             get_query_result_total => [ qw($query_result|OPTIONAL) ],
35             get_query_result_hits => [ qw($query_result|OPTIONAL) ],
36             get_query_result_aggregations => [ qw($query_result|OPTIONAL) ],
37             get_query_result_timed_out => [ qw($query_result|OPTIONAL) ],
38             get_query_result_took => [ qw($query_result|OPTIONAL) ],
39             term => [ qw(kv index|OPTIONAL type|OPTIONAL) ],
40             unique_term => [ qw(unique kv index|OPTIONAL type|OPTIONAL) ],
41             unique_values => [ qw(field index|OPTIONAL type|OPTIONAL) ],
42             wildcard => [ qw(kv index|OPTIONAL type|OPTIONAL) ],
43             range => [ qw(kv_from kv_to index|OPTIONAL type|OPTIONAL) ],
44             top => [ qw(kv_count index|OPTIONAL type|OPTIONAL) ],
45             top_match => [ qw(kv_count kv_match index|OPTIONAL type|OPTIONAL) ],
46             match => [ qw(kv index|OPTIONAL type|OPTIONAL) ],
47             match_phrase => [ qw(kv index|OPTIONAL type|OPTIONAL) ],
48             from_json_file => [ qw(json_file index|OPTIONAL type|OPTIONAL) ],
49             from_dump_file => [ qw(dump_file index|OPTIONAL type|OPTIONAL) ],
50             },
51             require_modules => {
52             'Metabrik::File::Json' => [ ],
53             'Metabrik::File::Dump' => [ ],
54             },
55             };
56             }
57              
58             sub create_client {
59 0     0 0   my $self = shift;
60              
61 0           my $ce = $self->client;
62 0 0         if (! defined($ce)) {
63 0 0         $ce = $self->open or return;
64 0           $self->client($ce);
65             }
66              
67 0           return $ce;
68             }
69              
70             sub reset_client {
71 0     0 0   my $self = shift;
72              
73 0           my $ce = $self->client;
74 0 0         if (defined($ce)) {
75 0           $self->client(undef);
76             }
77              
78 0           return 1;
79             }
80              
81             sub get_query_result_total {
82 0     0 0   my $self = shift;
83 0           my ($run) = @_;
84              
85 0 0         $self->brik_help_run_undef_arg('get_query_result_total', $run) or return;
86 0 0         $self->brik_help_run_invalid_arg('get_query_result_total', $run, 'HASH') or return;
87              
88 0 0         if (! exists($run->{hits})) {
89 0           return $self->log->error("get_query_result_total: invalid query result, no hits found");
90             }
91 0 0         if (! exists($run->{hits}{total})) {
92 0           return $self->log->error("get_query_result_total: invalid query result, no total found");
93             }
94              
95 0           return $run->{hits}{total};
96             }
97              
98             sub get_query_result_hits {
99 0     0 0   my $self = shift;
100 0           my ($run) = @_;
101              
102 0 0         $self->brik_help_run_undef_arg('get_query_result_hits', $run) or return;
103 0 0         $self->brik_help_run_invalid_arg('get_query_result_hits', $run, 'HASH') or return;
104              
105 0 0         if (! exists($run->{hits})) {
106 0           return $self->log->error("get_query_result_hits: invalid query result, no hits found");
107             }
108 0 0         if (! exists($run->{hits}{hits})) {
109 0           return $self->log->error("get_query_result_hits: invalid query result, no hits in hits found");
110             }
111              
112 0           return $run->{hits}{hits};
113             }
114              
115             sub get_query_result_aggregations {
116 0     0 0   my $self = shift;
117 0           my ($run) = @_;
118              
119 0 0         $self->brik_help_run_undef_arg('get_query_result_aggregations', $run) or return;
120 0 0         $self->brik_help_run_invalid_arg('get_query_result_aggregations', $run, 'HASH')
121             or return;
122              
123 0 0         if (! exists($run->{aggregations})) {
124 0           return $self->log->error("get_query_result_aggregations: invalid query result, ".
125             "no aggregations found");
126             }
127              
128 0           return $run->{aggregations};
129             }
130              
131             sub get_query_result_timed_out {
132 0     0 0   my $self = shift;
133 0           my ($run) = @_;
134              
135 0 0         $self->brik_help_run_undef_arg('get_query_result_timed_out', $run) or return;
136 0 0         $self->brik_help_run_invalid_arg('get_query_result_timed_out', $run, 'HASH')
137             or return;
138              
139 0 0         if (! exists($run->{timed_out})) {
140 0           return $self->log->error("get_query_result_timed_out: invalid query result, ".
141             "no timed_out found");
142             }
143              
144 0 0         return $run->{timed_out} ? 1 : 0;
145             }
146              
147             sub get_query_result_took {
148 0     0 0   my $self = shift;
149 0           my ($run) = @_;
150              
151 0 0         $self->brik_help_run_undef_arg('get_query_result_took', $run) or return;
152 0 0         $self->brik_help_run_invalid_arg('get_query_result_took', $run, 'HASH')
153             or return;
154              
155 0 0         if (! exists($run->{took})) {
156 0           return $self->log->error("get_query_result_took: invalid query result, no took found");
157             }
158              
159 0           return $run->{took};
160             }
161              
162             sub query {
163 0     0 0   my $self = shift;
164 0           my ($q, $index, $type, $hash) = @_;
165              
166 0   0       $index ||= '*';
167 0   0       $type ||= '*';
168 0 0         $self->brik_help_run_undef_arg('query', $q) or return;
169              
170 0 0         my $ce = $self->create_client or return;
171              
172 0 0         my $r = $self->SUPER::query($q, $index, $type, $hash) or return;
173 0 0         if (defined($r)) {
174 0 0         if (exists($r->{hits}{total})) {
175 0           return $r;
176             }
177             else {
178 0           return $self->log->error("query: failed with [$r]");
179             }
180             }
181              
182 0           return $self->log->error("query: failed");
183             }
184              
185             #
186             # run client::elasticsearch::query term domain=example.com index1-*,index2-*
187             #
188             sub term {
189 0     0 0   my $self = shift;
190 0           my ($kv, $index, $type) = @_;
191              
192 0   0       $index ||= $self->index;
193 0   0       $type ||= $self->type;
194 0 0         $self->brik_help_run_undef_arg('term', $kv) or return;
195 0 0         $self->brik_help_set_undef_arg('term', $index) or return;
196 0 0         $self->brik_help_set_undef_arg('term', $type) or return;
197              
198 0 0         if ($kv !~ /^\S+?=.+$/) {
199 0           return $self->log->error("term: kv must be in the form 'key=value'");
200             }
201 0           my ($key, $value) = split('=', $kv);
202              
203 0           $self->log->debug("term: key[$key] value[$value]");
204              
205             # Optimized version on ES 5.0.0
206 0           my $q = {
207             size => $self->size,
208             query => {
209             bool => {
210             must => { term => { $key => $value } },
211             },
212             },
213             };
214              
215 0           $self->log->verbose("term: keys [$key] value [$value] index [$index] type [$type]");
216              
217 0           return $self->query($q, $index, $type);
218             }
219              
220             #
221             # run client::elasticsearch::query unique_term ip domain=example.com index1-*,index2-*
222             #
223             sub unique_term {
224 0     0 0   my $self = shift;
225 0           my ($unique, $kv, $index, $type) = @_;
226              
227 0   0       $index ||= $self->index;
228 0   0       $type ||= $self->type;
229 0 0         $self->brik_help_run_undef_arg('unique_term', $unique) or return;
230 0 0         $self->brik_help_run_undef_arg('unique_term', $kv) or return;
231 0 0         $self->brik_help_set_undef_arg('unique_term', $index) or return;
232 0 0         $self->brik_help_set_undef_arg('unique_term', $type) or return;
233              
234 0 0         if ($kv !~ m{^.+?=.+$}) {
235 0           return $self->log->error("unique_term: kv [$kv] must be in the form ".
236             "'key=value'");
237             }
238 0           my ($key, $value) = split('=', $kv);
239              
240 0           $self->log->debug("unique_term: key[$key] value[$value]");
241              
242             # Optimized version on ES 5.0.0
243 0           my $q = {
244             size => 0,
245             query => {
246             bool => {
247             must => { term => { $key => $value } },
248             },
249             },
250             aggs => {
251             1 => {
252             cardinality => {
253             field => $unique,
254             precision_threshold => 40000,
255             },
256             },
257             },
258             };
259              
260 0           $self->log->verbose("unique_term: unique [$unique] keys [$key] value [$value] ".
261             "index [$index] type [$type]");
262              
263 0           return $self->query($q, $index, $type);
264             }
265              
266             #
267             #
268             #
269             sub unique_values {
270 0     0 0   my $self = shift;
271 0           my ($field, $index, $type) = @_;
272              
273 0   0       $index ||= $self->index;
274 0   0       $type ||= $self->type;
275 0 0         $self->brik_help_run_undef_arg('unique_values', $field) or return;
276 0 0         $self->brik_help_set_undef_arg('unique_values', $index) or return;
277 0 0         $self->brik_help_set_undef_arg('unique_values', $type) or return;
278              
279 0           my $size = $self->size * 10;
280              
281             # Will return 10*100000=1_000_000 unique values.
282 0           my $q = {
283             aggs => {
284             1 => {
285             terms => {
286             field => $field,
287             include => { num_partitions => 10, partition => 0 },
288             size => $size,
289             },
290             },
291             },
292             size => 0,
293             };
294              
295 0           $self->log->verbose("unique_values: unique [$field] index [$index] type [$type]");
296              
297 0           return $self->query($q, $index, $type);
298             }
299              
300             sub wildcard {
301 0     0 0   my $self = shift;
302 0           my ($kv, $index, $type) = @_;
303              
304 0   0       $index ||= $self->index;
305 0   0       $type ||= $self->type;
306 0 0         $self->brik_help_run_undef_arg('wildcard', $kv) or return;
307 0 0         $self->brik_help_set_undef_arg('wildcard', $index) or return;
308 0 0         $self->brik_help_set_undef_arg('wildcard', $type) or return;
309              
310 0 0         if ($kv !~ /^\S+?=.+$/) {
311 0           return $self->log->error("wildcard: kv must be in the form 'key=value'");
312             }
313 0           my ($key, $value) = split('=', $kv);
314              
315 0           my $q = {
316             size => $self->size,
317             query => {
318             #constant_score => { # Does not like constant_score
319             #filter => {
320             wildcard => {
321             $key => $value,
322             },
323             #},
324             #},
325             },
326             };
327              
328 0           $self->log->verbose("wildcard: keys [$key] value [$value] index [$index] type [$type]");
329              
330 0           return $self->query($q, $index, $type);
331             }
332              
333             #
334             # run client::elasticsearch::query range ip_range.from=192.168.255.36 ip_range.to=192.168.255.36
335             #
336             sub range {
337 0     0 0   my $self = shift;
338 0           my ($kv_from, $kv_to, $index, $type) = @_;
339              
340 0   0       $index ||= $self->index;
341 0   0       $type ||= $self->type;
342 0 0         $self->brik_help_run_undef_arg('range', $kv_from) or return;
343 0 0         $self->brik_help_run_undef_arg('range', $kv_to) or return;
344 0 0         $self->brik_help_set_undef_arg('range', $index) or return;
345 0 0         $self->brik_help_set_undef_arg('range', $type) or return;
346              
347 0 0         if ($kv_from !~ /^\S+?=.+$/) {
348 0           return $self->log->error("range: kv_from [$kv_from] must be in the form 'key=value'");
349             }
350 0 0         if ($kv_to !~ /^\S+?=.+$/) {
351 0           return $self->log->error("range: kv_to [$kv_to] must be in the form 'key=value'");
352             }
353 0           my ($key_from, $value_from) = split('=', $kv_from);
354 0           my ($key_to, $value_to) = split('=', $kv_to);
355              
356             #
357             # http://stackoverflow.com/questions/40519806/no-query-registered-for-filtered
358             # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-filtered-query.html
359             # Compatible with ES 5.0
360             #
361 0           my $q = {
362             size => $self->size,
363             query => {
364             bool => {
365             must => [
366             { range => { $key_to => { gte => $value_to } } },
367             { range => { $key_from => { lte => $value_from } } },
368             ],
369             },
370             },
371             };
372              
373 0           return $self->query($q, $index, $type);
374             }
375              
376             #
377             # run client::elasticsearch::query top name=10 users-*
378             #
379             sub top {
380 0     0 0   my $self = shift;
381 0           my ($kv_count, $index, $type) = @_;
382              
383 0   0       $index ||= $self->index;
384 0   0       $type ||= $self->type;
385 0 0         $self->brik_help_run_undef_arg('top', $kv_count) or return;
386 0 0         $self->brik_help_set_undef_arg('top', $index) or return;
387 0 0         $self->brik_help_set_undef_arg('top', $type) or return;
388              
389 0 0         if ($kv_count !~ /^\S+=\d+$/) {
390 0           return $self->log->error("top: kv_count [$kv_count] must be in the form 'key=value'");
391             }
392 0           my ($key_count, $value_count) = split('=', $kv_count);
393              
394 0           my $q = {
395             aggs => {
396             top_values => {
397             terms => {
398             field => $key_count,
399             size => int($value_count),
400             order => { _count => 'desc' },
401             },
402             },
403             },
404             };
405              
406 0           $self->log->verbose("top: key [$key_count] value [$value_count] index [$index] type [$type]");
407              
408 0           return $self->query($q, $index, $type);
409             }
410              
411             sub match_phrase {
412 0     0 0   my $self = shift;
413 0           my ($kv, $index, $type) = @_;
414              
415 0   0       $index ||= $self->index;
416 0   0       $type ||= $self->type;
417 0 0         $self->brik_help_run_undef_arg('match_phrase', $kv) or return;
418 0 0         $self->brik_help_set_undef_arg('match_phrase', $index) or return;
419 0 0         $self->brik_help_set_undef_arg('match_phrase', $type) or return;
420              
421 0 0         if ($kv !~ /^\S+?=.+$/) {
422 0           return $self->log->error("match_phrase: kv must be in the form 'key=value'");
423             }
424 0           my ($key, $value) = split('=', $kv);
425              
426 0           $self->log->debug("match_phrase: key[$key] value[$value]");
427              
428 0           my $q = {
429             size => $self->size,
430             query => {
431             match_phrase => {
432             $key => $value,
433             },
434             },
435             };
436              
437 0           return $self->query($q, $index, $type);
438             }
439              
440             sub match {
441 0     0 0   my $self = shift;
442 0           my ($kv, $index, $type) = @_;
443              
444 0   0       $index ||= $self->index;
445 0   0       $type ||= $self->type;
446 0 0         $self->brik_help_run_undef_arg('match', $kv) or return;
447 0 0         $self->brik_help_set_undef_arg('match', $index) or return;
448 0 0         $self->brik_help_set_undef_arg('match', $type) or return;
449              
450 0 0         if ($kv !~ /^\S+?=.+$/) {
451 0           return $self->log->error("match: kv must be in the form 'key=value'");
452             }
453 0           my ($key, $value) = split('=', $kv);
454              
455 0           $self->log->debug("match: key[$key] value[$value]");
456              
457 0           my $q = {
458             size => $self->size,
459             query => {
460             match => {
461             $key => $value,
462             },
463             },
464             };
465              
466 0           return $self->query($q, $index, $type);
467             }
468              
469             #
470             # run client::elasticsearch::query top_match domain=10 host=*www*
471             #
472             sub top_match {
473 0     0 0   my $self = shift;
474 0           my ($kv_count, $kv_match, $index, $type) = @_;
475              
476 0   0       $index ||= $self->index;
477 0   0       $type ||= $self->type;
478 0 0         $self->brik_help_run_undef_arg('top_match', $kv_count) or return;
479 0 0         $self->brik_help_run_undef_arg('top_match', $kv_match) or return;
480 0 0         $self->brik_help_set_undef_arg('top_match', $index) or return;
481 0 0         $self->brik_help_set_undef_arg('top_match', $type) or return;
482              
483 0 0         if ($kv_count !~ /^\S+?=.+$/) {
484 0           return $self->log->error("top_match: kv_count [$kv_count] must be in the form 'key=value'");
485             }
486 0 0         if ($kv_match !~ /^\S+?=.+$/) {
487 0           return $self->log->error("top_match: kv_match [$kv_match] must be in the form 'key=value'");
488             }
489 0           my ($key_count, $value_count) = split('=', $kv_count);
490 0           my ($key_match, $value_match) = split('=', $kv_match);
491              
492 0           my $q = {
493             size => $self->size,
494             query => {
495             #constant_score => { # Does not like constant_score
496             #filter => {
497             match => {
498             $key_match => $value_match,
499             },
500             #},
501             #},
502             },
503             aggs => {
504             top_values => {
505             terms => {
506             field => $key_count,
507             size => int($value_count),
508             },
509             },
510             },
511             };
512              
513 0           return $self->query($q, $index, $type);
514             }
515              
516             sub from_json_file {
517 0     0 0   my $self = shift;
518 0           my ($file, $index, $type) = @_;
519              
520 0   0       $index ||= $self->index;
521 0   0       $type ||= $self->type;
522 0 0         $self->brik_help_run_undef_arg('from_json_file', $file) or return;
523 0 0         $self->brik_help_run_file_not_found('from_json_file', $file) or return;
524 0 0         $self->brik_help_set_undef_arg('from_json_file', $index) or return;
525 0 0         $self->brik_help_set_undef_arg('from_json_file', $type) or return;
526              
527 0 0         my $fj = Metabrik::File::Json->new_from_brik_init($self) or return;
528 0 0         my $q = $fj->read($file) or return;
529              
530 0 0 0       if (defined($q) && length($q)) {
531 0           return $self->query($q, $index, $type);
532             }
533              
534 0           return $self->log->error("from_json_file: nothing to read from this file [$file]");
535             }
536              
537             sub from_dump_file {
538 0     0 0   my $self = shift;
539 0           my ($file, $index, $type) = @_;
540              
541 0   0       $index ||= $self->index;
542 0   0       $type ||= $self->type;
543 0 0         $self->brik_help_run_undef_arg('from_dump_file', $file) or return;
544 0 0         $self->brik_help_run_file_not_found('from_dump_file', $file) or return;
545 0 0         $self->brik_help_set_undef_arg('from_dump_file', $index) or return;
546 0 0         $self->brik_help_set_undef_arg('from_dump_file', $type) or return;
547              
548 0 0         my $fd = Metabrik::File::Dump->new_from_brik_init($self) or return;
549 0 0         my $q = $fd->read($file) or return;
550              
551 0           my $first = $q->[0];
552 0 0         if (defined($first)) {
553 0           return $self->query($first, $index, $type);
554             }
555              
556 0           return $self->log->error("from_dump_file: nothing to read from this file [$file]");
557             }
558              
559             1;
560              
561             __END__