代码之家  ›  专栏  ›  技术社区  ›  Alexandre Elshobokshy

Elastica未在setScript之前对聚合进行分组

  •  0
  • Alexandre Elshobokshy  · 技术社区  · 6 年前

    我在elasticsearch中有一个type产品,它包含一个包含多个id的列,其中一些id是相同的。 还有包含当前价格和数量的列。我想得到每个唯一id的price*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 不在 id 在执行 setScript() ,从而将 price * qte 在所有的身份证上,即使是重复的。

    换句话说,我想计算 id=1 => 25*4 (而不是 (25*4)*3 ,用于 id=2 => 38*2 (而不是 (38*2)*2) .. 等

    我发现解决这个问题的一个诀窍是把答案除以医生的数量,但我正在寻找一种使用Elastica的官方方法。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Val    6 年前

    我会用 avg 两者的聚合 price qte 字段,然后使用 bucket_script pipeline aggregation 把平均价格乘以平均数量,就能达到你的预期。

    3*25的平均值是25,3*4的平均值是4,然后你可以用25乘以4,得到id=1的答案。。。其他身份证也一样。

    在纯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);