diff --git a/CHANGELOG.md b/CHANGELOG.md index 6798ccd361..8940ce9ba1 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/ruflin/Elastica/compare/7.1.1...master) ### Backward Compatibility Breaks ### Added + +* Added `Elastica\Aggregation\NormalizeAggregation` [#1956](https://github.com/ruflin/Elastica/pull/1956) + ### Changed * Using default Elasticsearch images for testing instead of OSS https://github.com/ruflin/Elastica/pull/1954 diff --git a/src/Aggregation/NormalizeAggregation.php b/src/Aggregation/NormalizeAggregation.php new file mode 100644 index 0000000000..190baaf1c7 --- /dev/null +++ b/src/Aggregation/NormalizeAggregation.php @@ -0,0 +1,72 @@ +setBucketsPath($bucketsPath); + } + + if (null !== $method) { + $this->setMethod($method); + } + } + + /** + * Set the buckets_path for this aggregation. + * + * @return $this + */ + public function setBucketsPath(string $bucketsPath): self + { + return $this->setParam('buckets_path', $bucketsPath); + } + + /** + * Set the method for this aggregation. + * + * @return $this + */ + public function setMethod(string $method): self + { + return $this->setParam('method', $method); + } + + /** + * Set the format for this aggregation. + * + * @return $this + */ + public function setFormat(string $format): self + { + return $this->setParam('format', $format); + } + + /** + * @throws InvalidException If buckets path or method are not set + */ + public function toArray(): array + { + if (!$this->hasParam('buckets_path')) { + throw new InvalidException('Buckets path is required'); + } + + if (!$this->hasParam('method')) { + throw new InvalidException('Method parameter is required'); + } + + return parent::toArray(); + } +} diff --git a/src/QueryBuilder/DSL/Aggregation.php b/src/QueryBuilder/DSL/Aggregation.php index 28b97f1cef..b461afb1c0 100644 --- a/src/QueryBuilder/DSL/Aggregation.php +++ b/src/QueryBuilder/DSL/Aggregation.php @@ -24,6 +24,7 @@ use Elastica\Aggregation\Min; use Elastica\Aggregation\Missing; use Elastica\Aggregation\Nested; +use Elastica\Aggregation\NormalizeAggregation; use Elastica\Aggregation\Percentiles; use Elastica\Aggregation\PercentilesBucket; use Elastica\Aggregation\Range; @@ -487,4 +488,14 @@ public function composite(string $name): Composite { return new Composite($name); } + + /** + * normalize aggregation. + * + * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-normalize-aggregation.html + */ + public function normalize(string $name, ?string $bucketsPath = null, ?string $method = null): NormalizeAggregation + { + return new NormalizeAggregation($name, $bucketsPath, $method); + } } diff --git a/src/QueryBuilder/Version/Version700.php b/src/QueryBuilder/Version/Version700.php index 9ccfc3be3f..3daefb32cd 100644 --- a/src/QueryBuilder/Version/Version700.php +++ b/src/QueryBuilder/Version/Version700.php @@ -94,6 +94,7 @@ class Version700 extends Version 'serial_diff', 'weighted_avg', 'composite', + 'normalize', ]; protected $suggesters = [ diff --git a/tests/Aggregation/NormalizeAggregationTest.php b/tests/Aggregation/NormalizeAggregationTest.php new file mode 100644 index 0000000000..2fa21eb238 --- /dev/null +++ b/tests/Aggregation/NormalizeAggregationTest.php @@ -0,0 +1,128 @@ + [ + 'field' => 'date', + 'interval' => 'day', + ], + 'aggs' => [ + 'sum_agg' => [ + 'sum' => [ + 'field' => 'value', + ], + ], + 'normalize_agg' => [ + 'normalize' => [ + 'buckets_path' => 'sum_agg', + 'method' => 'percent_of_sum', + 'format' => '00.00%', + ], + ], + ], + ]; + + $dateHistogramAgg = new DateHistogram('histogram_agg', 'date', 'day'); + + $sumAgg = new Sum('sum_agg'); + $sumAgg->setField('value'); + $dateHistogramAgg->addAggregation($sumAgg); + + $normalizeAgg = new NormalizeAggregation('normalize_agg', 'sum_agg', 'percent_of_sum'); + $normalizeAgg->setFormat('00.00%'); + $dateHistogramAgg->addAggregation($normalizeAgg); + + $this->assertEquals($expected, $dateHistogramAgg->toArray()); + } + + /** + * @group unit + */ + public function testToArrayInvalidBucketsPath(): void + { + $this->expectException(InvalidException::class); + + $normalizeAgg = new NormalizeAggregation('normalize_agg'); + $normalizeAgg->toArray(); + } + + /** + * @group unit + */ + public function testToArrayInvalidMethod(): void + { + $this->expectException(InvalidException::class); + + $normalizeAgg = new NormalizeAggregation('normalize_agg', 'agg'); + $normalizeAgg->toArray(); + } + + /** + * @group functional + */ + public function testNormalizeAggregation(): void + { + $this->_checkVersion('7.9'); + + $index = $this->_getIndexForTest(); + + $dateHistogramAgg = new DateHistogram('histogram_agg', 'date', 'day'); + $dateHistogramAgg->setFormat('yyyy-MM-dd'); + + $sumAgg = new Sum('sum_agg'); + $sumAgg->setField('value'); + $dateHistogramAgg->addAggregation($sumAgg); + + $normalizeAgg = new NormalizeAggregation('normalize_agg', 'sum_agg', 'percent_of_sum'); + $normalizeAgg->setFormat('00.00%'); + $dateHistogramAgg->addAggregation($normalizeAgg); + + $query = new Query(); + $query->addAggregation($dateHistogramAgg); + + $dateHistogramAggResult = $index->search($query)->getAggregation('histogram_agg')['buckets']; + + $this->assertCount(3, $dateHistogramAggResult); + + $this->assertEquals('14.29%', $dateHistogramAggResult[0]['normalize_agg']['value_as_string']); + $this->assertEquals('57.14%', $dateHistogramAggResult[1]['normalize_agg']['value_as_string']); + $this->assertEquals('28.57%', $dateHistogramAggResult[2]['normalize_agg']['value_as_string']); + } + + protected function _getIndexForTest(): Index + { + $index = $this->_createIndex(); + + $index->addDocuments([ + new Document(1, ['date' => '2018-12-01T01:00:00', 'value' => 1]), + new Document(2, ['date' => '2018-12-01T10:00:00', 'value' => 2]), + new Document(3, ['date' => '2018-12-02T02:00:00', 'value' => 3]), + new Document(4, ['date' => '2018-12-02T15:00:00', 'value' => 4]), + new Document(5, ['date' => '2018-12-02T20:00:00', 'value' => 5]), + new Document(6, ['date' => '2018-12-03T03:00:00', 'value' => 6]), + ]); + + $index->refresh(); + + return $index; + } +} diff --git a/tests/QueryBuilder/DSL/AggregationTest.php b/tests/QueryBuilder/DSL/AggregationTest.php index 70fb8f0a55..f890970f41 100644 --- a/tests/QueryBuilder/DSL/AggregationTest.php +++ b/tests/QueryBuilder/DSL/AggregationTest.php @@ -49,6 +49,7 @@ public function testInterface(): void $this->_assertImplemented($aggregationDSL, 'min', Aggregation\Min::class, ['name']); $this->_assertImplemented($aggregationDSL, 'missing', Aggregation\Missing::class, ['name', 'field']); $this->_assertImplemented($aggregationDSL, 'nested', Aggregation\Nested::class, ['name', 'path']); + $this->_assertImplemented($aggregationDSL, 'normalize', Aggregation\NormalizeAggregation::class, ['name']); $this->_assertImplemented($aggregationDSL, 'percentiles', Aggregation\Percentiles::class, ['name']); $this->_assertImplemented($aggregationDSL, 'percentiles_bucket', Aggregation\PercentilesBucket::class, ['name']); $this->_assertImplemented($aggregationDSL, 'range', Aggregation\Range::class, ['name']);