性能优化

短语查询和邻近查询都比简单的 query 查询代价更高。 一个 match 查询仅仅是看词条是否存在于倒排索引中,而一个 match_phrase 查询是必须计算并比较多个可能重复词项的位置。

Lucene nightly benchmarks 表明一个简单的 term 查询比一个短语查询大约快 10 倍,比邻近查询(有 slop 的短语查询)大约快 20 倍。当然,这个代价指的是在搜索时而不是索引时。

Tip 通常,短语查询的额外成本并不像这些数字所暗示的那么吓人。事实上,性能上的差距只是证明一个简单的 term 查询有多快。标准全文数据的短语查询通常在几毫秒内完成,因此实际上都是完全可用,即使是在一个繁忙的集群上。

在某些特定病理案例下,短语查询可能成本太高了,但比较少见。一个典型例子就是DNA序列,在序列里很多同样的词项在很多位置重复出现。在这里使用高 slop 值会到导致位置计算大量增加。

那么我们应该如何限制短语查询和邻近近查询的性能消耗呢?一种有用的方法是减少需要通过短语查询检查的文档总数。

结果集重新评分

先前的章节中 ,我们讨论了而使用邻近查询来调整相关度,而不是使用它将文档从结果列表中添加或者排除。一个查询可能会匹配成千上万的结果,但我们的用户很可能只对结果的前几页感兴趣。

一个简单的 match 查询已经通过排序把包含所有含有搜索词条的文档放在结果列表的前面了。事实上,我们只想对这些 顶部文档 重新排序,来给同时匹配了短语查询的文档一个额外的相关度升级。

search API 通过 重新评分 明确支持该功能。(((“rescoring”)))重新评分阶段支持一个代价更高的评分算法—比如 phrase 查询—只是为了从每个分片中获得前 K 个结果。 然后会根据它们的最新评分 重新排序。

该请求如下所示:

  1. GET /my_index/my_type/_search
  2. {
  3. "query": {
  4. "match": { <1>
  5. "title": {
  6. "query": "quick brown fox",
  7. "minimum_should_match": "30%"
  8. }
  9. }
  10. },
  11. "rescore": {
  12. "window_size": 50, <2>
  13. "query": { <3>
  14. "rescore_query": {
  15. "match_phrase": {
  16. "title": {
  17. "query": "quick brown fox",
  18. "slop": 50
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }

<1> match 查询决定哪些文档将包含在最终结果集中,并通过 TF/IDF 排序。(((“window_size parameter”)))

<2> window_size 是每一分片进行重新评分的顶部文档数量。

<3> 目前唯一支持的重新打分算法就是另一个查询,但是以后会有计划增加更多的算法。