You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Milvus中高效存储大规模布尔数组并支持检索过滤

优化门店库存存储与过滤的解决方案

针对布尔数组存储占用过高、需保留按门店ID过滤的需求,结合80%产品多数门店有货的业务特征,提供以下高效方案:

方案1:反转存储逻辑 - 仅存储缺货门店ID列表

由于多数产品在大部分门店有货,只记录缺货的门店ID而非全量布尔数组,可大幅压缩存储空间。

实现细节:

  1. 修改Milvus Schema:
product_id = FieldSchema(
    name="product_id", 
    dtype=DataType.INT64, 
    is_primary=True,
    auto_id=False
)

product_title_vector = FieldSchema(
    name="product_title_vector", 
    dtype=DataType.FLOAT_VECTOR,
    dim=768,
)

# 替换原布尔数组为存储缺货门店ID的INT64数组
out_of_stock_stores = FieldSchema(
    name="out_of_stock_stores", 
    dtype=DataType.ARRAY, 
    element_type=DataType.INT64,
    max_capacity=600  # 按20%缺货率预设,可根据实际业务调整
)
  1. 数据写入规则:
    每个产品仅收集缺货的门店ID存入out_of_stock_stores;若全门店有货,该字段为空数组。

  2. 检索过滤逻辑:
    查询指定门店有货的产品时,判断门店ID不在缺货列表中即可:

store_id = 1
# 过滤表达式:门店ID不在缺货列表内
filter_expr = "NOT contains(out_of_stock_stores, {})".format(store_id)

search_params = {"metric_type": "L2", "params": {"nprobe": 16}}
search_results = collection.search(
    data=query_vector_resized,
    anns_field="product_title_vector",
    expr=filter_expr,
    param=search_params,
    limit=1
)

空间优势:

按80%产品缺货门店数少于10个计算,单条记录平均占用80字节(10个INT64),500万条仅需40GB;对比原方案的15GB?不对——哦原方案3000个BOOL按字节存储是3KB/条,500万条15GB,此方案多数记录远小于3KB,整体存储量会显著低于原方案。若门店扩容至40000,原方案需200GB,此方案仍能保持较低存储规模。

方案2:位图压缩存储 - 将布尔数组打包为整数数组

把门店库存的布尔状态打包成64位整数的数组,每个整数存储64个门店的状态,大幅降低存储空间。

实现细节:

  1. 修改Milvus Schema:
product_id = FieldSchema(
    name="product_id", 
    dtype=DataType.INT64, 
    is_primary=True,
    auto_id=False
)

product_title_vector = FieldSchema(
    name="product_title_vector", 
    dtype=DataType.FLOAT_VECTOR,
    dim=768,
)

# 用INT64数组存储位图,3000门店需ceil(3000/64)=47个INT64;40000门店需625个
store_availability_bitmap = FieldSchema(
    name="store_availability_bitmap", 
    dtype=DataType.ARRAY, 
    element_type=DataType.INT64,
    max_capacity=47
)
  1. 数据写入转换:
    将布尔数组转换为位图整数:
def bool_array_to_bitmap(bool_array):
    bitmap = []
    for i in range(0, len(bool_array), 64):
        chunk = bool_array[i:i+64]
        value = 0
        for idx, val in enumerate(chunk):
            if val:
                value |= (1 << idx)
        bitmap.append(value)
    return bitmap

# 示例:将3000个布尔值转换为位图
bool_array = [True]*3000
bitmap = bool_array_to_bitmap(bool_array)
  1. 检索过滤逻辑:
    计算门店对应的位图索引和位位置,用位运算判断库存状态:
store_id = 1
store_idx = store_id - 1  # 转换为0-based索引
array_idx = store_idx // 64
bit_pos = store_idx % 64

# 过滤表达式:对应位为1表示有货
filter_expr = "(store_availability_bitmap[{}] & (1 << {})) != 0".format(array_idx, bit_pos)

search_params = {"metric_type": "L2", "params": {"nprobe": 16}}
search_results = collection.search(
    data=query_vector_resized,
    anns_field="product_title_vector",
    expr=filter_expr,
    param=search_params,
    limit=1
)

空间优势:

3000门店单条记录仅需376字节(47个INT64),仅为原方案的12.5%,500万条仅需1.88GB;40000门店单条记录需5KB(625个INT64),500万条仅需25GB,存储压力大幅降低。

方案3:分离向量与库存数据(备选)

若允许检索后二次过滤,可将产品向量存在Milvus,库存数据存入关系型数据库(如MySQL),Milvus检索得到product_id后,再去数据库查询对应门店的库存状态。此方案无法使用Milvus的expr过滤,适合实时性要求稍低的场景。

实现步骤:

  1. Milvus Schema仅保留product_id和product_title_vector;
  2. MySQL创建表:product_stores(product_id INT64, store_id INT64, is_available BOOL),并为(product_id, store_id)建立联合索引;
  3. Milvus检索得到product_id列表后,执行SQL查询:SELECT product_id FROM product_stores WHERE product_id IN (...) AND store_id = ? AND is_available = true。

内容的提问来源于stack exchange,提问作者Mohamed Niyaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:19:58