✏️ 编者按:
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,它们分别是:
- 属性过滤
- 数据删除
- 时间旅行
在 Milvus 中,Bitset 是如何计算的?
接下来,我们用三个例子来说明 Bitset 是如何计算的。
假设有 1 个 segment ,我们对这个 segment 依次执行了 3 次 DML(data manipulation language)操作:
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]
。
案例一
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
去参与查询运算。
案例二
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 的计算过程是什么样的?参考上方两个案例进行思考,点击下方的空白显示提示。
你想对了吗?