Skip to content

Commit abaae1d

Browse files
committed
[TASK] Add simple aggregation functionality
This change implements a new function addSimpleAggregation() and a new low-level function addSubAggregation to add (sub-) aggregatons to a elasticsearch request. Usage to get aggregation for property "color" in a node Vendor.Name:NodeType: `nodes = $Search.query(site).nodeType("Vendor.Name:NodeType").addSimpleAggregation("color", "color").execute() ` To get your aggregationResults access {nodes.aggregations} in your fluid template. This change also allows you to add sub-aggregations: `nodes = $Search.query(site).nodeType("Vendor.Name:NodeType").addSimpleAggregation("color", "color").addSimpleAggregation("type", "type", "terms", "color" ).execute() `
1 parent 20aab2d commit abaae1d

3 files changed

Lines changed: 164 additions & 1 deletion

File tree

Classes/Flowpack/ElasticSearch/ContentRepositoryAdaptor/Eel/ElasticSearchQueryBuilder.php

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class ElasticSearchQueryBuilder implements QueryBuilderInterface, ProtectedConte
6666
*
6767
* @var array
6868
*/
69-
protected $unsupportedFieldsInCountRequest = array('fields', 'sort', 'from', 'size', 'highlight');
69+
protected $unsupportedFieldsInCountRequest = array('fields', 'sort', 'from', 'size', 'highlight', 'aggs', 'aggregations');
7070

7171
/**
7272
* Amount of total items in response without limit
@@ -85,6 +85,13 @@ class ElasticSearchQueryBuilder implements QueryBuilderInterface, ProtectedConte
8585
*/
8686
protected $elasticSearchHitsIndexedByNodeFromLastRequest;
8787

