我将需要找出一个标签和另一组固定标签之间的共现时间。我有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秒的时间。
答案 0 :(得分: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
,其中仅包含满足前2个过滤子句的元素。
这时,原始查询可以不用这两个子句来完成。
在这种情况下,提高速度将来自限制文档的数量,数量越小,收益就越大。因此,如果fixed_set_tags_list
仅剩10亿美元,那么您绝对可以尝试一下。
说实话,这个用例更像是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中)。对于最终用户而言,这意味着“热身”将缓慢进行,并且会有大量类似的请求。
对于您来说,聚合和过滤将在两个字段上进行:create_time
和tags
。这意味着在执行了10或100个带有不同标签的请求后,响应时间将从1.5秒减少到更可忍受的时间。
为证明我的观点,这是我对Elasticsearch性能的研究中的Vegeta图,该查询在具有固定RPS发送的大量聚合的同一查询下:
如您所见,最初的请求耗时约10秒钟,而在100个请求后,耗时减少为200ms。
我绝对建议尝试这种“强力”方法,因为如果有效,那么就很好,如果不行,那就没什么用。
希望有帮助!