【问题标题】:Elasticsearch phrase suggester is suggesting me suggestions that do not exists in my indexElasticsearch 短语建议器向我建议在我的索引中不存在的建议
【发布时间】:2016-04-21 13:30:49
【问题描述】:

我有一个 Elasticsearch 索引,其中有一些数据。我实现了 did-you-mean 功能,因此当用户写错拼写的内容时,它可以收到带有正确单词的建议。

我使用短语建议器是因为我需要对短语的建议,例如名称,问题是索引中不存在某些建议。

例子:

document in the index: coding like a master
search: Codning like a boss
suggestion: <em>coding</em> like a boss
search result: not found

我的问题是,我的索引中没有与指定建议匹配的短语,因此它向我推荐了不存在的短语,因此会给我一个未找到的搜索。

我能用这个做什么?短语建议器不应该为索引中实际存在的短语提供建议吗?

这里我会留下相应的查询、映射和设置,以备不时之需。

设置和映射

{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "search.slowlog.threshold.fetch.warn": "2s",
      "index.analysis.analyzer.default.filter.0": "standard",
      "index.analysis.analyzer.default.tokenizer": "standard",
      "index.analysis.analyzer.default.filter.1": "lowercase",
      "index.analysis.analyzer.default.filter.2": "asciifolding",
      "index.priority": 3,
      "analysis": {
        "analyzer": {
          "suggests_analyzer": {
            "tokenizer": "lowercase",
            "filter": [
              "lowercase",
              "asciifolding",
              "shingle_filter"
            ],
            "type": "custom"
          }
        },
        "filter": {
          "shingle_filter": {
            "min_shingle_size": 2,
            "max_shingle_size": 3,
            "type": "shingle"
          }
        }
      }
    }
  },
  "mappings": {
    "my_type": {
      "properties": {
        "suggest_field": {
          "analyzer": "suggests_analyzer",
          "type": "string"
        }
      }
    }
  }
}

查询

{
  "DidYouMean": {
    "text": "Codning like a boss",
    "phrase": {
      "field": "suggest_field",
      "size": 1,
      "gram_size": 1,
      "confidence": 2.0
    }
  }
}

