【问题标题】:Elasticsearch query speed up with repeated used terms query filter使用重复使用的术语查询过滤器加快 Elasticsearch 查询速度
【发布时间】:2019-09-10 05:45:15
【问题描述】:

我需要找出一个标签和另一组固定标签之间的共现时间。我有 10000 个不同的单个标签,并且在固定的标签集中有 10k 个标签。我在固定时间范围的一组固定标签上下文下遍历所有单个标签。我的索引中有 10 亿个文档,包含 20 个分片。

这里是elasticsearch查询,elasticsearch 6.6.0:

es.search(index=index, size=0, body={ 
        "query": {
          "bool": {
              "filter": [
                  {"range": {
                      "created_time": {
                       "gte": fixed_start_time,  
                       "lte": fixed_end_time, 
                       "format": "yyyy-MM-dd-HH"
                       }}},
                        {"term": {"tags": dynamic_single_tag}},
                        {"terms": {"tags": {
                            "index" : "fixed_set_tags_list",
                            "id" : 2,
                            "type" : "twitter",
                            "path" : "tag_list"
                        }}}
                       ]

                }
          }, "aggs": {
             "by_month": {
              "date_histogram": {
                  "field": "created_time",
                  "interval": "month",
                              "min_doc_count": 0,
                              "extended_bounds": {
                                  "min": two_month_start_time,
                                  "max": start_month_start_time}

              }}}
        }) 

我的问题:是否有任何解决方案可以在 elasticsearch 中为固定的 10k 组标签术语查询和时间范围过滤器提供缓存,从而加快查询时间?对于我上面的查询,一个标签需要 1.5 秒。

【问题讨论】:

  • 我想问你几个澄清问题。参数的可变性如何(fixed_start_timefixed_end_timetwo_month_start_timestart_month_start_time)?它们是否会随着每个请求(每天、每月)而变化?标签集(从中提取dynamic_single_tag)是否与fixed_set_tags_list 相同?您需要多久重复一次此类工作 - 意思是,您想要的性能是多少,计算整个 10K 标签可以花多少时间?
  • @Nikolay Vasiliev 我需要每月执行一次 30k 查询。因此,fixed_start_time、fixed_end_time、two_month_start_time、start_month_start_time 将按月更改。 dynamic_single_tag 不在 fixed_set_tags_list 中。在性能方面,我有 30k 个查询,一个查询需要 1.5s,完成它需要 12.5 小时。我希望它能在 30 分钟或 1 小时内完成。
  • 我知道我可以添加更多节点,同时,我想知道是否有任何查询优化,例如第一组fixed_set_tags_list的过滤器缓存,在10k dynamic_single_tag查询之后,然后删除缓存,然后为第二组 fixed_set_tags_list 建立另一个过滤器缓存,并继续进行不同的 dynamic_single_tag 查询,依此类推。

标签: performance elasticsearch filter query-cache


【解决方案1】:

您看到的是 Elasticsearch 聚合的正常行为(实际上,考虑到您有 10 亿个文档,性能相当不错)。

您可以考虑以下几个选项:使用一批 filter 聚合、使用文档子集重新索引、从 Elasticsearch 下载数据并离线计算共现。

但也许值得尝试发送这 10K 查询并查看 Elasticsearch 内置缓存是否启动。

让我更详细地解释每个选项。

使用filter 聚合

首先,让我们概述一下我们在原始 ES 查询中所做的事情:

  • 在特定时间窗口过滤带有create_time的文档;
  • 过滤包含所需标签dynamic_single_tag的文档;
  • 还过滤列表中至少有一个标签fixed_set_tags_list的文档;
  • 计算在特定时间段内每个月有多少此类文档。

性能是个问题,因为我们有 10K 的标签可以进行此类查询。

我们可以在这里做的是将filter 上的dynamic_single_tag 从查询移动到聚合:

POST myindex/_doc/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        { "terms": { ... } }
      ]
    }
  },
  "aggs": {
    "by tag C": {
      "filter": {
        "term": {
          "tags": "C" <== here's the filter
        }
      },
      "aggs": {
        "by month": {
          "date_histogram": {
            "field": "created_time",
            "interval": "month",
            "min_doc_count": 0,
            "extended_bounds": {
              "min": "2019-01-01",
              "max": "2019-02-01"
            }
          }
        }
      }
    }
  }
}

