Elastica 未在 setScript 之前对聚合进行分组
Elastica not grouping aggregation before setScript
我在elasticsearch中有一个type product,其中包含一个包含多个id的列,其中一些是相同的。
还有包含当前价格和数量的列。我想要获得每个唯一 ID 的价格总和 * qte。
id price qte
__ _____ _________
1 25 4
1 25 4
1 25 4
2 38 2
2 38 2
3 12 3
3 12 3
3 12 3
3 12 3
4 33 6
5 64 8
5 64 8
(如果你想知道为什么会这样,那是因为还有其他列,每个列都有不同的值,还要注意每个唯一 ID 都有唯一的价格和唯一的数量)
所以我创建了聚合:
$id = new \Elastica\Aggregation\Terms('id');
$id->setField('id')->setSize(0);
$qte_price = new \Elastica\Aggregation\Sum('qte_price');
$qte_price->setScript('doc["price"].value * doc["qte"].value');
$id->addAggregation($qte_price);
这里的问题是 qte_price
在执行 setScript()
之前没有在 id
上使用第一个聚合,因此将 price * qte
的总和加起来所有 id 甚至是重复的。
换句话说,我想计算id=1 => 25*4
(而不是(25*4)*3
,id=2 => 38*2
(而不是(38*2)*2)
..等
我发现一个解决这个问题的技巧是将答案除以 doc_count,但我正在寻找使用 Elastica 进行此操作的官方方法。
我会对 price
和 qte
字段使用 avg
聚合,然后使用 bucket_script
pipeline aggregation 将平均价格乘以平均数量,然后会如你所愿。
3*25的平均值是25,3*4的平均值是4,然后25乘以4就得到id=1的答案……其他id也一样。
在纯 DSL 中,它看起来像这样:
{
"size": 0,
"aggs": {
"by_id": {
"terms": {
"field": "id"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
},
"avg_qte": {
"avg": {
"field": "qte"
}
},
"price_by_qte": {
"bucket_script": {
"buckets_path": {
"avgPrice": "avg_price",
"avgQte": "avg_qte"
},
"script": "params.avgPrice * params.avgQte"
}
}
}
}
}
}
用 Elastica 表示,会是这样:
$id = new \Elastica\Aggregation\Terms('id');
$id->setField('id')->setSize(0);
$avg_price = new \Elastica\Aggregation\Avg('avg_price');
$avg_price->setField('price');
$id->addAggregation($avg_price);
$avg_qte = new \Elastica\Aggregation\Avg('avg_qte');
$avg_qte->setField('qte');
$id->addAggregation($avg_qte);
$bucketScriptAggregation = new BucketScript(
'price_by_qte',
[
'avgPrice' => 'avg_price',
'avgQte' => 'avg_qte',
],
'params.avgPrice * params.avgQte'
);
$id->addAggregation($bucketScriptAggregation);
我在elasticsearch中有一个type product,其中包含一个包含多个id的列,其中一些是相同的。 还有包含当前价格和数量的列。我想要获得每个唯一 ID 的价格总和 * qte。
id price qte
__ _____ _________
1 25 4
1 25 4
1 25 4
2 38 2
2 38 2
3 12 3
3 12 3
3 12 3
3 12 3
4 33 6
5 64 8
5 64 8
(如果你想知道为什么会这样,那是因为还有其他列,每个列都有不同的值,还要注意每个唯一 ID 都有唯一的价格和唯一的数量)
所以我创建了聚合:
$id = new \Elastica\Aggregation\Terms('id');
$id->setField('id')->setSize(0);
$qte_price = new \Elastica\Aggregation\Sum('qte_price');
$qte_price->setScript('doc["price"].value * doc["qte"].value');
$id->addAggregation($qte_price);
这里的问题是 qte_price
在执行 setScript()
之前没有在 id
上使用第一个聚合,因此将 price * qte
的总和加起来所有 id 甚至是重复的。
换句话说,我想计算id=1 => 25*4
(而不是(25*4)*3
,id=2 => 38*2
(而不是(38*2)*2)
..等
我发现一个解决这个问题的技巧是将答案除以 doc_count,但我正在寻找使用 Elastica 进行此操作的官方方法。
我会对 price
和 qte
字段使用 avg
聚合,然后使用 bucket_script
pipeline aggregation 将平均价格乘以平均数量,然后会如你所愿。
3*25的平均值是25,3*4的平均值是4,然后25乘以4就得到id=1的答案……其他id也一样。
在纯 DSL 中,它看起来像这样:
{
"size": 0,
"aggs": {
"by_id": {
"terms": {
"field": "id"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
},
"avg_qte": {
"avg": {
"field": "qte"
}
},
"price_by_qte": {
"bucket_script": {
"buckets_path": {
"avgPrice": "avg_price",
"avgQte": "avg_qte"
},
"script": "params.avgPrice * params.avgQte"
}
}
}
}
}
}
用 Elastica 表示,会是这样:
$id = new \Elastica\Aggregation\Terms('id');
$id->setField('id')->setSize(0);
$avg_price = new \Elastica\Aggregation\Avg('avg_price');
$avg_price->setField('price');
$id->addAggregation($avg_price);
$avg_qte = new \Elastica\Aggregation\Avg('avg_qte');
$avg_qte->setField('qte');
$id->addAggregation($avg_qte);
$bucketScriptAggregation = new BucketScript(
'price_by_qte',
[
'avgPrice' => 'avg_price',
'avgQte' => 'avg_qte',
],
'params.avgPrice * params.avgQte'
);
$id->addAggregation($bucketScriptAggregation);