Релиз векторной базы данных 0.7.0: IVF-RaBitQ, DiskANN на io_uring и библиотека на 40% меньше
Обзор релиза 0.7.0 встраиваемой векторной базы данных: локальный поиск по рабочему пространству, интеграция с ReMe, квантованные и дисковые индексы, wheels для musllinux и DocIterator.
Версия 0.7.0 — большой релиз этой встраиваемой векторной базы данных. Изменения затронули четыре области: экосистему вокруг неё, алгоритмы индексов, способы развёртывания библиотеки и удобство в повседневной работе. Главное: CLI для поиска по рабочему пространству zvec-grep, интеграция с ReMe, IVF-RaBitQ, доведённый до продакшена DiskANN с io_uring и поддержкой ARM64, выбор AVX2 и AVX512 для RaBitQ во время выполнения, динамическая библиотека примерно на 40% меньше, wheels для musllinux, готовые бинарники SDK из CI, DocIterator и N-граммный токенизатор для полнотекстового поиска. Полные заметки к релизу лежат на странице GitHub-релиза проекта для тега v0.7.0.
Экосистема
zg: локальный поиск по рабочему пространству
Новая консольная утилита zvec-grep ищет по рабочему пространству целиком на вашей машине. За одним интерфейсом стоят три слоя:
- ripgrep — для быстрого поиска по строкам и регулярным выражениям
- BM25 с jieba — для лексического ранжирования
- векторный поиск HNSW — для смысловых запросов
Пользоваться ею должны и люди, и ИИ-агенты, а подключить к агентским процессам её можно через MCP. Тот, кто строит RAG по кодовой базе, памяти агента или документации, получает одну команду zg вместо нескольких склеенных между собой инструментов.
Интеграция с ReMe
База теперь работает как файловый бэкенд для ReMe — набора инструментов для управления памятью агентов. ReMe использует её для приближённого поиска ближайших соседей на HNSW внутри процесса по файлам памяти агента, так что приложения получают векторный поиск с низкой задержкой без запуска отдельного процесса базы.
Алгоритмы индексов
IVF-RaBitQ
RaBitQ впервые появился для индексов HNSW и Flat в прошлых версиях. В 0.7.0 он добрался до индексов IVF и дал ещё один способ пожертвовать небольшой долей полноты ради большой экономии памяти на данных масштаба миллиардов векторов.
Индекс IVF-RaBitQ разбивает векторы на кластеры в инвертированные списки, и каждый список квантуется через RaBitQ примерно до одного бита на измерение. Индекс остаётся компактным, но поддерживает переранжирование через refiner и скалярную фильтрацию и использует тот же API Query, что и раньше. Для нагрузок, которые подходят под профиль IVF, то есть крупных пакетных задач или поиска с ограниченной памятью, это часто самый дешёвый вариант.
SIMD-диспетчеризация для RaBitQ
RaBitQ теперь выбирает самый быстрый путь кода во время выполнения. На процессоре с AVX512 работают ядра AVX512, иначе AVX2, а скалярный код остаётся последним вариантом. Один бинарник может пользоваться новым железом без отдельных сборок и флагов компилятора.
DiskANN готов к продакшену
DiskANN был главной новинкой v0.5.0. Этот релиз делает его быстрее, надёжнее и доступнее на большем числе платформ.
Бэкенд io_uring. На Linux 5.3 и новее DiskANN предпочитает io_uring вместо libaio. Он обращается к ядру напрямую, поэтому для сборки не нужен liburing. Порядок отката такой: io_uring, затем libaio, затем pread, и при отсутствии бэкенда всё аккуратно деградирует.
Перекрывающийся асинхронный ввод-вывод и динамический beam. Лучевой поиск теперь совмещает работу процессора с чтением с диска и на ходу подстраивает ширину луча, чтобы диск был загружен, но не завален запросами. У нагрузок, упирающихся в диск, падает задержка. Связанное исправление дедупликации в visit-фильтре убирает лишние вставки кандидатов.
ARM64. DiskANN собирается и работает на Linux ARM64 и на Mac с Apple Silicon. На macOS используется синхронный pread с F_NOCACHE и отключённым упреждающим чтением, а CI на Linux прогоняет все бэкенды. Пограничные случаи вроде частичного или короткого чтения, EINTR и перехода между бэкендами обрабатываются безопасно.
Интроспекция. Активный бэкенд ввода-вывода кешируется и виден через API на C, C++ и Python, так что во время работы можно проверить, идут ли запросы через io_uring, libaio или pread.
Качество графа выросло
У Vamana появилась необязательная двухпроходная сборка. Быстрый первый проход строит грубый граф, второй его уточняет — хороший размен, когда полнота важнее времени сборки.
HNSW также умеет строить граф по исходным сырым векторам от провайдера индекса, даже если сам индекс хранит для поиска квантованную или преобразованную копию. Построение графа идёт с полной точностью, качество растёт, а память во время запросов остаётся небольшой.
Развёртывание
Похудевшая динамическая библиотека
Готовые разделяемые библиотеки на C и C++ на macOS ARM64 стали примерно на 40% меньше. Например, libzvec_c_api.dylib уменьшилась примерно с 37 до 22 МБ. Публичные API не изменились, скорость запросов тоже, а основной код поиска по-прежнему компилируется с -O3.
Экономия получилась за счёт трёх изменений:
- компиляция с
-ffunction-sections -fdata-sections, чтобы линкер выбрасывал неиспользуемый код - экспорт только собственных публичных символов библиотеки через
-exported_symbols_listили--version-script - полный отказ от protobuf в дереве зависимостей
Манифесты коллекций побайтово совместимы с прежним форматом protobuf. Сериализацией теперь занимаются небольшие внутренние кодировщик и декодер.
Wheels для musllinux
Появились официальные wheels для musllinux на x86_64 и ARM64, так что библиотека без проблем ставится на Alpine Linux и другие системы на musl. Для этого понадобилось несколько исправлений под musl. Большие SIMD-буферы убрали со стандартного стека потока в 128 КБ, а логгер стал синглтоном Майерса, чтобы не было повторных регистраций __cxa_atexit в разных разделяемых библиотеках.
Конвейер готовых SDK
Workflow GitHub Release теперь собирает готовые к использованию пакеты SDK для C и C++. Теги alpha, beta и RC автоматически помечаются как пре-релизы. Перед загрузкой каждый пакет проходит smoke-тест. Раннеры для десктопа и musl компилируют маленькие тестовые программы на C и C++ и запускают их против подготовленного SDK. Для Android проверка — это кросс-сборка, которая обязана слинковаться, а для iOS — осмотр обоих срезов XCFramework и раскладки заголовков.
Удобство
DocIterator
Тем, кто работает с памятью агентов и ETL, часто нужно пройти по всем документам коллекции без вектора запроса. Для этого есть DocIterator. При создании он делает снимок текущих сегментов и битовой карты удалений, так что последующие записи и удаления обходу не мешают. Он работает из C++, C и Python, а контроль доступа не даёт обходу и операциям обслуживания пересекаться.
На Python:
with collection.iter_docs(
output_fields=["title"], # only fetch needed scalar fields; primary key is always returned
include_vector=False,
) as docs:
for doc in docs:
print(doc.id, doc.fields["title"])
N-граммный токенизатор для FTS
В полнотекстовом поиске появился N-граммный токенизатор. Он индексирует перекрывающиеся последовательности символов длины n и не обращает внимания на границы слов. Это подходит для поиска фраз и подстрок в коротких текстах, идентификаторах в коде и строках логов, а также для языков, где границы слов определить сложно. Значение n задаётся через extra_params при создании FTS-индекса.
Производительность
- DiskANN совмещает работу процессора и диска в лучевом поиске, а динамическая ширина луча держит параллелизм на разумном уровне.
- RaBitQ выбирает ядра AVX512 или AVX2 во время выполнения, без единой жёстко заданной цели сборки.
- Удаление мёртвого кода в динамической библиотеке даёт бинарники поменьше, которые быстрее загружаются и занимают меньше резидентной памяти, а ядра поиска остаются на
-O3.
Прочие изменения и исправления
- Python API: новый
collection.close(), проверка пустых FTS-запросов,topkи неизвестных имён полей, аккуратнее работа с векторами NumPy. - C++ API: публичные имена теперь в стиле
snake_case. - C API: больше нет фиктивной строки версии
0.2.1, когда git-теги отсутствуют. - Корректность поиска: фильтры проверяются, устаревшее состояние фильтра сбрасывается, а инварианты кучи нельзя обойти.
- K-Means: исправлены веса выборки в сферическом K-MC2 и нормализация центроидов.
- Хранилище: обрабатываются несовпадающие границы скалярных пакетов, последний IPC-фрагмент в mmap-хранилище обрабатывается правильно, записываемые сегменты только с удалениями сохраняются, а осиротевшие и списанные каталоги сегментов чистятся при восстановлении после сбоя и на Windows.
- Коллекции: чтение и запись продолжаются, пока работает
Optimize. - Vamana: учитываются асимметричные метрики запросов.
- Сборка и CI: меньше экспортов из DLL на Windows, убраны устаревшие маркеры патчей сабмодулей, обновлены зависимости GitHub Actions, а проверки запускаются, когда черновой PR становится готовым.
Будущая работа над масштабируемостью хранилища, новыми алгоритмами и SDK для других языков отслеживается в публичной задаче с дорожной картой, номер 309 в GitHub-репозитории проекта.