【问题标题】:How do I search within a word within a searchable field? "Contains" search如何在可搜索字段中搜索单词? “包含”搜索
【发布时间】:2019-07-04 20:33:07
【问题描述】:

我有一个包含 4 个自定义分析器的搜索索引。其中两个用于特定语言的搜索,另外两个用于“精确”搜索(不需要词形还原)。为简单起见,我只包含特定语言自定义分析器的信息,尽管整体解决方案需要适用于所有自定义分析器。

{
    "tokenizers": [
        {
            "@odata.type": "#Microsoft.Azure.Search.MicrosoftLanguageStemmingTokenizer",
            "name": "text_language_search_custom_analyzer_ms_tokenizer",
            "maxTokenLength": 300,
            "isSearchTokenizer": false,
            "language": "french"
        },
        {
            "@odata.type": "#Microsoft.Azure.Search.MicrosoftLanguageStemmingTokenizer",
            "name": "text_language_search_endsWith_custom_analyzer_ms_tokenizer",
            "maxTokenLength": 300,
            "isSearchTokenizer": false,
            "language": "french"
        }
    ],
    "analyzers": [
        {
            "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
            "name": "text_language_search_custom_analyzer",
            "tokenizer": "text_language_search_custom_analyzer_ms_tokenizer",
            "tokenFilters": [
                "lowercase",
                "lang_text_synonym_token_filter",
                "asciifolding"
            ],
            "charFilters": [
                "html_strip"
            ]
        },
        {
            "@odata.type": "#Microsoft.Azure.Search.CustomAnalyzer",
            "name": "text_language_search_endsWith_custom_analyzer",
            "tokenizer": "text_language_search_endsWith_custom_analyzer_ms_tokenizer",
            "tokenFilters": [
                "lowercase",
                "lang_text_endsWith_synonym_token_filter",
                "asciifolding",
                "reverse"
            ],
            "charFilters": [
                "html_strip"
            ]
        }
    ]
}

为简单起见,我们假设索引只有 2 个可搜索字段。 - CategoryLangSearch(使用 text_language_search_custom_analyzer) - CategoryLangSearchEndsWith(使用 text_language_search_endsWith_custom_analyzer)

现在假设索引只有 1 个文档,包含以下内容: - "TELECOMMUNICATIONS" 的 CategoryLangSearch 字段值 - CategoryLangSearchEndsWith 字段值为“TELECOMMUNICATIONS”

我们的 UI/API 层具有逻辑,因此如果用户搜索 TELE*,它现在将使用 CategoryLangSearch 作为搜索字段。同样,我们的 UI/API 层将检测用户是否使用星号通配符进行搜索正面。因此,如果用户搜索 *TIONS,UI/API 层足够智能,可以改为搜索 CategoryLangSearchEndsWith 字段。

这一切都很棒......它完全按照预期工作。

然而,问题是,如果用户使用 * COMMU * 进行搜索,我们该怎么办? (忽略空格... S.O. 将星号视为粗体信号。用户键入 asteriskCOMMUasterisk,其中星号为 *)

我认为如果我像这样构建 azure 搜索参数会很“聪明”: (CategoryLangSearch:(COMMU*) OR CategoryLangSearchEndsWith:(*UMMOC)) 但在实践中,我发现这找不到 TELECOMMUNICATIONS ORGANIZATION .当我看到我们构建的查询时,这非常有意义。

所以,我的问题是,我们如何解决这个问题?无论如何,我们可以在 Azure 搜索中以形状或形式实现它吗?我看不到这条成功之路。我能看到的唯一可能的解决方案如下: 1. 如果用户搜索 something... 2.首先直接查询我们的MS SQL服务器,使用SQL支持的%something%语法进行搜索。 3. 找到匹配的 ID,然后使用 THAT 搜索 Azure 搜索索引。

【问题讨论】:

  • 嘿 Andres,旁注,因为您定义的两个标记器具有完全相同的配置,因此您定义一个并在您的两个客户分析器中使用它就足够了。这将使您的索引定义更清晰,但对行为的服务性能没有影响。
  • 谢谢@Yahnoosh... 甚至没有注意到这一点,但这是有道理的 :) 我只想让事情变得更简单。

标签: azure-cognitive-search


【解决方案1】:

有两种方法可以在 Azure 搜索中发出“包含”搜索。

  1. 第一种方法是在 Lucene 查询语法中使用正则表达式。在您的示例中,如果您发出正则表达式查询 /.*COMMU.*/,则搜索查询将首先扩展到搜索索引中包含字符串“commu”的所有术语,然后查找结果。您可以针对“精确”匹配的字段发出正则表达式查询。搜索查询如下所示: docs?search=exact_field:/.*COMMU.*/&queryType=full。

  2. 如果您的索引较小,建议使用上述方法,因为查找查询模式的查询扩展过程成本很高,尤其是对于像 /.*a.*/ 这样的广泛搜索。您可以在索引时间使用 ngram tokenfilter 预加载工作。令牌过滤器的配置如下。

{
  "@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2",
  "name": "ngram_tokenfilter",
  "minGram": 1,
  "maxGram": 100
}

例如,给定文本“hello”,此标记过滤器生成 ngram 标记为

h, e, l, l, o, he, el, ll, lo, hel, ell, ..., 你好。

查询使用 ngram tokenfilter 分析的新字段时,您不需要通配符或正则表达式运算符,但可以使用常规术语搜索。搜索查询“docs?search=ell”将找到包含术语“hello”的文档。这种方法避免了昂贵的扩展过程,因为所有“包含”的可能性都已经过预处理,并且存在于索引中。请注意,您只需要在索引时进行 ngram 分析。

还请注意,这个 ngram 分析会影响索引的大小,因为它会产生更多的标记。您可以使用参数“minGram”和“maxGram”来控制索引的大小。

由于您已经有一个 API/UI 可以根据“*”的位置来引导搜索,因此第二个选项似乎是一个不错的方法。

内特

【讨论】:

  • 感谢@Nate-Ko 的回复。我不确定我是否正确地做到了这一点。我尝试应用这个 NGramTokenFilterV2,但它大大增加了我们的索引时间,结果非常糟糕。我做了我通常的测试,简单地搜索 femme,搜索索引几乎认为每个文档都是匹配的。我们的突出显示也完全疯狂,几乎突出显示每个文档中的每个单词。我是否应该使用此 NGramTokenFilterV2 拥有另一组可搜索字段并针对这些字段进行搜索?还是我需要单独的自定义分析器,1 用于索引...
  • ... NGramTokenFilterV2 和另一个没有 NGramTokenFilterV2 的自定义搜索分析器?
  • 谢谢内特。这个 NGram 令牌过滤器是为我们解决这个问题的关键。
【解决方案2】:

很好的答案内特! 但这并不完全正确。

如果你像这样使用“ngram_tokenfilter”,它将生成六个令牌: { h,他,hel,地狱,你好 }。 您可以创建第二个“ngram_tokenfilter”并将“side”参数设置为“back”以获得所需的行为。

我有一个非常相似的问题,也许它可以帮助:Azure-search: How to get documents which exectly contain search term

祝大家有个愉快的一天!

【讨论】:

  • 感谢参与。'side' 参数适用于 edgeNGramTokenFilter。建议的解决方案使用 NGramTokenFilter。如果我错过了什么,请告诉我。 :)
  • 哦,是的,你是对的,我忽略了它;)我的解决方案使用了 edgeNGramTokenFilter。对不起
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多