Qdrant - Vector Database

Фильтрация: Filter API

Vector search находит семантически близкое. Но «покажи мне только опубликованные статьи на русском языке, созданные после 2024 года, с ценой до 1000» - это filter. Вместе они дают точный и умный поиск.

  • **E-commerce:** 'красные кроссовки' (vector) + size=42 AND brand='Nike' AND in_stock=true (filter)
  • **Knowledge base:** 'как настроить nginx' (vector) + category='devops' AND language='ru' (filter)
  • **Геолокация:** 'итальянский ресторан' (vector) + geo_radius=2km AND rating>4 AND open_now=true (filter)

Предварительные знания

  • Payload Indexes

Структура Filter: must / should / must_not

**Filter API** в Qdrant - способ ограничить поиск по payload. Работает как SQL WHERE, но для vector search. Фильтрация выполняется ДО или ПОСЛЕ векторного поиска - Qdrant выбирает стратегию автоматически.

ОператорSQL аналогЛогика
mustANDВсе условия должны выполняться
shouldORХотя бы одно условие должно выполняться
must_notNOTНи одно условие не должно выполняться
min_shouldOR с минимумомМинимум N из M условий должны выполняться

**Производительность:** фильтрация работает быстро ТОЛЬКО при наличии payload индекса. Без индекса Qdrant проверяет каждую точку - O(N). С индексом - O(log N). Всегда создавайте индекс для полей, по которым фильтруете (урок qd-08).

Нужно найти документы: (category='tech' AND language='en') OR (category='science' AND language='ru'). Как это записать в Filter API?

Field conditions: Match, Range, Geo и другие

**Field conditions** - конкретные проверки значений полей. Qdrant поддерживает: точное совпадение, совпадение из списка, диапазоны, геофильтры, проверку на null.

ConditionСинтаксисОписание
MatchValuematch: { value: 'en' }Точное совпадение одного значения
MatchAnymatch: { any: ['en', 'ru'] }Совпадение с одним из списка (IN)
MatchExceptmatch: { except: ['deleted'] }Не совпадает ни с одним из списка (NOT IN)
Rangerange: { gte: 0, lte: 100 }Числовой диапазон: gt, gte, lt, lte
DatetimeRangerange: { gte: '2024-01-01T00:00:00Z' }Диапазон дат (ISO 8601)
IsNullis_null: { key: 'field' }Поле равно null или отсутствует
IsEmptyis_empty: { key: 'tags' }Массив пуст или отсутствует
GeoBoundingBoxgeo_bounding_box: { top_left, bottom_right }Прямоугольная географическая область
GeoRadiusgeo_radius: { center, radius }Круговая область по радиусу (метры)

Нужно найти продукты с тегами ['sale', 'featured'] (оба тега обязательны) и ценой от 500 до 2000. Как правильно написать фильтр?

Nested filters и вложенные объекты

**Nested filters** позволяют фильтровать по полям внутри вложенных объектов и массивов. Особенно полезно для документов со сложной структурой payload.

**Когда нужен nested:** если в payload есть массив объектов, и вы хотите проверить что ОДИН элемент массива удовлетворяет сразу нескольким условиям. Без nested, условия могут совпасть с разными элементами массива.

Payload: `orders: [{status: 'shipped', amount: 50}, {status: 'pending', amount: 200}]`. Нужно найти записи с хотя бы одним заказом status='shipped' AND amount>100. Что вернёт nested filter?

Производительность фильтрации

**Производительность filter** критична в production. Qdrant выбирает стратегию фильтрации автоматически на основе selectivity (избирательности) фильтра и размера коллекции.

СтратегияКогда применяетсяКак работает
Pre-filteringФильтр высоко selective (< 5-10% точек)Сначала фильтр → затем ANN в подмножестве
Post-filteringФильтр низко selective (> 50% точек)Сначала ANN → затем фильтр по результатам
Exact (full scan)Очень маленькая коллекция или нет индексаПеребор всех точек

**Selectivity и стратегия:** если фильтр очень избирательный (например, category='rare-topic' - только 0.1% точек), Qdrant делает pre-filtering и ANN только по этому подмножеству. Это быстрее, чем full ANN + post-filter. Хорошие индексы + правильная selectivity = быстрые filtered queries.

Добавить фильтр по каждому полю payload для 'гибкого' поиска без предварительной индексации

Создавать payload индекс только для полей, реально используемых в фильтрах в production

Каждый payload индекс занимает память (примерно 50-200MB на 1M точек для keyword поля). Индексируйте только то, что нужно. Неиндексированные поля для фильтрации = full scan = медленно

У вас 1 миллион документов. Фильтр `category='python'` отбирает ~500 тысяч (50%). Какую стратегию выберет Qdrant и почему это правильно?

Ключевые идеи

  • **must/should/must_not** - AND/OR/NOT для payload условий
  • **Field conditions:** MatchValue, MatchAny, Range, IsNull, IsEmpty, GeoBoundingBox, GeoRadius
  • **Nested filter** - когда нужно что один элемент массива удовлетворяет нескольким условиям
  • **Производительность:** payload индекс обязателен для полей в фильтрах
  • **Стратегия:** Qdrant выбирает pre/post-filtering по selectivity автоматически
  • Помните hook? Вектор находит смысл, фильтр уточняет структурные требования - вместе они непобедимы

Что дальше

Фильтрация работает. Следующий шаг - группировка результатов для дедупликации.

  • Группировка результатов — searchGroups для дедупликации чанков по документу
  • Hybrid Search — Добавить filter к hybrid search запросу
  • Payload Index — Подробнее о настройке индексов для производительности

Вопросы для размышления

  • Какие поля payload в вашем проекте нужно индексировать? Как определить это из требований к поиску?
  • Когда имеет смысл использовать nested filter вместо обычного?
  • Как измерить влияние фильтра на производительность поиска в production?

Связанные уроки

  • qd-08-payload-index — Payload index - основа для фильтрации по полям
  • qd-11-hybrid-search — Фильтры используются внутри hybrid search для pre-filtering
  • pg-06-select — SQL WHERE clause - то же что qdrant filter, другой синтаксис
  • db-09-indexes-btree — B-tree index для фильтрации - аналог payload index в Qdrant
Фильтрация: Filter API

0

1

Войти