Механизм · 0.1.0b4

Один поиск в директории.
Один непрерывный скан.

Фильтрованный векторный поиск обычно представляет собой scatter-gather по индексу, который ничего не знает о вашем фильтре. Telys управляет физическим размещением напрямую: по ключу партиции поиск ближайших соседей с условием key=x — это O(1)-поиск в директории плюс один последовательный скан непрерывного блока. Эта страница описывает рантайм, поставляемый сегодня, а затем архитектуру, к которой он движется, — с пометкой «спецификация».

Panel 01 · Сегодня — поставляемый рантайм
01 Физическое размещение

Движок управляет расположением каждого вектора.

Коллекция объявляет partition_by при создании, и размещение следует ключу. Базовый сегмент кластеризован по партиции — каждый ключ отображается на один непрерывный срез — а свежие записи хранятся рядом в изменяемой дельте формата Arrow.

Базовый сегмент

Кластеризован по партиции

Векторы хранятся отсортированными по ключу партиции, так что каждая партиция — один непрерывный блок. Запрос с ограничением читает один последовательный участок памяти, а не строки, разбросанные по индексу.

Директория партиций

O(1) ключ → срез

Директория отображает каждое значение партиции на его (offset, length) в базовом сегменте. Разрешение фильтра — это поиск в словаре, а не обход индекса.

Изменяемая дельта

Записи в формате Arrow

add и upsert добавляют строки сюда, каждая помечена монотонным LSN записи. Дельта доступна для запросов немедленно и объединяется с базовым срезом через единый путь сканирования.

02 Путь чтения

Что выполняет один ограниченный запрос.

Запрос

col.search(qvec, where={"tenant_id": "acme"}, top_k=10)

Фильтр указывает ключ партиции, с которым была создана коллекция.

Директория партиций

O(1)-поиск: значение партиции разрешается в (offset, length) базового сегмента. Никакой генерации кандидатов, никакой точки входа в граф.

Скан непрерывного среза

SIMD-точное скорирование по одному последовательному блоку. Recall на этом пути равен 1.0 — это скан, а не приближение. Измеренные p50/p95 для этого шага публикуются на странице бенчмарков, каждый привязан к своему порогу recall и стенду.

Объединение дельты

Строки с одним ключом в Arrow-образной дельте проходят оценку по тому же пути. Запись видна уже следующему запросу.

Видимость MVCC

Фильтр применяется по LSN снимка: удалённые и вытесненные версии не всплывают. Top-k возвращается с прикреплённой полезной нагрузкой explain.

Для слишком больших партиций предусмотрена явная развилка: build_ivf строит пословный IVF над каждой партицией, превышающей пороговое число строк, а запросы маршрутизируются через него с точным переранжированием — откалиброванным по нижней границе полноты и указанным в плане.

03 Развилка explain

Каждый результат называет свой план.

explain=True возвращает физический план, по которому фактически выполнился запрос. По ключу партиции — сканирование непрерывного среза. Слишком большие партиции объявляют развилку IVF. Фильтры не по ключу откатываются к scatter-gather — и полезная нагрузка объясняет почему.

explain
hits = col.search(qvec, where={"tenant_id": "acme"}, top_k=10, explain=True)

hits["explain"]["plan"]
# on the partition key  → "PartitionSliceExactF32"   # one contiguous slice, exact, recall 1.0
# oversized partition   → "PartitionIVFRerankF32"   # per-partition IVF + exact rerank
# off-key filter        → "ScatterGatherExact"      # fallback — and it says why:

hits["explain"]["fallback_reason"]
# "path is not the physical partition key"
04 Записи и время

Ничто не перезаписывается. Версии вытесняются.

Модель записи — append-only MVCC. upsert записывает новую версию логического id и помечает предыдущую вытесненной; delete размещает tombstone с LSN удаления; snapshot() фиксирует согласованное представление для чтения; compact() сворачивает дельту в базовый сегмент и удаляет всё, что ни один снимок уже не видит.

python
col.upsert(vectors, ids=ids, metadata=metadata)   # a new version; the prior one is superseded
col.delete(["doc-41"])                            # tombstone at a delete LSN — no in-place erase
lsn = col.snapshot()                              # pin a consistent read view at an LSN
col.compact()                                     # fold delta into base; drop superseded rows
col.build_ivf(min_rows=20000, target_recall=0.98)
ВызовЧто делает
добавить / добавить_текстыВставка новых строк. Дублирующиеся id отклоняются — вторая физическая строка для одного логического id требует upsert намеренно.
обновить / обновить_текстыЗаписывает новую версию логического id; предыдущая версия вытесняется, но не перезаписывается на месте.
поиск / поиск_текстаФильтрованный top-k. explain=True прикрепляет физический план к результату.
deleteПомечает логические строки tombstone с LSN удаления.
compactСворачивает дельту в базовый сегмент; удаляет tombstone-строки и вытесненные версии.
build_ivfСтроит пословный IVF над партициями, превышающими пороговое число строк, откалиброванный по нижней границе полноты.
snapshotВозвращает LSN, фиксирующий согласованное представление для чтения.
save / statsСохраняет коллекцию на диск; выводит число строк, партиций и сведения о структуре.
Panel 02 · Направление — архитектурная спецификация

