返回

解决 Azure AI 搜索 Lucene 语法问题及多场景优化

Ai

解决 Azure AI 搜索中 Lucene 查询语法问题

最近在使用 Azure AI 搜索进行向量搜索时遇到了一些问题。索引包含 30 个特征,我想使用 Lucene 语法进行文本搜索,但发现它的行为和我预想的不太一样。

具体来说,在使用 Python 的 SearchClient 发起请求时:

filters = "Thickness ge 6"

text = "Color:WHITE"

results = search_client.search(
    query_type="full",
    search_text=text,
    vector_queries=vector_query,
    filter=filters,
    select=retrievable_field_names,  # all the fields
    top=15
)

我希望 “Color” 特征的值包含 “WHITE” 的文档能获得更高的分数。之所以没把 “Color” 放到 filter 里,是因为 “Color” 的值有时会包含 “WHITE” 以外的其他内容。

但实际上,不仅 “Color” 包含 “WHITE” 的文档得分高,其他特征(比如 “Collections”)包含 “WHITE” 的文档得分也会变高。这不是我想要的结果。

问题原因分析

问题的根源在于 Azure AI 搜索在 query_type="full" (即使用 Lucene 查询语法)时,search_text 参数的处理方式。 当我们使用像 Color:WHITE 这样的查询时,Azure AI Search 会执行以下操作:

  1. 字段限定搜索: Color:WHITE 意味着搜索"Color"字段中包含"WHITE"的文档.
  2. 非精确匹配: 默认情况下,搜索不是“精确匹配”。只要 “Color” 字段包含 “WHITE” 这个词条(token),就算匹配成功。Azure AI Search 会将字段值进行分词。例如, "Color:WHITE RED"也会匹配。
  3. 多字段boost问题: Azure AI Search 的评分机制会对匹配到的所有字段进行综合评分,如果在其他字段中也发现了 "WHITE",那么总体的得分也会变高。

解决方案

针对这个问题, 我摸索了几种不同的解决方法,分别适用于不同场景:

1. 使用双引号进行短语搜索

如果希望 "WHITE" 是一个完整的短语,而不是单独的单词, 可以用双引号括起来:

text = 'Color:"WHITE"'
  • 原理: 双引号表示短语搜索,要求 “WHITE” 作为一个整体出现在 “Color” 字段中。
  • 适用场景: 当你希望 "WHITE" 作为一个整体出现在 Color 特征中,且不希望出现因为分词出现匹配扩大。 比如“SNOW WHITE”不会被匹配,只有 “WHITE” 才会被匹配.
  • 代码示例:
filters = "Thickness ge 6"
text = 'Color:"WHITE"' # 使用双引号

results = search_client.search(
    query_type="full",
    search_text=text,
    vector_queries=vector_query,
    filter=filters,
    select=retrievable_field_names,
    top=15
)

2. 使用 filter 参数过滤 "Color" 字段

如果确定要筛选 Color 字段为 "WHITE" 的,最直接的方法是使用 filter 参数:

filters = "Thickness ge 6 and Color eq 'WHITE'"
  • 原理: filter 参数进行的是精确匹配。只有 Color 字段的值完全等于 WHITE 的文档才会被返回。
  • 代码示例:
filters = "Thickness ge 6 and Color eq 'WHITE'"  # Color 精确匹配
text = "*" #所有文档,或者根据其他非Color特征的进行向量搜索的内容。

results = search_client.search(
    query_type="full",
    search_text=text,
    vector_queries=vector_query,
    filter=filters,
    select=retrievable_field_names,
    top=15
)
  • 进阶用法
    如果你的Color可能包含多个颜色,用逗号分隔, 比如 "WHITE,BLACK,RED",你想找到包含"WHITE"的, 可以使用search.ismatch
filters = "Thickness ge 6 and search.ismatch('WHITE', 'Color', 'simple', 'any')"
  • 原理 : search.ismatch 函数可以在指定的字段中查找是否包含给定的字符串,可以处理更复杂的场景。 'any' 表示只要有一个匹配就返回 true

3. 组合使用 search_text 和 filter

可以将 search_textfilter 结合起来,实现更灵活的查询:

filters = "Thickness ge 6"
text = "Color:WHITE"

然后, 在filter里可以做进一步细化,只让部分特征可以有额外boost.
假设, 除了Color以外, 你还想对Material这个特征进行搜索(但不做filter), 可以使用 search.ismatch 针对 Material进行加权. 假设,Collection不希望boost, 就可以不做处理.

#假设除了Color:WHITE, 还想在Material里搜索RED:
text = "Color:WHITE Material:RED"
  • 原理: 利用 search_text 进行主要内容的检索, 使用filter 做更精细的限定。
  • 适用场景 多特征查询的常用模式

4. 使用 wildcard 查询

如果希望在 "Color" 中寻找以 “WHITE” 开头的值(例如 "WHITE-A", "WHITE-B"),可以使用通配符查询:

text = "Color:WHITE*"
  • 原理: * 代表零个或多个字符。
  • 适用场景: 模糊匹配特定模式的字符串.
  • 代码示例:
filters = "Thickness ge 6"
text = "Color:WHITE*"

results = search_client.search(
    query_type="full",
    search_text=text,
    vector_queries=vector_query,
    filter=filters,
    select=retrievable_field_names,
    top=15
)

5. 自定义评分配置文件 (Scoring Profile)

如果以上方法都不能完全满足需求,可以考虑自定义评分配置文件。 这样能够对不同字段的匹配情况赋予不同的权重。

  • 原理 : Azure AI 搜索允许自定义 scoring profile。我们可以通过配置,对 Color 字段匹配的文档给予更高的权重。
  • 进阶技巧 : 这需要对 Azure AI Search 的 scoring profiles 有比较深入的了解。 可以定义不同的 boosting 函数,根据自己的需求对匹配度进行更精细的调整。

在索引定义中创建一个scoring profile:

{
  "name": "myIndex",
  "fields": [
    { "name": "Color", "type": "Edm.String", "searchable": true, "filterable": true, "retrievable": true },
    { "name": "Material", "type": "Edm.String", "searchable": true, "filterable": false, "retrievable": true },
	{ "name": "Collection", "type": "Edm.String", "searchable": true, "filterable": false, "retrievable": true },
    { "name": "Thickness", "type": "Edm.Int32", "filterable": true, "retrievable": true }
  ],
  "scoringProfiles": [
    {
      "name": "colorBoost",
      "text": {
        "weights": {
          "Color": 5,
          "Material" : 2,
		  "Collection": 1
        }
      }
    }
  ],
  "defaultScoringProfile": "colorBoost"
}

然后在查询时指定使用 colorBoost 配置文件.

filters = "Thickness ge 6"
text = "Color:WHITE Material:RED"

results = search_client.search(
  query_type="full",
  search_text=text,
  vector_queries=vector_query,
  filter=filters,
  select=retrievable_field_names,
  top=15,
  scoring_profile="colorBoost"
)
  • 说明 : 这里我们将 Color 字段的权重设置为 5, Material权重设置为2, 其余的(包括Collection)设置为1(默认).

安全建议

在使用通配符查询时,特别是以 * 开头的查询(例如 *WHITE),需要注意性能问题。这种查询可能会消耗较多的资源, 在数据量非常大时可能会很慢。
一般不建议允许用户输入以 * 开头的查询。
如果使用自定义评分,一定要控制好各个特征的权重,防止权重过高/过低,影响最终效果。