common_grams 过滤器

common_grams 过滤器是针对短语查询能更高效的使用停用词而设计的。它与 shingles 过滤器类似(参见 查找相关词(shingles), 为每个相邻词对生成,用示例解释更为容易。

common_grams 过滤器根据 query_mode 设置的不同而生成不同输出结果:false (为索引使用) 或 true (为搜索使用),所以我们必须创建两个独立的分析器:

  1. PUT /my_index
  2. {
  3. "settings": {
  4. "analysis": {
  5. "filter": {
  6. "index_filter": { (1)
  7. "type": "common_grams",
  8. "common_words": "_english_" (2)
  9. },
  10. "search_filter": { (1)
  11. "type": "common_grams",
  12. "common_words": "_english_", (2)
  13. "query_mode": true
  14. }
  15. },
  16. "analyzer": {
  17. "index_grams": { (3)
  18. "tokenizer": "standard",
  19. "filter": [ "lowercase", "index_filter" ]
  20. },
  21. "search_grams": { (3)
  22. "tokenizer": "standard",
  23. "filter": [ "lowercase", "search_filter" ]
  24. }
  25. }
  26. }
  27. }
  28. }

<1> 首先我们基于 common_grams 过滤器创建两个过滤器: index_filter 在索引时使用(此时 query_mode 的默认设置是 false ), search_filter 在查询时使用(此时 query_mode 的默认设置是 true )。

<2> common_words 参数可以接受与 stopwords 参数同样的选项(参见 指定停用词 specifying-stopwords )。这个过滤器还可以接受参数 common_words_path ,使用存于文件里的常用词。

<3> 然后我们使用过滤器各创建一个索引时分析器和查询时分析器。

有了自定义分析器,我们可以创建一个字段在索引时使用 index_grams 分析器:

  1. PUT /my_index/_mapping/my_type
  2. {
  3. "properties": {
  4. "text": {
  5. "type": "string",
  6. "analyzer": "index_grams", (1)
  7. "search_analyzer": "standard" (1)
  8. }
  9. }
  10. }

<1> text 字段索引时使用 index_grams 分析器,但是在搜索时默认使用 standard 分析器,稍后我们会解释其原因。

索引时(At Index Time)

如果我们对短语 The quick and brown fox 进行拆分,它生成如下词项:

  1. Pos 1: the_quick
  2. Pos 2: quick_and
  3. Pos 3: and_brown
  4. Pos 4: brown_fox

新的 index_grams 分析器生成以下词项:

  1. Pos 1: the, the_quick
  2. Pos 2: quick, quick_and
  3. Pos 3: and, and_brown
  4. Pos 4: brown
  5. Pos 5: fox

所有的词项都是以 unigrams 形式输出的(the、quick 等等),但是如果一个词本身是常用词或者跟随着常用词,那么它同时还会在 unigram 同样的位置以 bigram 形式输出:the_quickquick_andand_brown

单字查询(Unigram Queries)

因为索引包含 unigrams,可以使用与其他字段相同的技术进行查询,例如:

  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "match": {
  5. "text": {
  6. "query": "the quick and brown fox",
  7. "cutoff_frequency": 0.01
  8. }
  9. }
  10. }
  11. }

上面这个查询字符串是通过为文本字段配置的 search_analyzer 分析器 —本例中使用的是 standard 分析器— 进行分析的, 它生成的词项为: thequickandbrownfox

因为 text 字段的索引中包含与 standard 分析去生成的一样的 unigrams ,搜索对于任何普通字段都能正常工作。

二元语法短语查询(Bigram Phrase Queries)

但是,当我们进行短语查询时,我们可以用专门的 search_grams 分析器让整个过程变得更高效:

  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "match_phrase": {
  5. "text": {
  6. "query": "The quick and brown fox",
  7. "analyzer": "search_grams" (1)
  8. }
  9. }
  10. }
  11. }

<1> 对于短语查询,我们重写了默认的 search_analyzer 分析器,而使用 search_grams 分析器。

search_grams 分析器会生成以下词项:

  1. Pos 1: the_quick
  2. Pos 2: quick_and
  3. Pos 3: and_brown
  4. Pos 4: brown
  5. Pos 5: fox

分析器排除了所有常用词的 unigrams,只留下常用词的 bigrams 以及低频的 unigrams。如 the_quick 这样的 bigrams 比单个词项 the 更为少见,这样有两个好处:

  • the_quick 的位置信息要比 the 的小得多,所以它读取磁盘更快,对系统缓存的影响也更小。

  • 词项 the_quick 没有 the 那么常见,所以它可以大量减少需要计算的文档。

两词短语(Two-Word Phrases)

我们的优化可以更进一步,因为大多数的短语查询只由两个词组成,如果其中一个恰好又是常用词,例如:

  1. GET /my_index/_search
  2. {
  3. "query": {
  4. "match_phrase": {
  5. "text": {
  6. "query": "The quick",
  7. "analyzer": "search_grams"
  8. }
  9. }
  10. }
  11. }

那么 search_grams 分析器会输出单个语汇单元:the_quick 。这将原来昂贵的查询(查询 thequick )转换成了对单个词项的高效查找。