File Coverage

blib/lib/Elastic/Model/Result.pm
Criterion Covered Total %
statement 18 61 29.5
branch 0 16 0.0
condition 0 8 0.0
subroutine 6 15 40.0
pod 2 2 100.0
total 26 102 25.4


line stmt bran cond sub pod time code
1             package Elastic::Model::Result;
2             $Elastic::Model::Result::VERSION = '0.52';
3 1     1   1009 use Moose;
  1         3  
  1         8  
4              
5 1     1   6594 use Carp;
  1         2  
  1         78  
6 1     1   5 use Elastic::Model::Types qw(UID);
  1         3  
  1         10  
7 1     1   6551 use MooseX::Types::Moose qw(HashRef Maybe Num Bool);
  1         2  
  1         9  
8              
9 1     1   5707 use namespace::autoclean;
  1         2  
  1         12  
10              
11             #===================================
12             has 'result' => (
13             #===================================
14                 isa => HashRef,
15                 is => 'ro',
16                 required => 1,
17             );
18              
19             #===================================
20             has 'is_partial' => (
21             #===================================
22                 isa => Bool,
23                 is => 'ro',
24                 required => 1,
25             );
26              
27             #===================================
28             has 'uid' => (
29             #===================================
30                 isa => UID,
31                 is => 'ro',
32                 lazy => 1,
33                 builder => '_build_uid',
34                 handles => [ 'index', 'type', 'id', 'routing' ]
35             );
36              
37             #===================================
38             has 'source' => (
39             #===================================
40                 is => 'ro',
41                 isa => Maybe [HashRef],
42                 lazy => 1,
43                 builder => '_build_source',
44             );
45              
46             #===================================
47             has 'score' => (
48             #===================================
49                 is => 'ro',
50                 isa => Num,
51                 lazy => 1,
52                 builder => '_build_score'
53             );
54              
55             #===================================
56             has 'fields' => (
57             #===================================
58                 is => 'ro',
59                 isa => HashRef,
60                 traits => ['Hash'],
61                 lazy => 1,
62                 builder => '_build_fields',
63                 handles => { field => 'get' }
64             );
65              
66             #===================================
67             has 'highlights' => (
68             #===================================
69                 is => 'ro',
70                 isa => HashRef,
71                 lazy => 1,
72                 builder => '_build_highlights'
73             );
74              
75             #===================================
76             has 'object' => (
77             #===================================
78                 is => 'ro',
79                 does => 'Elastic::Model::Role::Doc',
80                 lazy => 1,
81                 builder => '_build_object'
82             );
83              
84             #===================================
85             has 'partial' => (
86             #===================================
87                 is => 'ro',
88                 does => 'Elastic::Model::Role::Doc',
89                 lazy => 1,
90                 builder => '_build_partial'
91             );
92              
93 1     1   257 no Moose;
  1         2  
  1         6  