感谢您的帮助。

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    这实际上是意料之中的。如果您使用analyze api 分析您的文档,您将更好地了解正在发生的事情。

    GET suggest_index/_analyze?text=coding like a master&analyzer=suggests_analyzer
    

    这是输出

    {
       "tokens": [
          {
             "token": "coding",
             "start_offset": 0,
             "end_offset": 6,
             "type": "word",
             "position": 1
          },
          {
             "token": "coding like",
             "start_offset": 0,
             "end_offset": 11,
             "type": "shingle",
             "position": 1
          },
          {
             "token": "coding like a",
             "start_offset": 0,
             "end_offset": 13,
             "type": "shingle",
             "position": 1
          },
          {
             "token": "like",
             "start_offset": 7,
             "end_offset": 11,
             "type": "word",
             "position": 2
          },
          {
             "token": "like a",
             "start_offset": 7,
             "end_offset": 13,
             "type": "shingle",
             "position": 2
          },
          {
             "token": "like a master",
             "start_offset": 7,
             "end_offset": 20,
             "type": "shingle",
             "position": 2
          },
          {
             "token": "a",
             "start_offset": 12,
             "end_offset": 13,
             "type": "word",
             "position": 3
          },
          {
             "token": "a master",
             "start_offset": 12,
             "end_offset": 20,
             "type": "shingle",
             "position": 3
          },
          {
             "token": "master",
             "start_offset": 14,
             "end_offset": 20,
             "type": "word",
             "position": 4
          }
       ]
    }
    

    如您所见,为文本生成了一个标记“编码”,因此它在您的索引中。它向您建议不在索引中的内容。如果您严格想要词组搜索,那么您可能需要考虑使用keyword tokenizer。例如,如果您将映射更改为

    {
      "settings": {
        "index": {
          "analysis": {
            "analyzer": {
              "suggests_analyzer": {
                "tokenizer": "lowercase",
                "filter": [
                  "lowercase",
                  "asciifolding",
                  "shingle_filter"
                ],
                "type": "custom"
              },
              "raw_analyzer": {
                "tokenizer": "keyword",
                "filter": [
                  "lowercase",
                  "asciifolding"
                ]
              }
            },
            "filter": {
              "shingle_filter": {
                "min_shingle_size": 2,
                "max_shingle_size": 3,
                "type": "shingle"
              }
            }
          }
        }
      },
      "mappings": {
        "my_type": {
          "properties": {
            "suggest_field": {
              "analyzer": "suggests_analyzer",
              "type": "string",
              "fields": {
                "raw": {
                  "analyzer": "raw_analyzer",
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
    

    那么这个查询会给你预期的结果

    {
      "DidYouMean": {
        "text": "codning lke a master",
        "phrase": {
          "field": "suggest_field.raw",
          "size": 1,
          "gram_size": 1
        }
      }
    }
    

    对于“像老板一样编码”,它不会显示任何内容。

    编辑 1

    2) 从您的 cmets 以及在我自己的数据集上运行一些短语建议,我觉得更好的方法是使用 collate 选项 phrase suggester 提供,以便我们可以根据 query 检查每个建议并仅在要从索引中取回任何文档时才返回建议。我还在映射中添加了stemmers 以仅考虑根词。我正在使用light_english,因为它不那么激进。 More 对此。

    映射的分析器部分现在看起来像这样

     "analysis": {
         "analyzer": {
             "suggests_analyzer": {
                 "tokenizer": "standard",
                 "filter": [
                     "lowercase",
                     "english_possessive_stemmer",
                     "light_english_stemmer",
                     "asciifolding",
                     "shingle_filter"
                 ],
                 "type": "custom"
             }
         },
         "filter": {
             "light_english_stemmer": {
                 "type": "stemmer",
                 "language": "light_english"
             },
             "english_possessive_stemmer": {
                 "type": "stemmer",
                 "language": "possessive_english"
             },
             "shingle_filter": {
                 "min_shingle_size": 2,
                 "max_shingle_size": 4,
                 "type": "shingle"
             }
         }
     }
    

    现在这个查询会给你想要的结果。

    {
       "suggest" : {
         "text" : "appel on the tabel",
         "simple_phrase" : {
           "phrase" : {
             "field" :  "suggest_field",
             "size" :   5,
             "collate": {
               "query": { 
                 "inline" : {
                   "match_phrase": {
                       "{{field_name}}" : "{{suggestion}}" 
                   }
                 }
               },
               "params": {"field_name" : "suggest_field"}, 
               "prune": false
             }
           }
         }
       },
       "size": 0
     }
    

    这会让你回到桌上的苹果 这里使用了match_phrase 查询,它将针对索引运行每个建议的短语。您可以创建"prune" : true 并查看所有建议的结果,无论匹配如何。您可能需要考虑使用stop 过滤器来避免停用词。

    希望这会有所帮助!

    【讨论】:

    • 我现在就试一试。关于shingle filter,我认为你是对的。直到现在我才真正使用 shingle_filter,当时我正在寻找解决此问题的方法,并且一些帖子推荐它作为 did-you-mean 功能。
    • 嘿,我只是试试这个,这正是我所需要的,谢谢!顺便问一下,你知道那里处理复数的方法吗?我的意思是,例如,为了获得建议,我既不写 apple 也不写 apples。我知道snowball 过滤器,但由于它通过令牌工作,并且keyword 令牌生成器产生一个单独的令牌,在这种情况下它并不准确:apples on the tables,它产生:桌子上的苹果,你知道吗?
    • 嘿,我已经更新了我的答案。请看一看。它应该照顾你建议的一切。如果有问题,请告诉我
    • 我很确定当我说你的回答解决了我面临的问题时,我真的很感激,也感谢你的努力,我是认真的。我欠你一个 :) 顺便说一句,我想知道collate 会产生哪些性能后果?我当然会做我的研究,但如果你知道什么,我会很高兴来到这里
    • 很高兴能帮上忙,在触发多个短语建议请求时有this issue,但已解决,除此之外我认为它没有任何问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多