你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

部分字词搜索和包含特殊字符(连接符、通配符、正则表达式、模式)的模式

部分字词搜索是指由字词片段组成的查询,其中没有包含整个字词,而可能只是包含字词的开头、中间部分或末尾(有时称为前缀查询、中缀查询或后缀查询)。 部分字词搜索可能包括片段的组合,其中通常包含特殊字符,例如属于查询字符串一部分的连接符、短划线或斜杠。 常见的用例包括电话号码、URL、代码或带连字符的组合词的一部分。

如果索引没有表示要搜索的文本片段的标记,则部分字词和特殊字符可能会出现问题。 在索引的 词法分析阶段 , (假定默认的标准分析器) ,将丢弃特殊字符,拆分复合词,并删除空格。 如果要搜索在词法分析期间修改的文本片段,则查询会失败,因为找不到匹配项。 以以下示例为例: (标记化为 、、 "703") 的+1 (425) 703-6214电话号码不会显示在查询中"3-62",因为索引中实际上不存在该内容。 "6214""425""1"

解决方案是在索引编制期间调用一个分析器来保留完整的字符串(在必要的情况下包括空格和特殊字符),以便可以在查询字符串中包括空格和这些字符。 使用完整的非标记化字符串可为“开头”或“以结尾”查询进行模式匹配,其中提供的模式可以根据未通过词法分析转换的术语进行评估。

如果需要支持调用已分析和非分析内容的搜索方案,请考虑在索引中创建两个字段,每个方案一个字段。 一个字段用于词法分析。 第二个字段使用保留内容的分析器存储原有字符串,该分析器会发出完整字符串标记以进行模式匹配。

提示

如果你熟悉 Postman 和 REST API,请下载查询示例集合以查询本文中所述的部分字词和特殊字符。

Azure 认知搜索在索引中扫描完整的标记化字词,不会基于部分字词查找匹配项,除非你包括通配符占位符运算符(*?)或将查询格式设置为正则表达式。

部分字词是使用以下方法指定的:

  • 正则表达式查询,可以是在 Apache Lucene 下有效的任何正则表达式。

  • 进行前缀匹配的通配符运算符,指的是一种公认的模式,它包括一个字词的开头,后跟 *? 后缀运算符,例如,search=cap* 将匹配“Cap'n Jack's Waterfront Inn”或“Gacc Capital”。 简单和完整的 Lucene 查询语法都支持前缀匹配。

  • 进行中缀和后缀匹配的通配符,它将 *? 运算符置于字词的内部或开头,并需要使用正则表达式语法(表达式用正斜杠围起来)。 例如,查询字符串 (search=/.*numeric.*/) 会返回将“alphanumeric”和“alphanumerical”作为后缀匹配项和中缀匹配项的结果。

对于正则表达式、通配符和模糊搜索,在查询时不使用分析器。 对于分析程序根据运算符和分隔符的存在检测到的这些查询形式,查询字符串不经词法分析便直接传递给引擎。 对于这些查询形式,将忽略在字段上指定的分析器。

注意

当部分查询字符串在 URL 片段中包含诸如斜杠之类的字符时,你可能需要添加转义字符。 在 JSON 中,使用反斜杠 \ 来转义正斜杠 /。 因此,search=/.*microsoft.com\/azure\/.*/ 是 URL 片段“microsoft.com/azure/”的语法。

解决部分搜索/模式搜索的问题

如果需要根据片段、模式或特殊字符进行搜索,可将默认分析器替代为自定义分析器,后者按照更简单的标记化规则运行,在索引中保留整个字符串。

方法如下所示:

  1. 定义第二个字段,以存储字符串的原有版本(假设在查询时需要已分析的和未分析的文本)
  2. 对各种可在适当粒度级别发出标记的分析器进行评估和选择
  3. 将分析器分配到字段
  4. 生成并测试索引

提示

评估分析器是需要频繁重建索引的迭代过程。 可以使用 Postman 以及创建索引删除索引加载文档搜索文档 REST API 来简化此步骤。 使用“加载文档”时,请求正文应包含要测试的小型代表性数据集(例如,包含电话号码或产品代码的字段)。 在同一 Postman 集合中使用这些 API 可以快速循环执行这些步骤。

1 - 创建专用字段

