如何在可搜索字段中的某个词内进行搜索? "Contains" 搜索

How do I search within a word within a searchable field? "Contains" search

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

{
    "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 搜索参数,我认为它会是 "smart":(CategoryLangSearch:(COMMU*) OR CategoryLangSearchEndsWith:(*UMMOC)) 但是,在实践中,我发现这样做找不到电信组织。当我看到我们构建的查询时,这非常有意义。

那么,我的问题是,我们如何实现这一目标?我们能否以任何形式在 Azure 搜索中实现它?我看不到这条通往成功的道路。我能看到的唯一可能的解决方案如下: 1. 如果用户搜索 something... 2. 首先直接查询我们的 MS SQL 服务器,使用 SQL 支持的 %something% 语法进行搜索。 3. 找到匹配的 ID,然后使用它根据 Azure 搜索索引进行搜索。

您可以通过两种方式在 Azure 搜索中进行 'contains' 搜索。

  1. 第一种方法是在 Lucene 查询语法中使用正则表达式。在您的示例中,如果您发出正则表达式查询 /.*COMMU.*/,搜索查询将首先扩展到搜索索引中包含字符串 'commu' 的所有术语,然后找到结果。您可以针对 "exact" 匹配项的字段发出正则表达式查询。搜索查询看起来像: 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, ..., hello.

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

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

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

内特

内特回答得好! 但这并不完全正确。

如果你像这样使用 "ngram_tokenfilter" 它将生成正好六个标记: { h, he, hel, hell, hello }. 您可以创建第二个 "ngram_tokenfilter" 并将 "side" 参数设置为 "back" 以获得所需的行为。

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

祝大家有个愉快的一天!