Elasticsearch:自定义分析器中同义词图和停止过滤器之间的意外交互

问题描述

说明

我正在尝试使用包括停用词在内的多词同义词进行查询。 先举个例子来解释一下。

我已将以下文档放入索引中。

  • foo
  • foo 吧
  • 酒吧的foo
  • 脸书

查询 {"query":{"match":{"test":{"query":"foo of bar"}}}} 的预期结果是返回文档:

  • foo 吧
  • 酒吧的foo
  • 脸书

配置

在这个例子中,我有 2 个过滤器:

  • stop:将移除
  • 标记
  • synonym_graph:处理同义词fb,foo bar,foo of bar

映射

{
  "properties": {
    "test": {
      "type": "text","analyzer": "test_index_analyzer","search_analyzer": "test_search_analyzer"
    }
}

设置

{
    "settings" : {
        "index": {
            "number_of_shards": 1,"number_of_replicas": 0,"analysis": {
                "analyzer": {
                    "test_index_analyzer": {
                        "type": "custom","tokenizer": "whitespace","filter": [
                            "english_stop"
                        ]
                    },"test_search_analyzer": {
                        "type": "custom","filter": [
                            "english_stop","english_syn"
                        ]
                    }
                },"filter": { 
                    "english_stop": {
                        "type": "stop","stopwords": "_english_","ignore_case": true,"remove_trailing": false
                    },"english_syn": {
                        "type": "synonym_graph","synonyms": [
                            "fb,foo of bar","fb,foo bar"
                        ]
                    }
                }
            }
        }
    }
}

结果

token 格式:"token,start_offset-end_offset,type/position/positionLength"

查询 搜索结果 索引分析 搜索分析
fb fb fb,0-2,word,1 foo,SYNONYM / 0 / 1
foo,SYNONYM / 0 / 3
fb,word / 0 / 4
bar,SYNONYM / 2 / 2
bar,SYNONYM / 3 / 1
栏的foo fb foo,0-3,1
bar,7-10,2,1
fb,0-10,SYNONYM / 0 / 3
foo,word / 0 / 1
bar,word / 2 / 1
foo bar fb,foo bar foo,4-7,1,0-7,SYNONYM / 0 / 2
foo,word / 1 / 1

所有搜索都希望返回 3 行:

  • 脸书
  • foo 吧
  • 酒吧的foo

注意:bar 的 foo 永远不会返回

我的猜测是 foo of bar 被停止过滤器索引到位置 [foo,bar] 并且同义词正在寻找 [foo,bar]。

你对我的目标有什么建议吗?

解决方法

当您使用停用词过滤器时,单词的位置将被保留,因此如果您检查 bar of foo 的分析器结果,您将得到以下结果:

{
  "tokens" : [
    {
      "token" : "foo","start_offset" : 0,"end_offset" : 3,"type" : "word","position" : 0
    },{
      "token" : "bar","start_offset" : 7,"end_offset" : 10,"position" : 2
    }
  ]
}

如您所见,您在零位置获得了 'foo' 标记,在 2 位置获得了 'bar',因此同义词过滤器找不到此文档。

要解决您的问题,您应该先应用同义词过滤器,然后删除如下停用词。

"test_search_analyzer": {
    "type": "custom","tokenizer": "whitespace","filter": [
      "english_syn","english_stop"
    ]
  }

并且您应该将“foo bar,foo of bar”添加到同义词列表中。

我认为保留停用词是必要的,因为它可以帮助获得更精确的搜索结果(尤其是 ES 使用的 BM25 相似度。),您可以查看有关它的弹性搜索官方文章here