Всё нижеследующее — спецификация, а не справочник по выпущенному API. Это субстрат, к которому сходится среда выполнения. Шов на стороне SDK заморожен, поэтому замена под ним невидима для вызывающих.

05 Целевой субстрат

Один планировщик. Одно плоское IR. Один исполнитель.

Три фронтенда опускаются в один планировщик, который выдаёт одно плоское физическое промежуточное представление, исполняемое одним векторизованным исполнителем Mojo непосредственно над Arrow-буферами.

Фронтенды

Модель памяти (remember · recall · as_of), API запросов (point_get · scan · search · hybrid_search) и фабрика. Единый входной контракт; никаких отдельных движков на API.

Один планировщик

Логическое и физическое планирование в одном месте. Селективность оценивается по статистике сегментов; план явный и возвращается вместе с результатом.

Одно плоское IR

Плоский массив операторов, связанных целочисленными слотами. Межоператорный регистр — это набор строк: битовая карта, отсортированные row-id или вектор выборки.

Исполнитель Mojo

Векторизованное выполнение над Arrow-буферами и массивами кандидатов FAISS. Горячий путь SIMD остаётся вне Python; сжатые страницы Parquet сначала декодируются в промежуточные буферы.

Arrow дельта + WAL

Слой мутаций

Журнал упреждающей записи для надёжности и упорядочивания и изменяемая Arrow-образная дельта для немедленной видимости — табличный слой, которого Parquet лишён сам по себе.

Parquet-сегменты

Запечатанные, неизменяемые

Надёжные сжатые столбцовые сегменты. Статистика футера управляет отсечением сегментов и групп строк; запечатанные файлы никогда не изменяются.

.vidx файлы-спутники

FAISS ANN

Пословные индексы FAISS, привязанные к контрольной сумме и версии сегмента, отображённые только для чтения с временем жизни, привязанным к снимку чтения.

Скалярные + разреженные спутники

Отсечение и лексический поиск

Zone maps, bloom-фильтры и битовые карты для отсечения; BM25-sidecar для разреженного поиска и слияния оценок.

flat IR — набор операторов
SCAN  FILTER  PROJECT  POINT_GET  RANGE_GET  AGGREGATE  TOP_K
HASH_JOIN  HASH_GROUP_BY  SORT
ANN_SEARCH  SPARSE_SEARCH  FUSE  RERANK  MATERIALIZE
06 Путь записи

Сначала WAL. Видимость немедленная. Запечатывание в фоне.

WAL append

Фреймы только для добавления с контрольными суммами и монотонными LSN. Восстановление воспроизводит записи после последнего запечатанного LSN и усекает на первой неверной контрольной сумме.

Arrow delta

Запись попадает в изменяемую дельту и сразу доступна для запросов — запечатанные сегменты и дельта объединяются через единый путь сканирования.

Фоновое запечатывание

По достижении порогового значения размера, числа строк или возраста дельта сортируется и записывается как сегмент Parquet с файлами .vidx и sidecar, после чего публикуется атомарной заменой манифеста.

Compaction

Фоновые слияния объединяют малые сегменты, удаляют помеченные на удаление строки и перестраивают sidecar-файлы — с контролем бюджета, чтобы on-device развёртывания оставались незаметными.

Запечатанные сегменты никогда не изменяются. Чтение фиксирует снимок манифеста и LSN; писатели запечатывают новые сегменты и заменяют манифест, не затрагивая активные операции чтения. Сборка мусора ожидает завершения самого старого живого снимка.

07 Filtered ANN как планирование

Фильтр выбирает план, а не наоборот.

Filtered ANN — это адаптивное планирование по селективности: планировщик оценивает, сколько строк проходит фильтр по статистике сегментов, и выбирает наиболее дешёвую стратегию, удовлетворяющую контракту на полноту выборки.

Selective

Предфильтр → точный

Сначала скалярный или bitmap-префильтр, затем точное SIMD-скоринг по прошедшим строкам. Ниже порогового числа строк ANN пропускается полностью — точное сканирование, recall 1.0.

Moderate

Обход по allow-bitmap

Обход ANN несёт allow-bitmap, поэтому индекс возвращает только строки, допущенные фильтром.

Broad

ANN → постфильтр

Сначала ANN с адаптивной избыточной выборкой, затем пост-фильтрация. Фильтр отсекает немного, поэтому генерация кандидатов идёт первой.

08 Статус

Проверка корректности предшествует любым показателям скорости.

Поставляемый рантайм верифицируется наборами тестов паритета, запускаемых против обеих реализаций движка, и каждый запрос может назвать физический план, по которому он был выполнен. Таков порядок операций: сначала проверка корректности, затем измерения.

Бенчмарки публикуются в рамках контракта честности — согласованный recall, согласованное железо, результаты с разделением по транспорту, с указанием победы / ничьей / поражения. Первые измеренные результаты уже доступны на странице бенчмарков: каждая цифра сопровождается полными условиями — железо, датасет, размерность, селективность, recall и транспорт. Любой множитель остаётся гипотезой за пределами указанных рядом с ним условий.

Методология бенчмарковОбзор продукта