分析器将确定如何在索引中标记化字词。 由于分析器是按字段分配的,因此你可以在索引中创建字段,以针对不同的方案进行优化。 例如,可以定义“featureCode”和“featureCodeRegex”,这样就可以先执行常规的全文搜索,再进行高级模式匹配。 分配给每个字段的分析器将确定如何在索引中标记化每个字段的内容。

{
  "name": "featureCode",
  "type": "Edm.String",
  "retrievable": true,
  "searchable": true,
  "analyzer": null
},
{
  "name": "featureCodeRegex",
  "type": "Edm.String",
  "retrievable": true,
  "searchable": true,
  "analyzer": "my_custom_analyzer"
},

2 - 设置分析器

选择可生成完整字词标记的分析器时,以下分析器是常用选项:

分析器 行为
语言分析器 保留组合词或字符串、元音变化和动词形式中的连字符。 如果查询模式包含短划线,则使用语言分析器可能已足够。
keyword 整个字段的内容将标记化为单个字词。
whitespace 仅在空白位置分隔。 包含短划线或其他字符的字词被视为单个标记。
自定义分析器 (建议)创建自定义分析器可以指定标记器 (tokenizer) 和标记筛选器。 以前的分析器必须按原样使用。 使用自定义分析器可以选取要使用的标记器和标记筛选器。

建议的组合是关键字标记器小写标记筛选器。 内置 关键字分析器 本身不会对任何大写文本进行小写,这可能会导致查询失败。 自定义分析器提供一个机制用于添加小写标记筛选器。

如果使用 Web API 测试工具(如 Postman),可以添加 测试分析器 REST 调用 来检查标记化输出。

你必须有一个可供使用的已填充索引。 对于现有的索引以及包含短划线或部分字词的字段,可以针对特定字词尝试各种分析器,以查看发出哪些标记。

  1. 首先,检查标准分析器,看默认情况下如何标记化字词。

    {
    "text": "SVP10-NOR-00",
    "analyzer": "standard"
    }
    
  2. 评估响应,以查看文本如何在索引中标记化。 请注意小写每个术语、删除连字符以及将子字符串拆分成单独标记的方式。 只有与这些标记匹配的查询才会在结果中返回此文档。 包含“10-NOR”的查询会失败。

    {
        "tokens": [
            {
                "token": "svp10",
                "startOffset": 0,
                "endOffset": 5,
                "position": 0
            },
            {
                "token": "nor",
                "startOffset": 6,
                "endOffset": 9,
                "position": 1
            },
            {
                "token": "00",
                "startOffset": 10,
                "endOffset": 12,
                "position": 2
            }
        ]
    }
    
  3. 现在,请修改请求以使用 whitespacekeyword 分析器:

    {
    "text": "SVP10-NOR-00",
    "analyzer": "keyword"
    }
    
  4. 这一次,响应由单个标记(大写)组成,短划线保留为字符串的一部分。 如果你需要基于某个模式或部分字词(例如 10-NOR)进行搜索,你会发现,查询引擎现在有了查找匹配项的基础。

    {
    
        "tokens": [
            {
                "token": "SVP10-NOR-00",
                "startOffset": 0,
                "endOffset": 12,
                "position": 0
            }
        ]
    }
    

重要

请注意,在生成查询树时,查询分析程序往往会将搜索表达式中的字词小写。 如果使用的分析器在编制索引期间不会将文本输入小写,并且你未获得预期的结果,则原因可能就在于此。 解决方法是根据下面的“使用自定义分析器”部分所述添加小写标记筛选器。

3 - 配置分析器

无论是评估分析器还是继续执行特定配置,都需要在字段定义中指定分析器,如果未使用内置分析器,则可能需要配置分析器本身。 交换分析器时,通常需要重建索引(删除、重新创建并重新加载)。

使用内置分析器

内置分析器可以在字段定义的属性上 analyzer 按名称指定,索引中不需要额外的配置。 以下示例演示如何在字段中设置 whitespace 分析器。

有关其他方案以及其他内置分析器的详细信息,请参阅内置分析器

    {
      "name": "phoneNumber",
      "type": "Edm.String",
      "key": false,
      "retrievable": true,
      "searchable": true,
      "analyzer": "whitespace"
    }

使用自定义分析器

如果使用 自定义分析器,请使用用户定义的 tokenizer、token filter 以及可能的配置设置组合在索引中定义它。 接下来,在字段定义中引用它,就像引用内置分析器一样。

