【问题标题】:Filter on TOP aggregation - elasticsearch 5.6过滤 TOP 聚合 - elasticsearch 5.6
【发布时间】:2019-06-19 21:09:20
【问题描述】:

注意:这种查询在2或3年前已经被问过,但没有任何满意的答案。我在这里发布我的具体问题。希望有人提出一些好的解决方案。

我面临从 elasticsearch 获取所需记录的挑战。我们严格需要对 TOP 聚合返回的结果进行过滤。无论如何,下面是我的场景:

鉴于:我们有一个名为“服务”的实体,其属性如下:

{
    "id": "servicer-id-1",
    "status": "OPEN",         // These may be CLOSED, RESOLVED
    "timeRaised": "2019-03-21T15:09:17.015Z",
    "timeChanged": "2019-03-21T15:09:17.015Z"
}

我有一个弹性索引,其中上述服务的任何更改都存储为整个服务文档(一种服务历史)。具有相同 ID 的服务不止一项。我们每次都更新 timeChanges 属性。

索引中有数百万个服务文档。

问题陈述:我们需要特定的服务,这些服务是在给定时间范围内的最新状态(timeChanged)和状态为 OPEN。

我做了什么: 我使用以下查询和 10000 bacth 大小的滚动 API 来解决我们的问题:

{
  "size" : 1000,   //given by user
  "query" : {
    "constant_score" : {
      "filter" : {
        "bool" : {
          "must" : [
            {
              "range" : {
                "timeChanged" : {
                  "from" : 1552940830000,
                  "to" : 1553498830000,
                  "include_lower" : true,
                  "include_upper" : true,
                  "boost" : 1.0
                }
              }
            }
          ],
          "disable_coord" : false,
          "adjust_pure_negative" : true,
          "boost" : 1.0
        }
      },
      "boost" : 1.0
    }
  },
  "post_filter": {
    "bool": {
        "must": [{
            {
                "constant_score": {
                    "filter": {
                        "terms": {
                            "status": ["OPEN"],
                            "boost": 1.0
                        }
                    },
                    "boost": 1.0
                }
            }
        }],
      "disable_coord" : false,
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  },
  "_source" : false,
  "aggregations" : {
    "by_serviceId" : {
      "terms" : {
        "field" : "id",
        "size" : 50000,        // we set it with total number of services exist
        "min_doc_count" : 1,
        "shard_min_doc_count" : 0,
        "show_term_doc_count_error" : false,
        "order" : [
          {
            "_count" : "desc"
          },
          {
            "_term" : "asc"
          }
        ]
      },
      "aggregations" : {
        "top" : {
          "top_hits" : {
            "from" : 0,
            "size" : 1,
            "version" : false,
            "explain" : false,
            "sort" : [
              {
                "timeChanged" : {
                  "order" : "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

从上面的查询中,我们从滚动的第一次命中获得聚合,这是聚合中最新服务状态的列表。通过 Post 过滤器,我们以 10000 个批次获取 OPEN 服务,并尝试将 ids(通过 java 代码)与聚合列表进行匹配以找出我们的候选者。

返回所需的输出花费了太多时间。索引中的 440 万条记录大约需要 8 分钟。

如果您建议一种对返回的聚合数据进行过滤的方法,则可以解决此问题。但是找了这么多地方,发现在elastic中是不支持的。是这样吗? 相同问题的参考:

Elasticsearch: filter top hits aggregation

Elasticsearch exclude top hit on field value

请帮助并提出更好的方法来完成这个场景。

谢谢。

免责声明:请不要建议应用查询然后聚合,因为它不能解决问题。例如如果我先过滤 OPEN 状态然后进行汇总,那么对于给定日期,我总是会获得 OPEN 服务,但实际上对于给定日期,服务可能已解决。

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    这是我满足您需求的尝试。我有一个概念聚合证明,它不能处理字符串状态。所以我们首先需要将字符串状态转换为数字(也许update by query 可以为您完成这项工作)

    在我的例子中

    OPEN => status_number = 1 
    CLOSED => status_number = 2 
    RESOLVED => status_number = 3 
    

    这是我的 50 美分要求:D

    POST <index>/doc/_search
    {
      "size": 0,
      "query": {
        "bool": {
          "filter": {
            "range": {
              "timeChanged": {
                "gte": "2019-03-21T15:09:17.015Z",
                "lte": "2019-03-21T15:09:18.015Z"
              }
            }
          }
        }
      },
      "aggs": {
        "service": {
          "terms": {
            "field": "id.keyword",
            "size": 10
          },
          "aggs": {
            "last_status": {
              "terms": {
                "field": "status_number",
                "size": 1,
                "order": {
                  "last_change": "desc" // order to keep the last status of the timespan with the size of 1
                }
              },
              "aggs": {
                "last_change": {
                  "max": {
                    "field": "timeChanged"
                  }
                }
              }
            },
            "min_status": {
              "min_bucket": {
                "buckets_path": "last_status._key" // used to transforms a bucket list in a single value for the bucket_selector beneath
              }
            },
            "filtered": {
              "bucket_selector": {
                "buckets_path": {
                  "key": ">min_status"
                },
                "script": """
                  params.key == 1 // filter buckets where last status_number is 1 si status = OPEN
                """
              }
            }
          }
        }
      }
    }
    

    输出很详细:

    {
      "took": 2,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
      },
      "hits": {
        "total": 6,
        "max_score": 0,
        "hits": []
      },
      "aggregations": {
        "service": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "servicer-id-4",
              "doc_count": 1,
              "last_status": {
                "doc_count_error_upper_bound": 0,
                "sum_other_doc_count": 0,
                "buckets": [
                  {
                    "key": 1,
                    "doc_count": 1,
                    "last_change": {
                      "value": 1553180958015,
                      "value_as_string": "2019-03-21T15:09:18.015Z"
                    }
                  }
                ]
              },
              "min_status": {
                "value": 1,
                "keys": [
                  "1"
                ]
              }
            }
          ]
        }
      }
    }
    

    但您只需要 aggregations.service.buckets.key

    我希望它可以帮助你,但当然没有数据我无法评估这个查询的性能。

    【讨论】:

    • 感谢您的关注和努力。我分析并考虑尝试您的建议,但我无法通过查询更新满足整数约束,并且除了用户使用的状态之外还有其他字段也是字符串类型(为了直接提出问题,我没有提及)。对了,你还有其他想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-17
    • 2014-02-02
    • 2018-01-30
    • 2014-12-31
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    相关资源
    最近更新 更多