我有一个包含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个文档,具有以下内容: - CategoryLangSearch“TELECOMMUNICATIONS”的字段值 - CategoryLangSearchEndsWith“TELECOMMUNICATIONS”的字段值
我们的UI / API层具有逻辑,因此如果用户搜索TELE *,它现在将使用CategoryLangSearch作为要搜索的字段。同样,我们的UI / API层将检测用户是否在星号中使用星号通配符进行搜索。面前。因此,如果用户搜索* TIONS,则UI / API层足够智能,而不是搜索CategoryLangSearchEndsWith字段。
一切都很棒......它完全符合预期。
但问题是,如果用户使用* COMMU *进行搜索,我们可以做些什么 (忽略空格...... S.O.将星号视为粗体信号。用户输入asteriskCOMMUasterisk,其中星号为*)
如果我像这样构建azure搜索参数,我认为这将是“聪明的”:(CategoryLangSearch:(COMMU *)OR CategoryLangSearchEndsWith:(* UMMOC))但是,在实践中,我发现这没有找到电信组织。当我看到我们构建的查询时,这非常有意义。
所以,我的问题是,我们如何解决这个问题呢?我们可以在Azure Search中以任何方式,形状或形式将其删除吗?我没有看到这个成功之路。我能看到的唯一可行解决方案如下: 1.如果用户搜索某事 ... 2.首先直接查询我们的MS SQL服务器,使用SQL支持的%something%语法进行搜索。 3.找到匹配的ID,然后使用THAT搜索Azure搜索索引。
答案 0 :(得分:1)
有两种方法可以在Azure搜索中发出“包含”搜索。
第一种方法是在Lucene查询语法中使用regex表达式。在您的示例中,如果您发出正则表达式查询/.*COMMU.*/,搜索查询将首先扩展到搜索索引中包含字符串'commu'的所有项,然后查找结果。您可以针对“完全”匹配对字段发出正则表达式查询。搜索查询看起来像: ?文档搜索= exact_field:/.* COMMU * /&放大器;查询类型=满。
如果索引较小,建议使用上述方法,因为查找查询模式的查询扩展过程代价很高,尤其是对于/.*a.*/等广泛搜索。您可以在索引时使用ngram tokenfilter预加载工作。 tokenfilter的配置如下。
{ "@odata.type": "#Microsoft.Azure.Search.NGramTokenFilterV2", "name": "ngram_tokenfilter", "minGram": 1, "maxGram": 100 }
例如,给定一个文本“hello”,这个tokenfilter生成ngram标记为
h,e,l,l,o,he,el,ll,lo,hel,ell,...,你好。
查询使用ngram tokenfilter分析的新字段时,您不需要使用通配符或正则表达式运算符,但可以使用常规术语搜索。搜索查询“docs?search = ell”将找到包含术语“hello”的文档。这种方法避免了昂贵的扩展过程,因为所有“包含”的可能性都已经过预处理,并且存在于索引中。请注意,您只需要在索引时进行ngram分析。
请注意,此ngram分析会影响索引的大小,因为它会生成更多令牌。您可以使用参数'minGram'和'maxGram'来控制索引的大小。
由于您已经有一个基于'*'位置指向搜索的API / UI,第二个选项似乎是一个很好的方法。
内特
答案 1 :(得分:0)
很棒的答案Nate! 但这不完全正确。
如果您像这样使用“ngram_tokenfilter”,它将生成正好六个令牌: {h,他,嗨,地狱,你好} 。 您可以创建第二个“ngram_tokenfilter”并将“side”参数设置为“back”以获得所需的行为。
我有一个非常类似的问题,也许它可以提供帮助:Azure-search: How to get documents which exectly contain search term
祝你们玩得愉快!