【问题标题】:ElasticSearch phrase prefix search - How do I get the matched phrase?ElasticSearch 短语前缀搜索 - 如何获取匹配的短语?
【发布时间】:2014-04-23 22:50:19
【问题描述】:

我正在使用 ElasticSearch 构建自动完成功能。当用户键入时,我想显示数据中的完成列表,以便用户选择一个。例如,如果数据包含以下短语:

very unusual
very unlikely
very useful

和用户类型:

very u

我想显示上面的短语。

我正在使用这个查询:

  "query": {
    "multi_match": {
      "query": "very u",
      "fields": [
        "name",
        "description",
        "contentBlocks.caption",
        "contentBlocks.text"
      ],
      "type": "phrase_prefix",
      "max_expansions": 10,
      "cutoff_frequency": 0.001
    }

这与我正在寻找的内容相匹配,但从搜索结果中提取匹配的短语非常尴尬。我一直在使用高亮,我通过解析高亮来收集匹配的短语。例如:

    "highlight": {
      "contentBlocks.text": [
        "turned the <em>very</em> <em>unusual</em> doorknob"
      ]
    }

    "highlight": {
      "contentBlocks.text": [
        "invented a <em>very</em> <em>useful</em> mechanism"
      ]
    }

这样做的正确方法是什么?


“短语建议者”可能能够做我所描述的事情,但你将如何让它做到这一点并不明显。

我已将感兴趣的字段(例如“描述”)编入索引,如下所示:

  "description" : {
    "index_analyzer" : "snowball_stem",
    "search_analyzer" : "snowball_stem",
    "type" : "string",
    "fields" : {
      "autocomplete" : {
        "index_analyzer" : "shingle_analyzer",
        "search_analyzer" : "shingle_analyzer",
        "type" : "string"
      }
    }
  },

我使用 snowball_stem 分析器进行搜索,使用 shingle_analyzer 进行自动完成功能。 shingle_analyzer 看起来像这样:

"settings" : {
    "analysis" : {
        "analyzer" : {
            "shingle_analyzer" : {
                "type" : "custom",
                "tokenizer" : "standard",
                "filter" : [
                    "standard",
                    "lowercase",
                    "shingle_filter"
                ],
                "char_filter" : [
                    "html_strip"
                ]
            }
        },
        "filter" : {
            "shingle_filter" : {
                "type" : "shingle",
                "min_shingle_size" : 2,
                "max_shingle_size" : 2
            }
        }
    }
},

短语建议者的文档似乎完全面向“拼写纠正”而不是完成。由于我追求的是完成,我将直接生成器的 min_word_length 和 prefix_length 设置为输入文本的长度,在本例中为 2。

我根据文档制作了一个建议查询:

{
    "text" : "sa",
    "autocomplete_description" : {
        "phrase" : {
            "analyzer" : "standard",
            "field" : "description.autocomplete",
            "size" : 10,
            "max_errors" : 2,
            "confidence" : 0.0,
            "gram_size" : 2,
            "direct_generator" : [
                {
                    "field" : "description.autocomplete",
                    "suggest_mode" : "always",
                    "size" : 10,
                    "min_word_length" : 2,
                    "prefix_length" : 2
                }
            ]
        }
    }
}

搜索“sa”的建议得到以下结果:

{
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "autocomplete_description" : [ {
    "text" : "sa",
    "offset" : 0,
    "length" : 2,
    "options" : [ {
      "text" : "say",
      "score" : 0.012580795
    }, {
      "text" : "sa",
      "score" : 0.01127677
    }, {
      "text" : "san",
      "score" : 0.0106529845
    }, {
      "text" : "sad",
      "score" : 0.008533429
    }, {
      "text" : "saw",
      "score" : 0.008107899
    }, {
      "text" : "sam",
      "score" : 0.007155634
    } ]
  } ]
}

我希望为输入“sa”找到以“sa”开头的任意长度的单词。为什么它只返回两个或三个字符的单词?为什么它只返回六个选项?我一直使用的 multi_match phrase_prefix 查询可以找到许多以“sa”开头的较长单词,例如“saving”、“sassy”、“safari”和“salad”。

当我搜索多词文本的建议时,例如“one or”(在数据中出现很多次),它什么也找不到。 multi_match phrase_prefix 查询查找“one or more”、“one or the”、“one or you”和“one or both”。

我怎样才能让这个建议者做我想做的事?

【问题讨论】:

  • 如果您有任何问题,请告诉我,或者我可以在答案中添加任何内容。
  • 我尝试使用短语提示器来执行此操作,但我没有取得太大的成功。我在上面的问题描述中添加了有关我的实验的信息和更详细的问题。
  • @davidhaimson 短语建议者仅根据编辑距离提出建议。这就是为什么您只会获得较短的完成 - 它们在编辑距离上比“节省”之类的要近得多。

标签: autocomplete elasticsearch


【解决方案1】:

您可以使用completion suggester 大致获得所需的内容。这样做的主要问题是它不再具有搜索意识。您可以通过添加 suggester context 来解决此问题,但它仅适用于过滤器,不考虑搜索文本。

我所知道的获得“最佳”行为(上下文感知搜索完成)的唯一方法是执行以下操作:

  • 创建一个 suggestions 字段,在该字段中对文本进行标记,就像您希望用户看到的那样(可能是标准分析器,或者可能添加一个 2-shingle 标记过滤器)。
  • 假设用户发出不完整的查询very un。在幕后问题搜索very,然后使用term aggregations 获取与搜索上下文匹配的列表词,但限制使用"include": "un.*" 返回的词。
  • 生成的列表看起来像 [unusual,unlikely,uncool]。

这种方法的唯一问题是,尤其是在分片环境中,它有很多查询,并且您将一个非常高的基数字段 (suggestions) 拉入内存。所以...我不知道这是否可行。所以也许最好用完成建议器返回。如果您尝试其中任何一种方法,我很想听听您的体验。

【讨论】:

  • 感谢您对此进行调查,@JnBrymn。我最终使用了我最初描述的代码,使用了 phrase_prefix 查询和后处理亮点。这似乎是一种 hack,但它工作可靠且性能出奇的好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 2023-03-20
  • 1970-01-01
  • 2019-09-09
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多