94              
95             #===================================
96 0     0     sub _build_uid { Elastic::Model::UID->new_from_store( shift()->result ) }
97 0     0     sub _build_score { shift->result->{_score} }
98 0 0   0     sub _build_fields { shift->result->{fields} || {} }
99 0 0   0     sub _build_highlights { shift->result->{highlight} || {} }
100             #===================================
101              
102             #===================================
103             sub _build_source {
104             #===================================
105 0     0         my $self = shift;
106 0 0             return undef if $self->is_partial;
107 0               return $self->result->{_source};
108             }
109              
110             #===================================
111             sub _build_object {
112             #===================================
113 0     0         my $self = shift;
114 0   0           $self->result->{_object} ||= $self->model->get_doc(
115                     uid => $self->uid,
116                     source => $self->source
117                 );
118             }
119              
120             #===================================
121             sub _build_partial {
122             #===================================
123 0     0         my $self = shift;
124                 $self->result->{_partial} ||= $self->model->new_partial_doc(
125                     uid => Elastic::Model::UID->new_partial( $self->result ),
126                     partial_source => $self->result->{_source}
127 0   0           );
128             }
129              
130             #===================================
131             sub highlight {
132             #===================================
133 0     0 1       my $self = shift;
134 0 0             my $field = shift() or croak "Missing (field) name";
135 0 0             my $highlights = $self->highlights->{$field} or return;
136 0               return @{$highlights};
  0            
137             }
138              
139             #===================================
140             sub explain {
141             #===================================
142 0     0 1       my $self = shift;
143              
144 0               my $result = $self->result;
145                 my $explain = $result->{_explanation}
146 0   0               || return "No explanation\n";
147              
148                 my $text = sprintf "Doc: [%s|%s|%s], Shard: [%s|%d]:\n",
149 0 0                 map { defined $_ ? $_ : 'undef' }
150 0                   @{$result}{qw(_index _type _id _node _shard)};
  0            
151              
152 0               my $indent = 0;
153 0               my @stack = [$explain];
154              
155 0               while (@stack) {
156 0                   my @current = @{ shift @stack };
  0            
157 0                   while ( my $next = shift @current ) {
158 0                       my $spaces = ( ' ' x $indent ) . ' - ';
159 0                       my $max = 67 - $indent;
160 0 0                     $max = 30 if $max < 30;
161 0                       my $desc = $next->{description};
162 0                       while ( length($desc) > $max ) {
163 0                           $desc =~ s/^(.{30,${max}\b|.{${max}})\s*//;
164 0                           $text .= sprintf "%-70s |\n", $spaces . $1;
165                         }
166                         $text .= sprintf "%-70s | % 9.4f\n", $spaces . $desc,
167 0                           $next->{value};
168 0 0                     if ( my $details = $next->{details} ) {
169 0                           unshift @stack, [@current];
170 0                           @current = @{$details};
  0            
171 0                           $indent += 2;
172                         }
173                     }
174 0                   $indent -= 2;
175                 }
176 0               return $text;
177             }
178              
179             1;
180              
181             =pod
182            
183             =encoding UTF-8
184            
185             =head1 NAME
186            
187             Elastic::Model::Result - A wrapper for individual search results
188            
189             =head1 VERSION
190            
191             version 0.52
192            
193             =head1 SYNOPSIS
194            
195             $result = $results->next_result;
196            
197             $object = $result->object;
198             $uid = $result->uid;
199             $partial_obj = $result->partial;
200            
201             \%all_highlights = $result->highlights;
202             @field_highlights = $result->highlight('field_name');
203            
204             \%all_fields = $result->fields;
205             $field_value = $result->field('field_name');
206             $script_field_value = $result->field('script_field_name');
207            
208             $explain = $result->explain;
209             $score = $result->score;
210             \%source_field = $result->source;
211             \%raw_result = $result->result;
212            
213             =head1 DESCRIPTION
214            
215             L<Elastic::Model::Result> wraps the individual result returned from
216             L<Elastic::Model::Results>, L<Elastic::Model::Results::Cached>
217             or L<Elastic::Model::Results::Scrolled>.
218            
219             =head1 ATTRIBUTES
220            
221             =head2 object
222            
223             $object = $result->object();
224            
225             The object associated with the result. By default, the L</source> field is
226             returned in search results, meaning that we can inflate the object directly from
227             the search results. B<Note:> If you set L<Elastic::Model::View/fields> and you
228             don't include C<'_source'> then you will be unable to inflate your object
229             without a separate (but automatic) step to retrieve it from Elasticsearch.
230            
231             Also see L<Elastic::Manual::Scoping>.
232            
233             =head2 uid
234            
235             =head2 index, type, id, routing
236            
237             $uid = $result->uid;
238             $index = $result->index | $result->uid->index;
239             $type = $result->type | $result->uid->type;
240             $id = $result->id | $result->uid->id;
241             $routing = $result->routing | $result->uid->routing;
242            
243             The L<uid|Elastic::Model::UID> of the doc. L<index|Elastic::Model::UID/index>,
244             L<type|Elastic::Model::UID/type>, L<id|Elastic::Model::UID/id>
245             and L<routing|Elastic::Model::UID/routing> are provided for convenience.
246            
247             =head2 partial
248            
249             $partial_obj = $result->partial_object();
250            
251             If your objects are large, you may want to load only part of the object in your
252             search results. You can specify which parts of the object to include or exclude
253             using L<Elastic::Model::View/"include_paths / exclude_paths">.
254            
255             The partial objects returned by L</partial> function exactly as real objects,
256             except that they cannot be saved.
257            
258             =head2 is_partial
259            
260             $bool = $result->is_partial;
261            
262             Return C<true> or C<false> to indicate whether the currently loaded
263             C<_source> field is partial or not.
264            
265             =head2 highlights
266            
267             =head2 highlight
268            
269             \%all_highlights = $result->highlights;
270             @field_highlights = $result->highlight('field_name');
271            
272             The snippets from the L<highlighted fields|Elastic::Model::View/highlight>
273             in your L<view|Elastic::Model::View>. L</highlights> returns a hash ref
274             containing snippets from all the highlighted fields, while L</highlight> returns
275             a list of the snippets for the named field.
276            
277             =head2 fields
278            
279             =head2 field
280            
281             \%all_fields = $result->fields;
282             $field_value = $result->field('field_name');
283             $script_field_value = $result->field('script_field_name');
284            
285             The values of any L<fields|Elastic::Model::View/fields> or
286             L<script_fields|Elastic::Model::View/script_fields> specified in your
287             L<view|Elastic::Model::View>.
288            
289             =head2 score
290            
291             $score = $result->score;
292            
293             The relevance score of the result. Note: if you L<sort|Elastic::Model::View/sort>
294             on any value other than C<_score> then the L</score> will be zero, unless you
295             also set L<Elastic::Model::View/track_scores> to a true value.
296            
297             =head2 explain
298            
299             $explanation = $result->explain;
300            
301             If L<Elastic::Model::View/explain> is set to true, then you can retrieve
302             the text explanation using L</explain>, for instance:
303            
304             print $result->explain;
305            
306             Doc: [myapp|user|BS8mmGFhRdS5YcpeLkdw_g], Shard: [a7gbLmJWQE2EdIaP_Rnnew|4]:
307             - product of: | 1.1442
308             - sum of: | 2.2885
309             - weight(name:aardwolf in 0), product of: | 2.2885
310             - queryWeight(name:aardwolf), product of: | 0.6419
311             - idf(docFreq=1, maxDocs=26) | 3.5649
312             - queryNorm | 0.1801
313             - fieldWeight(name:aardwolf in 0), product of: | 3.5649
314             - tf(termFreq(name:aardwolf)=1) | 1.0000
315             - idf(docFreq=1, maxDocs=26) | 3.5649
316             - fieldNorm(field=name, doc=0) | 1.0000
317             - coord(1/2) | 0.5000
318            
319             And here's a brief explanation of what these numbers mean:
320             L<http://www.lucenetutorial.com/advanced-topics/scoring.html>.
321            
322             =head2 result
323            
324             \%raw_result = $result->result
325            
326             The raw result hashref as returned by Elasticsearch.
327            
328             =head2 source
329            
330             \%source_field = $result->source
331            
332             The C<_source> field (ie the hashref which represents your object in
333             Elasticsearch). This value is returned by default with any search, and is
334             used to inflate your L</object> without having to retrieve it in a separate
335             step. B<Note:> If you set L<Elastic::Model::View/fields> and you don't include
336             C<'_source'> then you will be unable to inflate your object without a separate
337             (but automatic) step to retrieve it from Elasticsearch.
338            
339             =head1 AUTHOR
340            
341             Clinton Gormley <drtech@cpan.org>
342            
343             =head1 COPYRIGHT AND LICENSE
344            
345             This software is copyright (c) 2015 by Clinton Gormley.
346            
347             This is free software; you can redistribute it and/or modify it under
348             the same terms as the Perl 5 programming language system itself.
349            
350             =cut
351              
352             __END__
353            
354             # ABSTRACT: A wrapper for individual search results
355            
356