英文版地址: https://www.elastic.co/guide/en/elasticsearch/guide/current/stopwords-phrases.html
本书基于 Elasticsearch 2.x 版本,有些内容可能已经过时。
停用词与短语查询(Phrase Queries)edit
所有查询中, 短语查询(见短语匹配) 大约占到5%,但是在慢查询里面它们又占大部分。
短语查询性能相对较差,特别是当短语中包括常用词的时候,如 “To be, or not to be”
短语全部由停用词组成,这是一种极端情况。原因在于几乎需要匹配全量的数据。
在 停用词的两面-停用词的优缺点,中,我们提到移除停用词只能节省倒排索引中的一小部分空间。这句话只部分正确,一个典型的索引可能包含部分或所有以下数据:
- 词项字典(Terms dictionary)
- 索引中所有文档内所有词项的有序列表,以及包含该词的文档数量。
- 倒排表(Postings list)
- 包含每个词项的文档(ID)列表。
- 词频(Term frequency)
- 每个词项在每个文档里出现的频率。
- 位置(Positions)
- 每个词项在每个文档里出现的位置,供短语查询或近似查询使用。
- 偏移(Offsets)
- 每个词项在每个文档里开始与结束字符的偏移,供词语高亮使用,默认是禁用的。
- 归一化因子(Norms)
- 用来对字段长度进行规范化处理的因子,给较短字段予以更多权重。
将停用词从索引中移除会节省 词项字典 和 倒排表 里的少量空间,但 位置 和 偏移 是另一码事。位置和偏移数据很容易变成索引大小的两倍、三倍、甚至四倍。
位置信息edit
analyzed
字符串字段的位置信息默认是开启的, 所以短语查询能随时使用到它。
词项出现的越频繁,用来存储它位置信息的空间就越多。在一个大的文档集合中,对于那些非常常见的词,它们的位置信息可能占用成百上千兆的空间。
运行一个针对高频词 the
的短语查询可能会导致从磁盘读取好几G的数据。这些数据会被存储到内核文件系统的缓存中,以提高后续访问的速度,这看似是件好事,但这可能会导致其他数据从缓存中被剔除,进一步使后续查询变慢。
这显然是我们需要解决的问题。
索引选项edit
我们首先应该问自己:是否真的需要使用短语查询或 近似查询?
答案通常是:不需要。在很多应用场景下,比如说日志,我们需要知道一个词 是否 在文档中(这个信息由倒排表提供)而不是关心词的位置在哪里。或许我们要对一两个字段使用短语查询,但是我们完全可以在其他 analyzed
字符串字段上禁用位置信息。
index_options
参数 允许我们控制索引里为每个字段存储的信息。 可选值如下:
-
docs
-
只存储文档及其包含词项的信息。这对
not_analyzed
字符串字段是默认的。 -
freqs
-
存储
docs
信息,以及每个词在每个文档里出现的频次。词频是完成TF/IDF 相关度计算的必要条件,但如果只想知道一个文档是否包含某个特定词项,则无需使用它。 -
positions
-
存储
docs
、freqs
、analyzed
,以及每个词项在每个文档里出现的位置。 这对analyzed
字符串字段是默认的,但当不需使用短语或近似匹配时,可以将其禁用。 -
offsets
-
存储
docs
,freqs
,positions
, 以及每个词在原始字符串中开始与结束字符的偏移信息(postings
highlighter )。这个信息被用以高亮搜索结果,但它默认是禁用的。
我们可以在索引创建的时候为字段设置 index_options
选项,或者在使用 put-mapping
API新增字段映射的时候设置。我们无法修改已有字段的这个设置:
停用词edit
删除停用词是能显著降低位置信息所占空间的一种方式。 一个被删除停用词的索引仍然可以使用短语查询,因为剩下的词的原始位置仍然被保存着,这正如 保持词元在原内容中的位置(Maintaining Positions) 中看到的那样。 尽管如此,将词项从索引中排除终究会降低搜索能力,这使我们难以区分 Man in the moon
与 Man on the moon
这两个短语。
幸运的是,鱼与熊掌是可以兼得的:请查看 common_grams
过滤器。