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)*3id=2 => 38*2(而不是(38*2)*2) ..等

我发现一个解决这个问题的技巧是将答案除以 doc_count,但我正在寻找使用 Elastica 进行此操作的官方方法。

我会对 priceqte 字段使用 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);