Skip to main content
Тип данных QBit реорганизует хранение векторов, чтобы ускорить приближенный поиск. Вместо того чтобы хранить элементы каждого вектора вместе, он группирует одинаковые позиции битов во всех векторах. При этом векторы хранятся с полной точностью, а во время поиска вы можете выбирать уровень квантования: считывать меньше битов, чтобы сократить I/O и ускорить вычисления, или больше битов для более высокой точности. Это дает выигрыш в скорости за счет уменьшения объема передаваемых данных и вычислений благодаря квантованию, при этом все исходные данные при необходимости остаются доступными. Чтобы объявить столбец типа QBit, используйте следующий синтаксис:
  • element_type – тип каждого элемента вектора. Допустимые типы: Int8, BFloat16, Float32 и Float64
  • dimension – размерность, то есть число элементов в каждом векторе
  • stride – необязательный параметр. Число размерностей, хранящихся вместе в одной группе потоков. Если не указано, по умолчанию используется dimension (одна группа). Если указано, dimension должно быть кратно stride, а если stride меньше dimension, то stride должно быть кратно 8. Размерности dimension разбиваются на dimension / stride последовательных групп, а битовые плоскости каждой группы хранятся в отдельных потоках. Это позволяет при поиске по первым D размерностям (где D кратно stride) считывать только потоки тех групп, которые охватывают эти размерности, что полезно для эмбеддингов Matryoshka.

Создание QBit

Использование типа QBit при определении столбца таблицы:

Преобразование массивов в QBit

Массивы преобразуются в QBit, если длина массива соответствует размерности QBit. Тип элементов массива не обязательно должен совпадать с типом элементов QBit. Любой числовой тип элементов автоматически преобразуется в нужный тип. Это позволяет напрямую перенести существующий столбец эмбеддингов в столбец QBit:
Явное преобразование также работает с CAST, например CAST(embedding AS QBit(Float32, 8)).

Преобразование QBit в массивы

Обратное преобразование восстанавливает исходный вектор из битово-транспонированного представления, поэтому приведение QBit к Array возвращает сохранённые значения. Это обратная операция к преобразованию массивов в QBit:
Восстановленный массив использует тип элементов QBit, после чего его элементы преобразуются в запрошенный тип элементов массива. Поэтому работает и приведение, которое одновременно меняет тип элементов, например из QBit(Float32, N) в Array(Float64). Преобразование по цепочке Array -> QBit -> Array не приводит к потере данных для Int8, Float32 и Float64. Для BFloat16 оно соответствует прямому преобразованию в BFloat16 — единственная потеря точности связана с самим BFloat16. Когда dimension не кратна 8, конечные элементы дополнения, присутствующие во внутреннем представлении, отбрасываются, поэтому результат всегда содержит ровно dimension элементов.

Преобразование между типами QBit

QBit можно привести к другому QBit, если размерность (число элементов вектора) остается прежней. При этом и element_type, и stride могут изменяться; приведение к QBit с другой размерностью вызывает исключение, поскольку это привело бы к изменению самого вектора. Изменение element_type заново строит вектор и преобразует каждый элемент в новый тип, в точности как при соответствующем преобразовании Array: расширение (например, из QBit(Float32, N) в QBit(Float64, N)) происходит без потери точности, тогда как сужение приводит к потере точности так же, как и сужающее приведение Array.
Изменение только stride (при сохранении того же element_type) перегруппировывает сохранённые битовые плоскости, не затрагивая значения, поэтому потерь данных не возникает:

Подстолбцы QBit

QBit реализует шаблон доступа к подстолбцам, который позволяет обращаться к отдельным битовым плоскостям сохранённых векторов. Доступ к каждой битовой позиции можно получить с помощью синтаксиса .N, где N — это позиция бита:
Количество доступных подстолбцов зависит от типа элементов (а при использовании stride — от числа групп stride):
  • Int8: 8 подстолбцов на группу stride (1-8)
  • BFloat16: 16 подстолбцов на группу stride (1-16)
  • Float32: 32 подстолбца на группу stride (1-32)
  • Float64: 64 подстолбца на группу stride (1-64)
Подстолбцы упорядочены в порядке групп: в общем случае vec.N считывает битовую плоскость (N-1) % element_size группы stride (N-1) / element_size. Например, в QBit(BFloat16, 4096, 1024) 4096 размерностей разбиваются на 4 группы по 1024, поэтому всего получается 64 подстолбца: vec.1vec.16 — это битовые плоскости первой группы stride (размерности 1–1024), vec.17vec.32 относятся ко второй группе (размерности 1025–2048), и так далее.

Страйды

По умолчанию QBit хранит каждую битовую плоскость как один поток, охватывающий все dimension размерностей, поэтому при поиске всегда считываются целые битовые плоскости по всему вектору. Необязательный параметр stride разбивает dimension размерностей на dimension / stride последовательных групп и хранит битовые плоскости каждой группы в отдельных потоках. Это позволяет при поиске только по первым D размерностям (где D кратно stride) считывать только потоки тех групп, которые покрывают эти размерности, — это полезно для эмбеддингов Matryoshka, где начальные размерности образуют пригодный для использования эмбеддинг меньшей размерности.
Здесь 4096 размерностей разбиты на 4 группы по 1024. Подстолбцы идут в порядке групп: для BFloat16 (16 битовых плоскостей) vec.1vec.16 — это 16 битовых плоскостей первой группы stride (размерности 1–1024), vec.17vec.32 относятся ко второй группе (размерности 1025–2048) и так далее. В общем случае vec.N считывает битовую плоскость (N-1) % element_size группы stride (N-1) / element_size. Чтобы выполнить поиск с уменьшенной размерностью, передайте число считываемых размерностей в качестве четвёртого аргумента транспонированных функций расстояния (см. ниже). Опорный вектор должен содержать как минимум столько элементов (любые дополнительные конечные элементы игнорируются), а это значение должно быть кратно stride.

Функции векторного поиска

Это функции расстояния для поиска по векторному сходству, использующие тип данных QBit: Для QBit со stride эти функции принимают необязательный четвёртый аргумент used_dims — число начальных размерностей для чтения, — при этом читаются только группы stride, охватывающие эти размерности. Опорный вектор должен содержать как минимум used_dims элементов (любые дополнительные элементы в конце игнорируются, поэтому вектор запроса полной размерности можно повторно использовать для поиска в уменьшенной размерности, не обрезая его заранее), а used_dims должен быть кратен stride.
Последнее изменение 23 июля 2026 г.