如果目标是完整字词标记化,我们建议使用一个由关键字标记器小写标记筛选器组成的自定义分析器。

  • 关键字标记器为字段的整个内容创建单个标记。
  • 小写标记筛选器将大写字母转换为小写文本。 查询分析程序通常将任何大写文本输入小写。 小写过程可将包含标记化字词的输入均匀化。

以下示例演示了一个提供关键字标记器和小写标记筛选器的自定义分析器。

{
"fields": [
  {
  "name": "accountNumber",
  "analyzer":"myCustomAnalyzer",
  "type": "Edm.String",
  "searchable": true,
  "filterable": true,
  "retrievable": true,
  "sortable": false,
  "facetable": false
  }
],

"analyzers": [
  {
  "@odata.type":"#Microsoft.Azure.Search.CustomAnalyzer",
  "name":"myCustomAnalyzer",
  "charFilters":[],
  "tokenizer":"keyword_v2",
  "tokenFilters":["lowercase"]
  }
],
"tokenizers":[],
"charFilters": [],
"tokenFilters": []
}

注意

keyword_v2 标记器和 lowercase 令牌筛选器对于系统是已知的,它们使用默认配置,正因如此,可以按名称引用它们,而无需先定义它们。

4 - 生成和测试

使用支持方案的分析器和字段定义定义索引后,请加载具有代表性字符串的文档,以便可以测试部分字符串查询。

前面的部分介绍了逻辑。 本部分将逐步介绍在测试解决方案时应调用的每个 API。 如前所述,如果使用 Postman 等交互式 Web 测试工具,则可快速逐步完成这些任务。

  • 删除索引”会删除同名的现有索引,以便可以重新创建该索引。

  • 创建索引”会在搜索服务中创建索引结构,包括分析器定义以及附带分析器规范的字段。

  • 加载文档”会导入与索引具有相同结构的文档以及可搜索的内容。 完成此步骤后,索引便可供查询或测试。

  • 设置分析器中介绍了测试分析器。 使用各种分析器测试索引中的一些字符串,以了解术语的标记化方式。

  • 搜索文档中介绍了如何使用通配符和正则表达式的简单语法完整 Lucene 语法来构造查询请求。

    若要进行部分字词查询,例如,查询“3-6214”以找到“+1 (425) 703-6214”的匹配项,可以使用简单语法:search=3-6214&queryType=simple

    若要进行中缀和后缀查询,例如,查询“num”或“numeric”以找到“alphanumeric”的匹配项,请使用完整 Lucene 语法和正则表达式:search=/.*num.*/&queryType=full

调整查询性能

如果实现包含 keyword_v2 tokenizer 和小写令牌筛选器的建议配置,则可能会注意到查询性能下降,因为索引中现有令牌的额外令牌筛选器处理。

以下示例添加一个 EdgeNGramTokenFilter,使前缀匹配速度更快。 为包含字符的 2-25 个字符组合生成了更多令牌: (MS、MSF、MSFT、MSFT/、MSFT/S、MSFT/SQ、MSFT/SQL) 。

可以想象,额外的标记化会导致更大的索引。 如果有足够的容量来容纳较大的索引,则此方法的响应时间更短,可能是更好的解决方案。

{
"fields": [
  {
  "name": "accountNumber",
  "analyzer":"myCustomAnalyzer",
  "type": "Edm.String",
  "searchable": true,
  "filterable": true,
  "retrievable": true,
  "sortable": false,
  "facetable": false
  }
],

"analyzers": [
  {
  "@odata.type":"#Microsoft.Azure.Search.CustomAnalyzer",
  "name":"myCustomAnalyzer",
  "charFilters":[],
  "tokenizer":"keyword_v2",
  "tokenFilters":["lowercase", "my_edgeNGram"]
  }
],
"tokenizers":[],
"charFilters": [],
"tokenFilters": [
  {
  "@odata.type":"#Microsoft.Azure.Search.EdgeNGramTokenFilterV2",
  "name":"my_edgeNGram",
  "minGram": 2,
  "maxGram": 25,
  "side": "front"
  }
]
}

后续步骤

本文说明了分析器如何造成查询问题和解决查询问题。 接下来,请更详细地了解分析器对索引编制和查询处理的影响。 具体而言,请考虑使用分析文本 API 返回标记化的输出,以便可以确切地了解分析器正在为索引创建哪些内容。