如何配置Elasticsearch以在单词的开头或结尾(但不是在中间)查找子字符串?

时间:2015-11-08 14:29:52

标签: elasticsearch

我开始学习Elasticsearch,现在我正在尝试编写我的第一个分析器配置。我想要实现的是,如果它们位于单词的开头或结尾,则会找到子字符串。如果我有“stackoverflow”这个词并且我搜索“stack”我想找到它,当我搜索“flow”时我想找到它,但是我想要找到它搜索“ackov”(在我的用例中这没有意义)。

我知道有“Edge n gram tokenizer”,但是一个分析器只能有一个标记器,边缘n-gram可以是正面或背面(但不能同时进行)。

如果我理解正确,将两个版本的“Edge ngram 过滤器”(正面和背面)应用到分析器,那么我也找不到,因为两个过滤器都需要返回true,不是吗?因为“堆栈”不在单词的结尾,所以后边缘n克过滤器将返回false并且不会找到单词“stackoverflow”。

那么,如何配置我的分析器在一个单词的结尾或开头找到子字符串,而不是在中间?

1 个答案:

答案 0 :(得分:2)

可以做的是定义两个分析器,一个用于在字符串的开头匹配,另一个用于在字符串的末尾匹配。在下面的索引设置中,我将前一个prefix_edge_ngram_analyzer命名为后者suffix_edge_ngram_analyzer。这两个分析器可以应用于text.prefix子字段的多字段字符串字段,分别应用于text.suffix字符串字段。

{
  "settings": {
    "analysis": {
      "analyzer": {
        "prefix_edge_ngram_analyzer": {
          "tokenizer": "prefix_edge_ngram_tokenizer",
          "filter": ["lowercase"]
        },
        "suffix_edge_ngram_analyzer": {
          "tokenizer": "keyword",
          "filter" : ["lowercase","reverse","suffix_edge_ngram_filter","reverse"]
        }
      },
      "tokenizer": {
        "prefix_edge_ngram_tokenizer": {
          "type": "edgeNGram",
          "min_gram": "2",
          "max_gram": "25"
        }
      },
      "filter": {
        "suffix_edge_ngram_filter": {
          "type": "edgeNGram",
          "min_gram": 2,
          "max_gram": 25
        }
      }
    }
  },
  "mappings": {
    "test_type": {
      "properties": {
        "text": {
          "type": "string",
          "fields": {
            "prefix": {
              "type": "string",
              "analyzer": "prefix_edge_ngram_analyzer"
            },
            "suffix": {
              "type": "string",
              "analyzer": "suffix_edge_ngram_analyzer"
            }
          }
        }
      }
    }
  }
}

然后我们假设我们索引以下测试文档:

PUT test_index/test_type/1
{ "text": "stackoverflow" }

然后我们可以使用以下查询通过前缀或后缀进行搜索:

# input is "stack" => 1 result
GET test_index/test_type/_search?q=text.prefix:stack OR text.suffix:stack

# input is "flow" => 1 result
GET test_index/test_type/_search?q=text.prefix:flow OR text.suffix:flow

# input is "ackov" => 0 result
GET test_index/test_type/_search?q=text.prefix:ackov OR text.suffix:ackov

使用查询DSL查询的另一种方法:

POST test_index/test_type/_search
{
   "query": {
      "multi_match": {
         "query": "stack",
         "fields": [ "text.*" ]
      }
   }
}

<强>更新

如果您已有字符串字段,则可以将其“升级”为多字段,并使用其分析器创建两个必需的子字段。这样做的方法是按顺序执行此操作:

  1. 关闭索引以创建分析器

    POST test_index/_close
    
  2. 更新索引设置

    PUT test_index/_settings
    {
    "analysis": {
      "analyzer": {
        "prefix_edge_ngram_analyzer": {
          "tokenizer": "prefix_edge_ngram_tokenizer",
          "filter": ["lowercase"]
        },
        "suffix_edge_ngram_analyzer": {
          "tokenizer": "keyword",
          "filter" : ["lowercase","reverse","suffix_edge_ngram_filter","reverse"]
        }
      },
      "tokenizer": {
        "prefix_edge_ngram_tokenizer": {
          "type": "edgeNGram",
          "min_gram": "2",
          "max_gram": "25"
        }
      },
      "filter": {
        "suffix_edge_ngram_filter": {
          "type": "edgeNGram",
          "min_gram": 2,
          "max_gram": 25
        }
      }
    }
    }
    
  3. 重新打开索引

    POST test_index/_open
    
  4. 最后,更新文本字段的映射

    PUT test_index/_mapping/test_type
    {
      "properties": {
        "text": {
          "type": "string",
          "fields": {
            "prefix": {
              "type": "string",
              "analyzer": "prefix_edge_ngram_analyzer"
            },
            "suffix": {
              "type": "string",
              "analyzer": "suffix_edge_ngram_analyzer"
            }
          }
        }
      }
    }
    
  5. 您仍然需要重新索引所有文档,以便填充和分析新的子字段text.prefixtext.suffix