使用嵌套对象字段进行 Qdrant 过滤

问题描述 投票:0回答:1

我在 Qdrant 上有一个数据结构,在有效负载中,我有这样的东西:


{
    "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",
        },
    ],
    "brand": {
        "id": 114326,
        "logo": None,
        "slug": "happiness-istanbul-114326",
        "title": "Happiness Istanbul",
    },
}

根据Qdrant文档,我实现了这样的品牌过滤:

filters_list = []
    if param_filters:
        brands = param_filters.get("brand_params")
        if brands:
            filter = models.FieldCondition(
                key="brand.id",
                match=models.MatchAny(any=[int(brand) for brand in brands]),
            )
            filters_list.append(filter)
        search_results = qd_client.search(
            query_filter=models.Filter(must=filters_list),
            collection_name=f"lang{lang}_products",
            query_vector=query_vector,
            search_params=models.SearchParams(hnsw_ef=128, exact=False),
            limit=limit,
        )

到目前为止有效。但是当我尝试过滤“属性”字段时,事情变得复杂。如您所见,它是一个字典列表,包含以下字典:

{
    "attribute_value_id": 22040,
    "id": 1255,
    "key": "Material",
    "value": "Polyester",
}

而前端发送过来的

attrs
过滤器就是这样的结构:

attrs structure: {"attr_id": [attr_value_ids], "attr_id": [att_value_ids]}
>>> example: {'1237': ['21727', '21759'], '1254': ['52776']}

如何过滤以查看查询过滤器参数中提供的

attr_id
(此处为
1237
1254
)是否存在于
attributes
字段中并且具有提供的
attr_value_id
之一在列表中(例如此处的
['21727', '21759']
)?

这是我迄今为止尝试过的:

if attrs:
            # attrs structure: {"attr_id": [attr_value_ids], "attr_id": [att_value_ids]}
            print("attrs from search function:", attrs)
            for attr_id, attr_value_ids in attrs.items():
                # Convert attribute value IDs to integers
                attr_value_ids = [
                    int(attr_value_id) for attr_value_id in attr_value_ids
                ]
                # Add a filter for each attribute ID and its values
                filter = models.FieldCondition(
                    key=f"attributes.{attr_id}.attr_value_id",
                    match=models.MatchAny(any=attr_value_ids),
                )
                filters_list.append(filter)

问题是

key=f"attributes.{attr_id}.attr_value_id",
是错误的,我不知道如何实现这一点。

更新:也许更接近一步:

我决定展平数据库中的数据,也许可以做得更好。首先,我创建了一个名为 flattened_attributes 的新字段,如下所示:

[
  {
    "1237": 21720
  },
  {
    "1254": 52791
  },
  {
    "1255": 22044
  },
]

此外,在过滤之前,我对前端发送的 attr 过滤器采用了相同的方法:

        if attrs:
            # attrs structure: {"attr_id": [attr_value_ids], "attr_id": [att_value_ids]}
            # we need to flatten attrs to filter on payloads
            flattened_attr = []
            for attr_id, attr_value_ids in attrs.items():
                for attr_value_id in attr_value_ids:
                    flattened_attr.append({attr_id:int(attr_value_id)})

现在,我有两个类似的字典列表,我想过滤那些至少有一个是从前端收到的(

flattened_attr
)。

有一种类型的过滤,如果键的值存在于值列表中,我们会进行过滤,如文档中提到的。但我不知道如何检查数据库中的 flattened_attributes

 字段中是否存在字典。

python python-3.x filtering qdrant
1个回答
0
投票
注意:主要问题的更新是一个错误的方法(或者只是我无法遵循它),我想出了另一种解决问题的方法。

注意主要问题中

attributes

 字段的结构,我们看到有一个 
attribute_value_id
 键,对于不同的属性,该键可能不同(例如,“颜色”为 1254,“材质”为 1255)。

因此,在

search

 函数中,我编写了以下代码(我将详细介绍它):

attrs = param_filters.get("attr_params") if attrs: # attrs structure: {"attr_id": [attr_value_ids], "attr_id": [attr_value_ids]} # we need to flatten attrs to filter on payloads for attr_id, attr_value_ids in attrs.items(): flattened_attr = [] for attr_value_id in attr_value_ids: flattened_attr.append(int(attr_value_id)) filter = models.FieldCondition( key="attributes[].attribute_value_id", match=models.MatchAny(any=flattened_attr), ) filters_list.append(filter) search_results = qd_client.search( query_filter=models.Filter(must=filters_list), collection_name=f"lang{lang}_products", query_vector=query_vector, search_params=models.SearchParams(hnsw_ef=128, exact=False), limit=limit, )
首先,对于每个

attr_id

,我创建了一个包含
attr_value_ids
的单独列表(我必须将它们转换为
int
)。

然后,使用 Qdrant 文档(

here),我使用 key="attributes[].attribute_value_id"

 浏览 
attributes
 字段内的列表项,并在每个列表项(每个都是字典)内查找 
attribute_value_id
 键,并匹配它与发送的值。

另请注意,我正在为每个 attr_id 创建一个单独的过滤器:

for attr_id, attr_value_ids in attrs.items(): flattened_attr = [] for attr_value_id in attr_value_ids: flattened_attr.append(int(attr_value_id)) filter = models.FieldCondition( key="attributes[].attribute_value_id", match=models.MatchAny(any=flattened_attr), ) filters_list.append(filter)
这是因为,当发送一个 attr_id 的多个值时,至少其中一个应该为 true(attribute_value_id 之间的

OR

),但是当发送另一个 attr_id 时,这个新的值和前一个值都应该为 true(每个 attr_id 之间的 
AND
)。另外,请注意,我在主过滤条件中使用 
must
,因此每个过滤器分别应为 
True
,而在每个过滤器内,任何 value_ids 都是可接受的。

qd_client.search( query_filter=models.Filter(must=filters_list), collection_name=f"lang{lang}_products", query_vector=query_vector, search_params=models.SearchParams(hnsw_ef=128, exact=False), limit=limit, )
    
© www.soinside.com 2019 - 2024. All rights reserved.