我有以下映射
{
"yellows" : {
"aliases" : { },
"mappings" : {
"yellow" : {
"properties" : {
"ranges" : {
"type" : "nested",
"properties" : {
"geometry" : {
"type" : "geo_shape"
},
"id" : {
"type" : "long"
},
"other1" : {
"type" : "keyword"
},
"other2" : {
"type" : "long"
},
"other3" : {
"type" : "long"
}
}
}
...
}
}
}
}
}
查询越慢越size
。例如
curl https://path/to/elastic/yellows/_search?_source_exclude=ranges&from=0&size=50' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
# size 50 -> "took":71
curl https://path/to/elastic/yellows/_search?_source_exclude=ranges&from=0&size=100' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
# size 100 -> "took":1421
与此同时,size=0
或_source=false
的查询速度很快。例如
curl https://path/to/elastic/yellows/_search?_source_exclude=ranges&from=0&size=0' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
# size 0 -> "took":32
curl https://path/to/elastic/yellows/_search?_source=false&from=0&size=100' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
# _source=false -> "took":167
这意味着检索_source
s(即没有_souce=false
或size=0
)的查询速度较慢。此外,似乎检索到的文档中的范围越多,响应越慢。我在下面使用wc -c
作为检索文档中有多少范围的代理度量。不是最好的措施,但应该足够
curl https://path/to/elastic/yellows/_search?from=0&size=50' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}' | wc -c
# 2.332.822
curl https://path/to/elastic/yellows/_search?from=50&size=50' --data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}' | wc -c
# 38.591.502
正如你所看到的,前50个的范围远远小于前100个中的第50个。另外,请注意,在第一个片段中,前50个的查询比第二个50的查询要快得多,即使它有_source_exclude=ranges
。
在我看来,查询不是瓶颈。实际上,使用size=0
或_source=false
时,响应时间很短。因此,我怀疑范围是一个嵌套字段,即使请求排除它们,Elastic也会考虑它们(即_source_exclude=ranges
)。
有没有其他方法可以在不更改映射的情况下加快查询速度,还是应该更改映射以使范围不嵌套?
答案 0 :(得分:1)
您是对的,查询不是瓶颈。您看到的是请求fetch phase的增长时间,而搜索保持不变并且很小。
Elasticsearch大致在两个阶段执行搜索请求:Query phase和Fetch phase。
在查询阶段,ES会确定哪些文档与查询匹配,并为此使用快速索引,这些索引很可能缓存在RAM中。
在获取阶段,它实际上是从磁盘中获取它们并发送回响应。 (由于匹配的文档可以位于群集的任何节点中,所以实际上是分布式的,因为获取的文档可以位于该群集的任何节点。)
现在让我们看看在您提到的每种情况下会发生什么。
size=0
时会发生什么?curl https://path/to/elastic/yellows/_search?_source_exclude=ranges&from=0&size=0' \
--data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
在这种情况下,您告诉Elasticsearch跳过获取阶段:它仅返回匹配的文档数。它也不做任何排序,因为它是不需要的。
_source=false
和size=100
时会发生什么?curl https://path/to/elastic/yellows/_search?_source=false&from=0&size=100' \
--data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}'
_source=false
告诉Elasticsearch不要从磁盘获取JSON。它仅返回文档ID,在这种情况下按所需顺序排序。排序也是performed mostly in memory:
排序时,将相关的排序字段值加载到内存中。 这意味着每个分片应该有足够的内存来包含 他们。
这就是为什么这个查询也很快的原因。
from=50&size=50
会发生什么?curl https://path/to/elastic/yellows/_search?from=50&size=50' \
--data-binary '{"query":{"bool":{"must":[],"filter":{"bool":{"filter":[{"terms":{"...":["1"]}},{"terms":{"...":["..."]}}],"should":[]}}}},"sort":[{"...":{"order":"asc"}}]}' | wc -c
在这里,我们要求Elasticsearch跳过前50条记录,再给出下50条记录。正如您所测量的,响应约为36MB,这是很大的。前50条记录仅需要传输2MB数据。
发生的事情是,Elasticsearch最终必须访问磁盘,并且还要通过网络发送大量数据(不仅是100KB的数据)。这就是为什么您的查询速度较慢的原因。 1.5秒的传输时间〜36MB使我们的传输速度达到24MB /秒(200 MBit /秒),例如,这是光纤连接的虚拟极限。
确实,查询嵌套字段的速度比普通字段慢,但是在这种情况下,这不太可能成为问题:从磁盘读取数据并通过网络发送数据。
在Tuning for search speed上有一些提示,特别是建议给文件系统缓存更多的内存。
您已经发现可以使用_source_exclude=ranges
从响应中排除某些数据。如果您仍然需要响应,但只关心该ranges
数组的子集,则可以使用inner_hits
这样做。默认情况下,它将返回前3个匹配的嵌套子文档。
总是很难给出性能优化建议,因为它很大程度上取决于数据结构,数量和用例。识别瓶颈很重要;在您的情况下,我将首先检查磁盘的读写功能和网络。
要确定查询本身的瓶颈,我建议看一下Profile API。
希望有帮助!