解决 Azure AI 搜索 Lucene 语法问题及多场景优化
2025-03-23 20:56:27
解决 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 会执行以下操作:
- 字段限定搜索:
Color:WHITE
意味着搜索"Color"字段中包含"WHITE"的文档. - 非精确匹配: 默认情况下,搜索不是“精确匹配”。只要 “Color” 字段包含 “WHITE” 这个词条(token),就算匹配成功。Azure AI Search 会将字段值进行分词。例如, "Color:WHITE RED"也会匹配。
- 多字段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_text
和 filter
结合起来,实现更灵活的查询:
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
),需要注意性能问题。这种查询可能会消耗较多的资源, 在数据量非常大时可能会很慢。
一般不建议允许用户输入以 *
开头的查询。
如果使用自定义评分,一定要控制好各个特征的权重,防止权重过高/过低,影响最终效果。