Elasticsearch长短语搜索

Kon*_*din 3 full-text-search elasticsearch nest

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

例如,我有一个字段“ Seller”,最多可以包含250个字符,我想查找所有带有Seller =“带有空格的卖家名称”的商品。

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

's', 'so', 'som', 'some', 'some ', 'some s' etc. 
Run Code Online (Sandbox Code Playgroud)

我知道我可以定义最小和最大克,但我需要能够搜索“ a b”,因此我的最小克必须至少为3,最大克为字段的最大长度。

因此,我必须为每个项目创建很多令牌,并且这只是卖方,但是关于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"
    }
  }
},
Run Code Online (Sandbox Code Playgroud)

我将“ autoComplete”用作索引分析器,将“ caseInsensitive”用作搜索分析器

编辑:

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

实词示例:

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

search query: 'Huge 48" Bowt'
Run Code Online (Sandbox Code Playgroud)

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

sla*_*wek 5

您需要回答的第一个问题是:是否需要匹配单词中的子字符串。例如,在反式小姐中匹配小姐。如果您需要此功能,那么没有比ngrams更好的方法了。试图在术语开始时使用通配符,将意味着遍历索引中的每个术语以查看其是否匹配并且缩放效果不佳。

请注意,可以通过两种方式使用ngram:作为标记生成器或作为标记过滤器。除了您使用的令牌生成器之外,您还可以使用令牌过滤器变体。首先使用standardwhitespace标记化器对文本进行标记化,然后应用ngram标记过滤器。使用令牌过滤器,索引中将没有克。您需要多久查找一次以一个单词结尾的单词,ing然后立即以一个单词开头的单词to

如果您不需要查看单词的内在内容,但有时想省略后缀,则还有其他几种选择。第一个是另一种克,即边缘克,它们固定在单词的开头。边缘ngram的最常见用例场景是按需搜索功能。

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

在此处输入图片说明

令牌中的数字很重要,它们是位置号。查找短语时使用位置编号。查找词组"a b"本质上是在寻找令牌,"a"然后在寻找令牌,然后"b"检查它们的位置差是否等于1。如上所示,在查找短语时,这些克产生的位置可能会引起一些问题。

首先,让我们看看如何"huge bowtie"使用_validate API 通过这种方式对通过这种方式分析的字段解释短语查询:

  • 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"

标记器查询的解释非常简单:不必一一一看地查找两个标记,而必须查看所有克并确保它们彼此跟随。过滤器版本比较麻烦:查询"huge bowtie"将匹配文本,hu owt因为单词内至少匹配一克就足够了。

如果使用分析查询并且不指定需要短语搜索,则还必须小心。例如,由于默认运算符为,所以使用"query_string": { "query": "bowtie" }将转换bo OR bow OR bowt OR bowt OR bowti OR bowtie为边缘ngram 。那不是用户想要的,因为它将与匹配。query_stringORbo

还要注意,如果在同一位置上有多个标记,则存在一个问题,即有些短语即使不匹配也将匹配。例如"hu bowti",即使源文本中没有这样的短语,短语也会与edge_filter和ngram_filter令牌匹配。

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

如您所见,克引入了相当复杂的问题。这就是为什么人们通常将克与正常索引的文本结合在一起(使用多字段映射)。以后再给自己选择。使用不同的分析器为同一文本建立索引可以在多种方式下进行搜索,并在一次使用两个字段进行搜索时提高了准确性。

如果您不想处理所有与克相关的问题。您可以简单地正常索引文本并使用通配符。您需要付出搜索时间的代价,但是取决于您的数据和方案,它可能会起作用。在我公司中,我们个人使用通配符查询具有数十亿个文档的索引,并且可以很好地处理它。

如果决定使用通配符查询,则有几种选择。您可以使用通配符查询或query_string查询。但是,使用它们将无法立即进行短语和通配符后缀查询。希望有一个完全符合您要求的匹配查询变体:搜索词尾不完整的词组:

{
    "match_phrase_prefix" : {
        "message" : {
            "query" : "Huge 48" Bowt",
            "max_expansions" : 100
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

摘录自docs

match_phrase_prefix与match_phrase相同,只是它允许在文本的最后一项上进行前缀匹配。

把它们加起来。

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

也是一篇关于ngram的不错的文章。