【问题标题】:Elasticsearch multiple aggregation or terms and aggregation on a same columnElasticsearch 多个聚合或术语和同一列上的聚合
【发布时间】:2022-01-19 07:17:53
【问题描述】:

我想在 Elasticsearch 中实现 SQL 的功能。考虑下表:

我想要实现的是聚合列的不同值,SQL 等效:

select product,min(distinct price) from test group by product;

Expected output:

聚合可以是任何标准聚合,例如minmaxsumavgcount 等。

我已经尝试过使用无痛脚本,我可以通过无痛脚本实现所需的输出,但是以编程方式生成无痛脚本非常困难。

我正在寻找可以以编程方式生成的 EQL 查询或可以以编程方式生成无痛脚本的一些 java 插件。

Edit:

我试过的无痛脚本:

{
  "aggs": {
    "terms": {
      "scripted_metric": {
        "init_script": "state.rawMap = [:];",
        "map_script": "def product = doc['product'].value;state.rawMap.putIfAbsent(product, new ArrayList());def price = doc['price'].value;if(!state.rawMap.get(product).contains(price)){state.rawMap.get(product).add(price);}",
        "combine_script": "List outputList=new ArrayList();for (entry in state.rawMap.entrySet()) {def map=[:]; def min=entry.getValue().get(0); for(price in entry.getValue()){if(price<min){min=price;}}map.product=(entry.getKey()); map.min_price=min;outputList.add(map);}return outputList;"
      }
    }
  }
}

【问题讨论】:

  • 你能展示你到目前为止尝试过的查询吗...我看不出这与简单的术语聚合+最小子聚合有什么不同...好奇...
  • 我使用了无痛脚本。我无法使用 EQL 实现这一点。
  • 请显示查询,否则我们在黑暗中拍摄
  • @Val 我已经添加了我尝试过的无痛脚本。

标签: java elasticsearch


【解决方案1】:

无需无痛脚本!您想要的可以通过以下聚合查询来实现:

{
  "size": 0,
  "aggs": {
    "products": {
      "terms": {
        "field": "product"
      },
      "aggs": {
        "distinct_price": {
          "terms": {
            "field": "price"
          },
          "aggs": {
            "price_stats": {
              "stats": {
                "field": "price"
              }
            }
          }
        }
      }
    }
  }
}

【讨论】:

  • 感谢您的回答,如何找到价格的计数而不是最小值?
  • 您可以使用stats 聚合,然后您就拥有了一切:最小值、最大值、计数等
  • 上面的 EQL 不负责找出每个产品的不同价格。它考虑了所有的值。
  • 它返回的结果与您的第二个屏幕截图完全相同
  • distinct 在这种情况下毫无意义:min(distinct price) 产生与 min(price) 相同的结果
【解决方案2】:

以下查询将为您提供预期的结果:

POST test/_search
{
  "size": 0,
  "aggs": {
    "Fruites": {
      "terms": {
        "field": "product.keyword",
        "size": 10
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "price"
          }
        }
      }
    }
  }
}

样本结果:

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "Fruites" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "apple",
          "doc_count" : 2,
          "min_price" : {
            "value" : 120.0
          }
        },
        {
          "key" : "pears",
          "doc_count" : 2,
          "min_price" : {
            "value" : 150.0
          }
        },
        {
          "key" : "banana",
          "doc_count" : 1,
          "min_price" : {
            "value" : 70.0
          }
        }
      ]
    }
  }
}

您可以像下面这样创建索引映射:

PUT test
{
  "mappings": {
    "properties": {
      "price": {
        "type": "integer"
      },
      "product": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

示例数据索引如下:

POST _bulk
{"index":{"_index":"test","_id":"1"}}
{"product":"apple","price":"120"}
{"index":{"_index":"test","_id":"2"}}
{"product":"banana","price":"70"}
{"index":{"_index":"test","_id":"3"}}
{"product":"pears","price":"150"}
{"index":{"_index":"test","_id":"4"}}
{"product":"apple","price":"220"}
{"index":{"_index":"test","_id":"5"}}
{"product":"apple","price":"120"}
{"index":{"_index":"test","_id":"5"}}
{"product":"pears","price":"180"}

【讨论】:

  • 上面的 EQL 不负责找出每个产品的不同价格。它考虑了所有的值。
猜你喜欢
  • 2014-07-09
  • 2021-06-06
  • 2019-12-06
  • 2021-06-06
  • 2018-10-18
  • 2015-11-06
  • 2015-01-21
  • 2020-09-20
  • 1970-01-01
相关资源
最近更新 更多