Milvus — распределённая векторная база данных для поиска по смыслу. Она хранит эмбеддинги, строит приближённый индекс ближайших соседей и позволяет комбинировать векторный поиск с обычными условиями по полям. В 2026 году такие базы используют для поиска по документации, рекомендаций, дедупликации и мультимодального поиска, где сравнение «в лоб» по миллионам векторов уже не укладывается в бюджет задержки.

Как устроен Milvus

В распределённом режиме запрос проходит через прокси, который принимает данные и распределяет нагрузку. Координаторы управляют схемой, сегментами и индексами, а узлы query и data выполняют поиск и запись. Метаданные лежат в etcd, сами векторы и индексы — в объектном хранилище S3 или MinIO, поток изменений идёт через журнал WAL на Pulsar или Kafka. Такое разделение позволяет масштабировать чтение и запись независимо.

Для ноутбука и тестов есть Milvus Lite — встраиваемый режим без кластера. Для одного сервера подойдёт Standalone в Docker Compose, для промышленной нагрузки — Kubernetes с Helm или оператором. Начинать почти всегда стоит с Standalone: схема и клиентский код те же, а диагностика проще.

Запуск Standalone

Официальный compose-файл поднимает Milvus, etcd и MinIO. Скачайте его из релизов проекта и запустите:

curl -L -o milvus-standalone-docker-compose.yml \
  https://github.com/milvus-io/milvus/releases/latest/download/milvus-standalone-docker-compose.yml
docker compose -f milvus-standalone-docker-compose.yml up -d
curl -s http://localhost:9091/healthz
docker compose -f milvus-standalone-docker-compose.yml ps

Порт 19530 принимает клиентов, 9091 отдаёт метрики и проверку здоровья, 9001 — консоль MinIO. Если healthz отвечает OK, а клиент не подключается, проверьте, что порт опубликован и брандмауэр не блокирует соединение. Не открывайте 19530 в интернет: доступ закрывают сетью и прокси.

Схема коллекции

Коллекция — аналог таблицы. Помимо вектора в ней обычно есть первичный ключ и скалярные поля для фильтрации. Размерность вектора должна совпадать с моделью эмбеддингов: у многих современных моделей это 768 или 1024.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")
schema = client.create_schema(auto_id=True)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=768)
schema.add_field("title", DataType.VARCHAR, max_length=512)
schema.add_field("year", DataType.INT32)

Явная схема лучше динамической: она ловит ошибки типов на входе и позволяет строить индексы по скалярным полям.

Индекс и метрика

Индекс определяет компромисс между скоростью, памятью и полнотой. HNSW даёт высокую скорость поиска и требует памяти под граф, IVF_FLAT экономит память, но требует настройки числа списков, DiskANN выносит часть структуры на диск.

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="HNSW",
    metric_type="COSINE",
    params={"M": 16, "efConstruction": 200},
)
client.create_collection("papers", schema=schema, index_params=index_params)

Параметр M задаёт число связей в графе, efConstruction — качество построения. При поиске ef управляет компромиссом: больше значение — выше полнота и задержка. Метрику выбирают под модель: для нормализованных эмбеддингов подходит COSINE или IP, для сырых векторов — L2.

Запись и поиск с фильтром

Вставка принимает список словарей. Индексация выполняется асинхронно, поэтому сразу после вставки данные могут быть ещё не видны поиску.

rows = [
    {"embedding": vec, "title": "Kerberos в Linux", "year": 2026},
    {"embedding": vec2, "title": "Векторный поиск", "year": 2025},
]
client.insert("papers", rows)
client.flush("papers")

res = client.search(
    "papers", data=[query_vec], anns_field="embedding",
    limit=10, filter='year >= 2025',
    output_fields=["title", "year"],
    search_params={"metric_type": "COSINE", "params": {"ef": 64}},
)

Фильтр применяется вместе с поиском, а не после него, поэтому лишние векторы не попадают в топ. Выражения поддерживают сравнения, in, like и логические операторы. Для высокоселективных фильтров полезен partition key: он физически группирует данные и сокращает объём сканирования.

Гибридный поиск

Плотные эмбеддинги плохо ловят точные термины и артикулы, разреженные — наоборот. Гибридный поиск объединяет несколько запросов и ранжирует результаты общим алгоритмом.

from pymilvus import AnnSearchRequest, RRFRanker

dense = AnnSearchRequest(data=[query_vec], anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"ef": 64}}, limit=20)
sparse = AnnSearchRequest(data=["kerberos keytab"], anns_field="sparse",
    param={"metric_type": "BM25"}, limit=20)
res = client.hybrid_search("papers", [dense, sparse],
    ranker=RRFRanker(60), limit=10, output_fields=["title"])

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

Ресурсы и диагностика

Память считается просто: число векторов умножить на размерность и на четыре байта, плюс запас на индекс и служебные структуры. Десять миллионов векторов размерности 768 занимают около 30 ГБ только под сырые данные, а HNSW добавляет граф. Квантизация SQ8 уменьшает объём вчетверо ценой небольшой потери полноты.

docker stats --no-stream
curl -s localhost:9091/metrics | grep milvus_querynode
curl -s localhost:9091/metrics | grep milvus_proxy
client.get_collection_stats("papers")

Смотрите на задержку поиска, долю попаданий в кеш, размер сегментов и очередь запросов. Если задержка растёт вместе с числом сегментов, поможет compaction. Если память упирается в лимит, переходите на DiskANN или квантизацию, а не увеличивайте ef наугад.

Резервное копирование

Объектное хранилище и etcd — не резервная копия. Для согласованного снимка используйте утилиту milvus-backup: она сохраняет коллекции и метаданные в S3-совместимое хранилище.

milvus-backup create -n daily_2026_11_06
milvus-backup list
milvus-backup restore -n daily_2026_11_06 -c papers_restore

Проверяйте восстановление на стенде: неразвёрнутый снимок нельзя считать рабочим. Держите версию схемы и модели эмбеддингов рядом с копией — без них векторы бесполезны.

Чек-лист

  • Размерность и метрика совпадают с моделью эмбеддингов.
  • Индекс выбран под объём данных и лимит памяти.
  • Фильтры проверены на селективность, partition key обоснован.
  • Порт базы закрыт снаружи, доступ только через доверенную сеть.
  • Настроены метрики, алерты и регулярные проверки восстановления.

Итог

Milvus даёт масштабируемый слой для векторного поиска: отдельные компоненты отвечают за запись, индексацию и чтение, а объектное хранилище снимает ограничение на объём. Начните со Standalone и явной схемы, подберите индекс по замеру полноты и задержки, затем добавляйте фильтры и гибридный поиск. Главные ошибки — несовпадение метрики с моделью и экономия на резервных копиях.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте