停用词与性能

保留停用词最大的缺点就影响搜索性能。使用 Elasticsearch 进行全文搜索,它需要为所有匹配的文档计算相关度评分 _score 从而返回最相关的前 10 个文档。

通常大多数的单词在所有文档中出现的频率低于0.1%,但是有少数词(例如 the )几乎存在于所有的文档中。假设有一个索引含有100万个文档,查询 quick brown fox 词组,能够匹配上的可能少于1000个文档。但是如果查询 the quick brown fox 词组,几乎需要对索引中的100万个文档进行评分和排序,只是为了返回前 10 名最相关的文档。

问题的关键是 the quick brown fox 词组实际是查询 thequickbrownfox— 任何文档即使它什么内容都没有而只包含 the 这个词也会被包括在结果集中。因此,我们需要找到一种降低待评分文档数量的方法。

and 操作符 (and Operator)

我们想要减少待评分文档的数量,最简单的方式就是在<> match 查询时使用 and 操作符,这样可以让所有词都是必须的。

以下是 match 查询:

  1. {
  2. "match": {
  3. "text": {
  4. "query": "the quick brown fox",
  5. "operator": "and"
  6. }
  7. }
  8. }

上述查询被重写为 bool 查询如下:

  1. {
  2. "bool": {
  3. "must": [
  4. { "term": { "text": "the" }},
  5. { "term": { "text": "quick" }},
  6. { "term": { "text": "brown" }},
  7. { "term": { "text": "fox" }}
  8. ]
  9. }
  10. }

bool 查询会智能的根据较优的顺序依次执行每个 term 查询:它会从最低频的词开始。因为所有词项都必须匹配,只要包含低频词的文档才有可能匹配。使用 and 操作符可以大大提升多词查询的速度。

最少匹配数(minimum_should_match)

在精度匹配match-precision的章节里面,我们讨论过使用 minimum_should_match 配置去掉结果中次相关的长尾。虽然它只对这个目的奏效,但是也为我们从侧面带来一个好处,它提供 and 操作符相似的性能。

  1. {
  2. "match": {
  3. "text": {
  4. "query": "the quick brown fox",
  5. "minimum_should_match": "75%"
  6. }
  7. }
  8. }

在上面这个示例中,四分之三的词都必须匹配,这意味着我们只需考虑那些包含最低频或次低频词的文档。 相比默认使用 or 操作符的简单查询,这为我们带来了巨大的性能提升。不过我们有办法可以做得更好……