【问题标题】:Elasticsearch long phrases searchElasticsearch 长短语搜索
【发布时间】:2015-09-03 15:01:47
【问题描述】:

我正在使用 Elasticsearch 进行全文搜索,并且正在尝试找到一种更好的方法来搜索长短语。

例如,我有一个字段“Seller”,最多可以包含 250 个字符,我想查找所有带有 Seller = 'some Seller name with spaces' 的项目。

如果我理解正确,为了搜索包含空格的文本,我必须使用 NGramTokenizer,它基本上会创建如下标记:

's', 'so', 'som', 'some', 'some ', 'some s' etc. 

我知道我可以定义 min 和 max gram,但我需要能够搜索“a b”,所以我的 min gram 必须至少为 3,max gram 作为我的字段最大长度。

所以我必须为每件商品创建很多代币,而且它只是卖家,但是 4k 字符的描述呢?

此解决方案的性能非常低。

谁能提出一个更好的解决方案来处理带有空格的长短语?

我的索引设置:

analysis: {
  analyzer: {
    autoComplete: {
      filter: [
        "lowercase"
      ],
      type: "custom",
      tokenizer: "autoComplete"
    },
    caseInsensitive: {
      type: "custom",
      filter: [
        "lowercase"
      ],
      tokenizer: "keyword"
    }
  },
  tokenizer: {
    autoComplete: {
      type: "nGram",
      min_gram: "1",
      max_gram: "40"
    }
  }
},

我使用“autoComplete”作为索引分析器和“不区分大小写”作为搜索分析器

编辑:

我使用 NGramTokenizer 以便能够搜索部分单词

真实单词示例:

Title: 'Huge 48" Bowtie LED Opti neon wall sign. 100,000 hours Bar lamp light'

search query: 'Huge 48" Bowt'

使用空格标记器,如果您搜索短语,则无法搜索部分单词。

