Биты
В этой теме рассказывается о механизме битовых наборов, который позволяет реализовать в Milvus такие ключевые функции, как фильтрация атрибутов и операции удаления.
Обзор
Набор битов - это набор битов. Биты - это элементы, имеющие только два возможных значения, чаще всего 0
и 1
, или булевы значения true
и false
. В Milvus наборы битов - это массивы битовых чисел 0
и 1
, которые могут использоваться для компактного и эффективного представления определенных данных, в отличие от интов, плавающих чисел или символов. По умолчанию битовое число имеет значение 0
и устанавливается в значение 1
только в том случае, если оно удовлетворяет определенным требованиям.
Операции над наборами битов выполняются с помощью булевой логики, в соответствии с которой выходное значение является либо допустимым, либо недопустимым, также обозначаемым 1
и 0
соответственно. Например, логический оператор AND
может использоваться для сравнения двух битовых наборов, основанных на элементах в одинаковых индексных позициях, и выдает новый битовый набор с результатами. Если два элемента в позиции одинаковы, то в новом битовом наборе в этой позиции будет записан 1
, если различны - 0
.
Реализация
Биты - это простой, но мощный механизм, который помогает Milvus выполнять фильтрацию атрибутов, удаление данных и запросы с помощью Time Travel.
Фильтрация атрибутов
Поскольку битовые наборы содержат только два возможных значения, они идеально подходят для хранения результатов фильтрации атрибутов. Данные, удовлетворяющие требованиям заданного фильтра атрибутов, помечаются 1
.
Удаление данных
Битовые наборы служат компактным способом хранения информации о том, удалена ли строка в сегменте. Удаленные сущности помечаются 1
в соответствующем битовом наборе, который не будет вычисляться во время поиска или запроса.
Примеры
Здесь мы приводим три примера, иллюстрирующие использование битовых наборов в Milvus, со ссылками на все три основные реализации битовых наборов, рассмотренные выше. Во всех трех случаях имеется сегмент с 8 сущностями, а затем происходит серия событий языка манипулирования данными (DML) в порядке, показанном ниже.
- Четыре сущности, чьи
primary_key
s равны [1, 2, 3, 4] соответственно, вставляются, когда временная меткаts
равна 100. - Остальные четыре сущности, чьи
primary_key
s равны [5, 6, 7, 8], вставляются, когда временная меткаts
равна 200. - Сущности, чьи
primary_key
s равны [7, 8], удаляются, когда временная меткаts
равна 300. - Условиям фильтрации атрибутов удовлетворяют только сущности, чьи
primary_key
s равны [1, 3, 5, 7].
Порядок событий DML
Случай первый
В этом случае пользователь задает time_travel
равным 150, что означает, что он выполняет запрос к данным, удовлетворяющим ts = 150
. Процесс формирования набора битов показан на рисунке 1.
На начальном этапе фильтрации filter_bitset
должен быть [1, 0, 1, 0, 1, 0, 1, 0]
, где сущности [1, 3, 5, 7] отмечены как 1
, поскольку они являются действительными результатами фильтрации.
Однако сущности [4, 5, 6, 7] не были вставлены в базу данных векторов, когда ts
равнялся 150. Поэтому эти четыре сущности должны быть помечены как 0 независимо от условия фильтрации. Теперь результат набора битов должен быть [1, 0, 1, 0, 0, 0, 0, 0]
.
Как обсуждалось в разделе "Удаление данных", сущности, помеченные 1
, игнорируются при поиске или запросе. Теперь результат набора битов нужно перевернуть, чтобы объединить с битовой картой удаления, что дает нам [0, 1, 0, 1, 1, 1, 1, 1]
.
Что касается битового набора удаления del_bitset
, то его начальным значением должно быть [0, 0, 0, 0, 0, 0, 1, 1]
. Однако сущности 7 и 8 не удаляются до тех пор, пока ts
не станет равным 300. Поэтому, когда ts
равно 150, сущности 7 и 8 все еще действительны. В результате значение del_bitset
после путешествия во времени равно [0, 0, 0, 0, 0, 0, 0, 0]
.
Теперь у нас есть два набора битов после Путешествия во времени и фильтрации атрибутов: filter_bitset
[0, 1, 0, 1, 1, 1, 1, 1]
и del_bitset
[0, 0, 0, 0, 0, 0, 0, 0]
. Объединим эти два набора битов с помощью оператора двоичной логики OR
. Конечное значение result_bitset равно [0, 1, 0, 1, 1, 1, 1, 1]
, что означает, что на следующем этапе поиска или запроса будут вычислены только сущности 1 и 3.
Рисунок 1. Поиск с перемещением во времени = 150.
Случай второй
В этом случае пользователь задает time_travel
равным 250. Процесс генерации набора битов показан на рисунке 2.
Как и в первом случае, начальным filter_bitset
является [1, 0, 1, 0, 1, 0, 1, 0]
.
Все сущности находятся в базе данных вектора, когда ts
= 250. Таким образом, filter_bitset
остается неизменным, когда мы учитываем временную метку. Снова нужно перевернуть результат и получить [0, 1, 0, 1, 0, 1, 0, 1]
.
Что касается набора битов удаления del_bitset
, то его начальное значение - [0, 0, 0, 0, 0, 0, 1, 1]
. Однако сущности 7 и 8 не были удалены до тех пор, пока ts
не станет равным 300. Поэтому, когда ts
равно 250, сущности 7 и 8 все еще действительны. В результате после путешествия во времени del_bitset
будет [0, 0, 0, 0, 0, 0, 0, 0]
.
Теперь у нас есть два набора битов после Путешествия во времени и фильтрации атрибутов: filter_bitset
[0, 1, 0, 1, 0, 1, 0, 1]
и del_bitset
[0, 0, 0, 0, 0, 0, 0, 0]
. Объединим эти два набора битов с помощью оператора двоичной логики OR
. Результат_битового набора - [0, 1, 0, 1, 0, 1, 0, 1]
. Иными словами, на следующем этапе поиска или запроса будут вычислены только энтитеты [1, 3, 5, 7].
Рисунок 2. Поиск с временным перемещением = 250.
Третий случай
В этом случае пользователь задает time_travel
равным 350. Процесс генерации набора битов проиллюстрирован на рисунке 3.
Как и в предыдущих случаях, начальным filter_bitset
является [0, 1, 0, 1, 0, 1, 0, 1]
.
Все сущности находятся в базе данных вектора, когда ts
= 350. Поэтому конечный, перевернутый filter_bitset
- это [0, 1, 0, 1, 0, 1, 0, 1]
, как и во втором случае.
Что касается битового набора удаления del_bitset
, то поскольку сущности 7 и 8 уже были удалены при ts = 350
, поэтому результатом del_bitset
будет [0, 0, 0, 0, 0, 0, 1, 1]
.
Теперь у нас есть два набора битов после путешествия во времени и фильтрации атрибутов: filter_bitset
[0, 1, 0, 1, 0, 1, 0, 1]
и del_bitset
[0, 0, 0, 0, 0, 0, 1, 1]
. Объединим эти два набора битов с помощью оператора двоичной логики OR
. Конечный result_bitset
- это [0, 1, 0, 1, 0, 1, 1, 1]
. Иными словами, на следующем этапе поиска или запроса будут вычислены только сущности [1, 3, 5].
Рисунок 3. Поиск с перемещением во времени = 350.
Что дальше
Теперь, когда вы знаете, как работают битовые наборы в Milvus, вы также можете захотеть:
- Узнать, как использовать строки для фильтрации результатов поиска, или обратиться к разделу "Гибридный поиск" в нашей документации.
- Понять , как обрабатываются данные в Milvus.