88+
/**
89+
* This (internal) array stores all aggregation results for the last search request
90+
*
91+
* @var array
92+
*/
93+
protected $elasticSearchAggregationsFromLastRequest;
94+
8895
/**
8996
* The ElasticSearch request, as it is being built up.
9097
* @var array
@@ -396,6 +403,62 @@ public function queryFilterMultiple($data, $clauseType = 'must') {
396403
return $this;
397404
}
398405

406+
/**
407+
* Adds a simple aggregation with only filed set as configuration
408+
*
409+
* @param $name
410+
* @param $field
411+
* @param string $type
412+
* @param null $parentPath
413+
* @return $this
414+
*/
415+
public function addSimpleAggregation($name, $field, $type = 'terms', $parentPath = NULL) {
416+
if(!array_key_exists("aggregations", $this->request)) {
417+
$this->request['aggregations'] = array();
418+
}
419+
420+
$aggregation = array (
421+
$type => array (
422+
'field' => $field
423+
)
424+
);
425+
426+
if($parentPath !== NULL) {
427+
$this->addSubAggregation($parentPath, $name, $aggregation);
428+
} else {
429+
$this->request['aggregations'][$name] = $aggregation;
430+
}
431+
432+
return $this;
433+
}
434+
435+
/**
436+
* This is an low level method for internal usage.
437+
* You can add a custom $aggregationConfiguration under a given $parentPath. The $parentPath foo.bar would
438+
* insert your $aggregationConfiguration under
439+
* $this->request['aggregations']['foo']['aggregations']['bar']['aggregations'][$name]
440+
*
441+
* @param $parentPath
442+
* @param $name
443+
* @param array $aggregationConfiguration
444+
* @return $this
445+
* @throws QueryBuildingException
446+
*/
447+
public function addSubAggregation($parentPath, $name, $aggregationConfiguration) {
448+
// Find the parentPath
449+
$path =& $this->request['aggregations'];
450+
451+
foreach(explode(".", $parentPath) as $subPart) {
452+
if($path == NULL || !array_key_exists($subPart, $path)) {
453+
throw new QueryBuildingException("The parent path ".$subPart." could not be found when adding a sub aggregation");
454+
}
455+
$path =& $path[$subPart]['aggregations'];
456+
}
457+
458+
$path[$name] = $aggregationConfiguration;
459+
return $this;
460+
}
461+
399462
/**
400463
* Get the ElasticSearch request as we need it
401464
*
@@ -519,6 +582,10 @@ public function fetch() {
519582

520583
$this->elasticSearchHitsIndexedByNodeFromLastRequest = $elasticSearchHitPerNode;
521584

585+
if(array_key_exists("aggregations", $treatedContent)) {
586+
$this->elasticSearchAggregationsFromLastRequest = $treatedContent['aggregations'];
587+
}
588+
522589
return array_values($nodes);
523590
}
524591

@@ -534,6 +601,13 @@ public function execute() {
534601
return $result;
535602
}
536603

604+
/**
605+
* @return array
606+
*/
607+
public function getElasticSearchAggregationsFromLastRequest() {
608+
return $this->elasticSearchAggregationsFromLastRequest;
609+
}
610+
537611
/**
538612
* Return the total number of hits for the query.
539613
*

Classes/Flowpack/ElasticSearch/ContentRepositoryAdaptor/Eel/ElasticSearchQueryResult.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ public function getAccessibleCount() {
164164
return count($this->results);
165165
}
166166

167+
/**
168+
* @return array
169+
*/
170+
public function getAggregations() {
171+
$this->initialize();
172+
return $this->elasticSearchQuery->getQueryBuilder()->getElasticSearchAggregationsFromLastRequest();
173+
}
174+
167175
/**
168176
* Returns the ElasticSearch "hit" (e.g. the raw content being transferred back from ElasticSearch)
169177
* for the given node.

Tests/Unit/Eel/ElasticSearchQueryBuilderTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ public function sortDescWorks() {
175175
$this->assertSame($expected, $actual['sort']);
176176
}
177177

178+
/**
179+
* @return array
180+
*/
178181
public function rangeConstraintExamples() {
179182
return array(
180183
array('greaterThan', 'gt', 10),
@@ -199,6 +202,84 @@ public function rangeConstraintsWork($constraint, $operator, $value) {
199202
$this->assertInArray($expected, $actual['query']['filtered']['filter']['bool']['must']);
200203
}
201204

205+
/**
206+
* @return array
207+
*/
208+
public function simpleAggregationExamples() {
209+
return array(
210+
array('min', 'foo', 'bar'),
211+
array('terms', 'foo', 'bar'),
212+
array('sum', 'foo', 'bar'),
213+
array('stats', 'foo', 'bar'),
214+
array('value_count', 'foo', 'bar')
215+
);
216+
}
217+
218+
/**
219+
* @test
220+
* @dataProvider simpleAggregationExamples
221+
*/
222+
public function anSimpleAggregationCanBeAddedToTheRequest($type, $name, $field) {
223+
$expected = array(
224+
$name => array(
225+
$type => array(
226+
'field' => $field
227+
)
228+
)
229+
);
230+
231+
$this->queryBuilder->addSimpleAggregation($name, $field, $type);
232+
$actual = $this->queryBuilder->getRequest();
233+
234+
$this->assertInArray($expected, $actual);
235+
}
236+
237+
/**
238+
* @test
239+
*/
240+
public function anAggregationCanBeSubbedUnderAPath() {
241+
$this->queryBuilder->addSimpleAggregation("foo", "bar");
242+
$this->queryBuilder->addSimpleAggregation("bar", "bar", "terms", "foo");
243+
$this->queryBuilder->addSimpleAggregation("baz", "bar", "terms", "foo.bar");
244+
245+
$expected = array(
246+
"foo" => array(
247+
"terms" => array("field" => "bar"),
248+
"aggregations" => array(
249+
"bar" => array(
250+
"terms" => array("field" => "bar"),
251+
"aggregations" => array(
252+
"baz" => array(
253+
"terms" => array("field" => "bar")
254+
)
255+
)
256+
)
257+
)
258+
)
259+
);
260+
261+
$actual = $this->queryBuilder->getRequest();
262+
$this->assertInArray($expected, $actual);
263+
}
264+
265+
/**
266+
* @test
267+
* @expectedException \Flowpack\ElasticSearch\ContentRepositoryAdaptor\Exception\QueryBuildingException
268+
*/
269+
public function ifTheParentPathDoesNotExistAnExceptionisThrown() {
270+
$this->queryBuilder->addSimpleAggregation("foo", "bar");
271+
$this->queryBuilder->addSimpleAggregation("bar", "bar", "terms", "doesNotExist");
272+
}
273+
274+
/**
275+
* @test
276+
* @expectedException \Flowpack\ElasticSearch\ContentRepositoryAdaptor\Exception\QueryBuildingException
277+
*/
278+
public function ifSubbedParentPathDoesNotExistAnExceptionisThrown() {
279+
$this->queryBuilder->addSimpleAggregation("foo", "bar");
280+
$this->queryBuilder->addSimpleAggregation("bar", "bar", "terms", "foo.doesNotExist");
281+
}
282+
202283
/**
203284
* Test helper
204285
*

0 commit comments

Comments
 (0)