【问题讨论】:

  • 不太明白为什么需要 ngram。如果您希望能够搜索"a b",则需要在索引中包含一个完整的标记a b 或两个标记ab。这可以使用whitespace 标记器来完成,这将为文本a b c 生成标记:abc。这里不需要 ngram。虽然我可以看到您正在尝试使用自动完成功能做某事,但也许我没有清楚地理解您的问题。
  • 嗨 slawek,我已经更新了我的帖子,希望现在 NGramTokenizer 更有意义。
  • 我建议您使用 shingles 进行短语匹配,使用 nGrams 搜索单词的一部分。
  • 我使用 nGrams 搜索单词的一部分,但是在很长的字段上使用 nGrams 进行索引时存在问题。尝试使用 maxGram = 200+ 进行索引,这将需要很长时间 :(

标签: elasticsearch full-text-search nest


【解决方案1】:

您需要回答的第一个问题是:您需要匹配单词中的子字符串吗?例如在transmission中匹配miss。如果您需要此功能,那么没有比 ngrams 更好的方法来实现它。尝试在词条开头使用通配符意味着遍历索引中的每个词条以查看它是否匹配并且不能很好地扩展。

请注意,您可以通过两种方式使用 ngram:作为分词器或作为分词过滤器。除了您使用的标记器,您还可以使用标记过滤器变体。首先使用 standardwhitespace 标记器标记文本,然后应用 ngram 标记过滤器。使用令牌过滤器,您的索引中不会有带有空格的克。您需要多久查找一次以 ing 结尾的单词以及紧随其后又以 to 开头的单词的文本?

如果您不需要查看单词的内部,但有时想省略后缀,还有其他几个选项。第一个是另一种格,edge grams,锚定在单词的开头。边缘 ngram 最常见的用例场景是边输入边搜索功能。

您可以在下面看到索引示例比较(来自inquisitor 插件的屏幕截图)huge bowtie 使用所有这些克方法(最小值:2 最大值:3):

标记的数字很重要,它们是位置编号。查找短语时使用位置编号。寻找短语"a b" 本质上是寻找标记"a" 然后寻找标记"b" 并检查它们的位置差是否等于1。正如您在上面看到的,这些克结果位置在查找时可能会导致一些问题短语。

首先,让我们看看如何使用_validate API 使用查询"huge bowtie" 为这样分析的字段解释短语查询:

  • edge_filter "(hu hug huge) (bo bow bowt bowti bowtie)"
  • edge_tokenizer "hu hug huge bo bow bowt bowti bowtie"
  • ngram_filter "(hu hug ug uge ge) (bo bow ow owt wt wti ti tie ie)"
  • ngram_tokenizer "hu hug ug uge ge bo bow ow owt wt wti ti tie ie"

tokenizer 查询解释相当简单:您不必一个接一个地查找两个令牌,而是必须查看所有的gram 并确保它们彼此跟随。过滤器版本更麻烦:查询"huge bowtie" 将匹配文本hu owt,因为单词中至少有一个克匹配就足够了。

如果您使用分析查询并且未指定您需要词组搜索,您也必须小心。例如,使用 "query_string": { "query": "bowtie" } 将转换为边缘 ngram 的 bo OR bow OR bowt OR bowt OR bowti OR bowtie,因为默认的 query_string 运算符是 OR。这不是用户想要的,因为它会匹配 bo 的任何内容。

还要注意,如果在同一位置有多个标记,则会出现问题,即某些短语会匹配,即使它们不应该匹配。例如短语 "hu bowti" 将与 edge_filter 和 ngram_filter 标记匹配,即使源文本中没有这样的短语。

g 的标记过滤器变体似乎较差,并且没有真正有用。但是当使用 gram 标记过滤器时,人们commonly 使用不同的分析器进行搜索而不是索引。例如,如果我们将查询 "huge bowtie" 保留原样而不对其进行分析,它会通过仅查找 2 个术语来找到匹配项(因为它们都在索引中,所以有 huge:1bowtie:2)。但是,使用这种方法,您需要将 n 设置得相当高(100% 确保所有内容都匹配它应该等于最长的单词)。否则,在使用 max gram 5 时,您可能会遇到与 bowtie 搜索不匹配的情况,因为索引仅包含 bowti 令牌。

正如你所见,gram 引入了相当复杂的问题。这就是为什么人们通常将克与正常索引的文本结合起来(使用multi_field 映射)。留给自己以后的选择。使用不同的分析器索引相同的文本允许以多种方式进行搜索,并在一次使用两个字段进行搜索时提高精度。

如果您不想处理所有与克相关的问题。您可以简单地正常索引文本并使用通配符。您会在搜索时间上付出代价,但根据您的数据和场景,它可能会起作用。就我个人而言,在我的公司,我们使用通配符来查询包含数十亿文档的索引,并且弹性处理得很好。

如果您决定使用通配符查询,您有几个选择。您可以使用wildcard 查询或query_string 查询。但是使用它们您将无法同时进行短语和通配符后缀查询。希望有匹配查询变体可以完全满足您的要求:搜索短语,最后一个单词被视为不完整:

{
    "match_phrase_prefix" : {
        "message" : {
            "query" : "Huge 48" Bowt",
            "max_expansions" : 100
        }
    }
}

摘自docs

match_phrase_prefix 与 match_phrase 相同,不同之处在于它 允许对文本中的最后一个词进行前缀匹配。

总结一下。

如果我正确理解您的情况,我会在包含原始文本的多字段中使用边缘标记器或我最喜欢的边缘标记过滤器(使用标准搜索分析器)。拥有原始文本允许在边缘克中使用较低的值。有了这样的映射,您可以使用以下 query_string:"originalText: \"Huge 48" Bowt\" OR edgeGrammed: \"Huge 38" Bowt\""。您不必担心您的 n in edge gram 太低,因为您在原始文本中有一个后备。我认为n等于10-15就足够了?此外,原始文本通配符始终是一种选择。

Here 也是一篇关于 ngram 的好文章。

【讨论】:

  • 嗨 slawek,谢谢你这么彻底的回答,你肯定给了我最终解决方案的想法。
  • 很高兴我能帮上忙。它只是了解索引中的内容以及查询的执行方式。在我的公司,我们有完整的测试套件来确保分析仪按预期工作,而另一个用于测试此类分析的套件允许我们进行所需的搜索。我提到的分析器 API、调查者和验证 API 等工具有助于理解正在发生的事情。您可能会查看另一个工具 Extended _analyze plugin stackoverflow.com/a/30943879/808271 。如果您得出最终解决方案,请考虑在此处发布并与社区分享。我相信有人会觉得它很有用。
猜你喜欢
  • 2016-03-31
  • 1970-01-01
  • 2021-08-19
  • 1970-01-01
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
  • 1970-01-01
相关资源
最近更新 更多