Skip to content

Commit a665505

Browse files
author
Miroshnichenko
committed
add sort by script in aggregation
1 parent 78c0c6f commit a665505

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuery\Aggregating\Metrics;
4+
5+
use Ensi\LaravelElasticQuery\Aggregating\Result;
6+
use Ensi\LaravelElasticQuery\Contracts\Aggregation;
7+
use Ensi\LaravelElasticQuery\Contracts\ScriptLang;
8+
use Webmozart\Assert\Assert;
9+
10+
class ScriptAggregation implements Aggregation
11+
{
12+
public function __construct(
13+
private readonly string $name,
14+
private readonly string $aggregationType,
15+
private readonly array $params,
16+
private readonly string $source,
17+
private readonly string $lang = ScriptLang::PAINLESS,
18+
) {
19+
Assert::stringNotEmpty(trim($name));
20+
Assert::stringNotEmpty(trim($aggregationType));
21+
Assert::stringNotEmpty(trim($source));
22+
Assert::oneOf($lang, ScriptLang::cases());
23+
}
24+
25+
public function name(): string
26+
{
27+
return $this->name;
28+
}
29+
30+
public function parseResults(array $response): array
31+
{
32+
return [$this->name => Result::parseValue($response[$this->name]) ?? 0];
33+
}
34+
35+
public function toDSL(): array
36+
{
37+
$script = [
38+
'source' => $this->source,
39+
'lang' => $this->lang,
40+
];
41+
42+
if (!empty($this->params)) {
43+
$script['params'] = $this->params;
44+
}
45+
46+
return [
47+
$this->name => [
48+
$this->aggregationType => [
49+
'script' => $script,
50+
],
51+
],
52+
];
53+
}
54+
}

tests/IntegrationTests/AggregationQueryIntegrationTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
<?php
22

3+
use Ensi\LaravelElasticQuery\Aggregating\AggregationCollection;
34
use Ensi\LaravelElasticQuery\Aggregating\Bucket;
45
use Ensi\LaravelElasticQuery\Aggregating\FiltersCollection;
56
use Ensi\LaravelElasticQuery\Aggregating\Metrics\MinMaxScoreAggregation;
7+
use Ensi\LaravelElasticQuery\Aggregating\Metrics\ScriptAggregation;
68
use Ensi\LaravelElasticQuery\Aggregating\Metrics\TopHitsAggregation;
79
use Ensi\LaravelElasticQuery\Aggregating\MinMax;
810
use Ensi\LaravelElasticQuery\Aggregating\Range;
911
use Ensi\LaravelElasticQuery\Contracts\AggregationsBuilder;
1012
use Ensi\LaravelElasticQuery\Filtering\Criterias\RangeBound;
1113
use Ensi\LaravelElasticQuery\Filtering\Criterias\Term;
1214
use Ensi\LaravelElasticQuery\Search\Sorting\Sort;
15+
use Ensi\LaravelElasticQuery\Search\Sorting\SortCollection;
1316
use Ensi\LaravelElasticQuery\Tests\Data\Models\ProductsIndex;
1417
use Ensi\LaravelElasticQuery\Tests\IntegrationTestCase;
1518

@@ -210,3 +213,52 @@
210213
);
211214
}
212215
})->with([null, 'default_bucket']);
216+
217+
test('aggregation query by script', function () {
218+
/** @var IntegrationTestCase $this */
219+
$fieldName = 'max_tag_by_script';
220+
221+
$sort = new SortCollection();
222+
$sort->add(new Sort($fieldName));
223+
224+
$termAggregation = new AggregationCollection();
225+
$termAggregation->add(new ScriptAggregation(
226+
name: $fieldName,
227+
aggregationType: 'max',
228+
params: ['tag' => 'video'],
229+
source: '
230+
if (doc.containsKey("tags")
231+
&& doc["tags"].size() > 0
232+
&& doc["tags"].contains(params.tag)
233+
) {
234+
return 0;
235+
}
236+
return 1;
237+
',
238+
));
239+
240+
$results = ProductsIndex::aggregate()
241+
->terms(
242+
name: 'group_by',
243+
field: 'product_id',
244+
size: 3,
245+
sort: $sort,
246+
composite: $termAggregation
247+
)
248+
->get()
249+
->get('group_by');
250+
251+
$scores = $results->map(
252+
fn (Bucket $bucket) => $bucket->getCompositeValue($fieldName)
253+
)->toArray();
254+
255+
assertEqualsCanonicalizing(
256+
[1, 328, 150],
257+
$results->pluck('key')->toArray(),
258+
);
259+
260+
assertEqualsCanonicalizing(
261+
[0.0, 0.0, 1.0],
262+
$scores,
263+
);
264+
});

0 commit comments

Comments
 (0)