
本文详解如何在 Qdrant 中正确过滤嵌套于 payload 数组内的对象字段(如 attributes[].attribute_value_id),支持按多个属性 ID 分组匹配其对应值列表,实现精准 AND/OR 混合语义过滤。
本文详解如何在 qdrant 中正确过滤嵌套于 payload 数组内的对象字段(如 `attributes[].attribute_value_id`),支持按多个属性 id 分组匹配其对应值列表,实现精准 and/or 混合语义过滤。
在 Qdrant 中对结构化嵌套数据(尤其是列表型 payload 字段)进行高效、语义准确的过滤,是构建商品搜索、内容推荐等场景的关键能力。以典型电商数据为例,attributes 是一个字典列表,每个元素代表一个属性键值对:
"attributes": [
{ "attribute_value_id": 22003, "id": 1252, "key": "Environment", "value": "Casual/Daily" },
{ "attribute_value_id": 98763, "id": 1254, "key": "Color", "value": "Multicolored" },
{ "attribute_value_id": 22040, "id": 1255, "key": "Material", "value": "Polyester" }
]前端传入的过滤参数形如:{"1254": ["98763"], "1255": ["22040", "22041"]} —— 表示需同时满足:
✅ attributes 列表中存在至少一个对象,其 attribute_value_id 为 98763(对应 Color 属性);
✅ 且另存在至少一个对象,其 attribute_value_id 为 22040 或 22041(对应 Material 属性)。
关键在于:不同 attr_id 之间是逻辑 AND 关系(必须全部满足),而同一 attr_id 下的多个 attr_value_id 是逻辑 OR 关系(满足任一即可)。
Qdrant 原生支持通过 [] 语法遍历数组字段,配合 MatchAny 即可优雅实现该需求。正确写法如下:
from qdrant_client import models
filters_list = []
# 处理品牌过滤(已有逻辑,保持不变)
brands = param_filters.get("brand_params")
if brands:
filters_list.append(
models.FieldCondition(
key="brand.id",
match=models.MatchAny(any=[int(b) for b in brands])
)
)
# 处理 attributes 过滤(核心逻辑)
attrs = param_filters.get("attr_params")
if attrs:
for attr_id, attr_value_ids in attrs.items():
# 将字符串 ID 转为整数(Qdrant payload 中字段类型需严格匹配)
int_values = [int(v) for v in attr_value_ids]
# 使用 'attributes[].attribute_value_id' 遍历数组中每个对象的 attribute_value_id 字段
# MatchAny 实现 OR 语义:只要数组中任一对象的 attribute_value_id 匹配列表中任一值即通过
filters_list.append(
models.FieldCondition(
key="attributes[].attribute_value_id",
match=models.MatchAny(any=int_values)
)
)
# 执行搜索:must 列表要求所有 filter 同时为 True → 实现跨 attr_id 的 AND 语义
search_results = qd_client.search(
collection_name=f"lang{lang}_products",
query_vector=query_vector,
query_filter=models.Filter(must=filters_list),
search_params=models.SearchParams(hnsw_ef=128, exact=False),
limit=limit
)? 重要注意事项:
- ✅ key="attributes[].attribute_value_id" 是唯一正确的路径写法:[] 显式声明对数组元素进行“展开遍历”,而非尝试访问不存在的 attributes.1254.attribute_value_id;
- ❌ 不要尝试扁平化为 {"1254": 98763} 或类似结构——这会破坏原始语义,且 Qdrant 不支持对数组内字典的动态 key 进行匹配(即无法用 MatchAny 判断 "1254" in flattened_attributes[*].keys());
- ⚠️ 确保 payload 中 attribute_value_id 字段类型与查询值一致(如均为 integer),否则 MatchAny 可能静默失败;
- ? 若需同时约束 key 和 value(例如:key == "Color" AND value == "Red"),应改用 models.Filter 嵌套组合 FieldCondition + Must,但本例仅需 attribute_value_id 即可唯一标识属性值,故无需复杂嵌套。
此方案简洁、高效,完全依托 Qdrant 原生过滤能力,无需预处理数据结构或引入额外索引,是处理 JSON 数组嵌套字段过滤的标准实践。

















