头图

作者:蔡宇东

编者按:
Milvus 2.0 带来了不少新功能。在这些新功能中,时间旅行(time travel)、属性过滤和删除操作相互关联,因为这三个功能是通过一个共同的机制——Bitset 实现的。Milvus 研发工程师蔡宇东将为大家解析 Milvus 中 Bitset 的概念,并通过三个例子解释它是如何支持删除操作、时间旅行和属性过滤的。

什么是 Bitset?

从 Milvus 0.7.0 版本开始,为了支持 Delete 功能,我们引入了 Bitset,用于标记 segment 中的每行 entity 是否已被删除(若 Bitset 对应的 bit 位为 1,表明该行 entity 已被删除,该行 entity 在查询时不参与运算)。
在 Milvus 2.0 版本,我们进一步扩展了 Bitset 的使用。Bitset 最基本的语义保持不变——若对应的 bit 位为 1,表明该行 entity 不参与查询运算。但 Bitset 的使用不再局限于 Delete 操作,有 3 种操作会影响 Bitset,它们分别是:

  1. 属性过滤
  2. 数据删除
  3. 时间旅行

在 Milvus 中,Bitset 是如何计算的?

接下来,我们用三个例子来说明 Bitset 是如何计算的。
假设有 1 个 segment ,我们对这个 segment 依次执行了 3 次 DML(data manipulation language)操作:
image.png
Order of DML events

  • 在 ts = 100 时,执行插入操作,插入了 4 条 entity,它们的 primary_keys 分别为 [1, 2, 3, 4];
  • 在 ts = 200 时,执行第二次插入操作,插入另外 4 条 entity,它们的 primary_keys 分别为 [5, 6, 7, 8];
  • 在 ts = 300 时,执行 Delete 操作,删除了 2 条 entity,它们的 primary_key 分别为 [7, 8]。
  • 同时假设在进行查询时,通过属性过滤得到的结果为 primary_key = [1, 3, 5, 7] 。

案例一

image.png
Search with time_traval = 150
假设用户执行第一次查询,指定time_travel = 150。Bitset 的计算过程如上图所示。
filter_bitset 初始状态为 [1, 0, 1, 0, 1, 0, 1, 0] (此时 bit 位为 1 表示有效),因为查询时指定的 time_travel = 150,该时刻 pk = [5, 6, 7, 8] 的 entity 还没有插入,所以 pk = [5, 6, 7, 8] 的 entity 在 Bitset 中对应 bit 位都要清零。计算得到 filter_bitset_2 = [1, 0, 1, 0, 0, 0, 0, 0]。又因为最终结果 bitset 中的 1 应该表示该行 entity 无效,所以需要对 filter_bitset_2 中所有 bit 位取反,得到 filter_bitset_3 = [0, 1, 0, 1, 1, 1, 1, 1]。
del_bitset 初始状态为 [0, 0, 0, 0, 0, 0, 1, 1],考虑查询时指定的 time_travel = 150,该时刻 delete 操作还没有执行,所以 Bitset 所有 bit 位都应该清零,表示所有的数据都是有效的。这样就得到了 del_bitset_2 = [0, 0, 0, 0, 0, 0, 0, 0]。
把 filter_bitset_3 和 del_bitset_2 进行 OR 操作,可得到最终 result_bitset = [0, 1, 0, 1, 1, 1, 1, 1]。
最终,我们会用 result_bitset 去参与查询运算。

案例二

image.png

Search with time_traval = 250
假设用户执行第二次查询,指定time_travel = 250。Bitset 的计算过程如上图所示。
与第一个案例一样,filter_bitset 初始状态应该是 [1, 0, 1, 0, 1, 0, 1, 0]。
当 ts = 250 时,所有 entity [1, 2, 3, 4, 5, 6, 7, 8] 已经被插入到 Milvus 中。因此,filter_bitset_2和之前 filter_bitset 的结果保持不变。同样,我们要对 filter_bitset_2 的所有 bit 位取反,得到 [0, 1, 0, 1, 0, 1, 0, 1]。
del_bitset 初始状态为 [0, 0, 0, 0, 0, 1, 1]。同样考虑查询时指定的 time_travel = 250,该时刻 delete 操作还没有执行,所以 Bitset 所有 bit 位都应该清零,表示所有的数据都是有效的。因此,time travel 后的 del_bitset_2 = [0, 0, 0, 0, 0, 0, 0]。
把 filter_bitset_3 和 del_bitset_2 进行 OR 操作,可得到最终 result_bitset = [0, 1, 0, 1, 0, 1, 0, 1]。
最终只有 entities [1, 3, 5, 7] 会参与之后的查询运算。

案例三

假设用户执行第三次查询,指定time_travel = 350。那么,Bitset 的计算过程是什么样的?参考上方两个案例进行思考。
image.png

预告

不久之前,我们还介绍了 Milvus 2.0 中的数据删除设计。
在接下来的文章中,我们将继续介绍 Milvus 2.0 中数据压缩、动态负载均衡等功能背后的逻辑,欢迎大家继续关注!

Milvus 项目地址:https://github.com/milvus-io/...
Milvus 主页及文档地址:https://milvus.io/
Milvus Slack Channel:milvusio.slack.com


Zilliz
154 声望829 粉丝

Vector database for Enterprise-grade AI