结果将如下所示:

  "aggregations" : {
    "by tag C" : {
      "doc_count" : 2,
      "by month" : {
        "buckets" : [
          {
            "key_as_string" : "2019-01-01T00:00:00.000Z",
            "key" : 1546300800000,
            "doc_count" : 2
          },
          {
            "key_as_string" : "2019-02-01T00:00:00.000Z",
            "key" : 1548979200000,
            "doc_count" : 0
          }
        ]
      }
    }

现在,如果您要问这对性能有何帮助,这里有诀窍:为每个标签添加更多这样的 filter 聚合:"by tag D""by tag E" 等。

改进将来自“批量”请求,combining many initial requests into one。将所有 10K 个标签放在一个查询中可能不切实际,但即使是每个查询的 100 个标签批次也可以改变游戏规则。

(旁注:通过terms 聚合和include 过滤参数可以实现大致相同的行为。)

这种方法当然需要动手并编写更复杂的查询,但如果需要在零准备的情况下随机运行此类查询,它会派上用场。

重新索引文档

第二种方法背后的想法是通过reindex API预先减少文档集。 reindex 查询可能如下所示:

POST _reindex
{
  "source": {
    "index": "myindex",
    "type": "_doc",
    "query": {
      "bool": {
        "filter": [
          {
            "range": {
              "created_time": {
                "gte": "fixed_start_time",
                "lte": "fixed_end_time",
                "format": "yyyy-MM-dd-HH"
              }
            }
          },
          {
            "terms": {
              "tags": {
                "index": "fixed_set_tags_list",
                "id": 2,
                "type": "twitter",
                "path": "tag_list"
              }
            }
          }
        ]
      }
    }
  },
  "dest": {
    "index": "myindex_reduced"
  }
}

此查询将创建一个新索引myindex_reduced,其中仅包含满足前两个过滤子句的元素。

此时,无需这两个子句即可完成原始查询。

这种情况下的加速将来自于限制文档数量,它越小,增益越大。所以,如果fixed_set_tags_list 给你留下了 10 亿的一小部分,那么你绝对可以试试这个选项。

在 Elasticsearch 之外下载数据和处理

说实话,这个用例看起来更像是 pandas 的工作。如果您需要数据分析,我建议您使用scroll API 提取磁盘上的数据,然后使用任意脚本对其进行处理。

在 python 中,它可以像使用 elasticsearch 库的 .scan() 辅助方法一样简单。

为什么不试试蛮力方法?

Elasticsearch 已经尝试通过 request cache 帮助您进行查询。它仅适用于纯聚合查询 (size: 0),因此应该适用于您的情况。

但不会,因为查询的内容总是不同的(整个JSON of the query is used as caching key,而且我们在每个查询中都有一个新标签)。不同级别的缓存将开始发挥作用。

Elasticsearch heavily relies on the filesystem cache,这意味着在后台,文件系统中访问频率更高的块将被缓存(实际上加载到 RAM 中)。对于最终用户而言,这意味着“热身”将缓慢进行,并且会出现大量类似的请求。

在您的情况下,聚合和过滤将发生在 2 个字段上:create_timetags。这意味着在使用不同的标签进行 10 或 100 个请求后,响应时间将从 1.5 秒下降到更可以忍受的时间。

为了证明我的观点,这是我对 Elasticsearch 性能的研究中的Vegeta 图,该图来自我在使用固定 RPS 发送大量聚合的同一查询下的 Elasticsearch 性能:

如您所见,最初请求大约需要 10 秒,而在 100 次请求之后,它减少到了惊人的 200 毫秒。

我肯定会建议尝试这种“蛮力”方法,因为如果它有效,它是好的,如果它不 - 它没有任何成本。

希望有帮助!

【讨论】:

  • 非常感谢您详细的 cmets !!!你提到的所有选项听起来都很鼓舞人心。我会尝试所有选项并让您知道结果。附言尤其是使用 pandas 来完成这项工作是一个很好的想法。
  • 我实现了过滤器聚合,并在一个查询中将 4841 个 dynamic_single_tags 放入过滤器聚合中。性能是之前的 89 分钟(循环 4841 dynamic_single_tags 导致 4841 个查询)VS 7 分钟(使用一个查询将 4841 个 dynamic_single_tags 放入过滤器 aggs)。我发现更多的系统 RAM 和减少堆大小会大大提高性能。我相信 filter aggs 是我要实施的解决方案。非常感谢。
  • 太好了,很高兴它有帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多