Qdrant - Vector Database

Группировка результатов

RAG без группировки - как поиск в Google, где все первые 10 результатов с одного сайта. searchGroups решает это элегантно: «лучшие 5 документов с лучшими 2 чанками каждый» - один запрос, правильный контекст.

  • **RAG системы:** 4 документа × 3 чанка = 12 контекстных фрагментов без дублирования, с метаданными
  • **Поиск по новостям:** по 1 статье от каждого издания в топе - diversity в результатах
  • **Поиск кандидатов:** по 1-2 вакансии от каждой компании - не доминирует одна организация

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

  • Filtering: Filter API

Проблема: много чанков одного документа

**Стандартный RAG pipeline:** документ разбивается на чанки → каждый чанк индексируется как отдельная точка. При поиске топ-10 результатов может оказаться, что 7 из них - чанки одного документа. Это плохо для пользователя.

**Решения без groupBy:** 1. deduplication на уровне приложения - но тогда limit=100 и вы выбрасываете 90 результатов 2. хранить документы целиком - но теряете precision чанков. **searchGroups** решает это элегантно на уровне Qdrant.

ПодходПлюсыМинусы
Обычный search + dedup в кодеПростая реализацияВысокий limit → лишняя работа, непредсказуемый recall
Хранить только документы (не чанки)Нет дублированияПлохой recall на длинных документах
searchGroupsВстроенная дедупликация, N лучших чанков на документНужен payload индекс для group_by поля

RAG система возвращает релевантные результаты, но LLM видит один и тот же документ 5 раз из 10. Что это вызывает?

searchGroups API: group_by и group_size

**searchGroups** - специальный метод Qdrant, который группирует результаты по значению payload поля. Возвращает top-N документов, каждый с top-M чанков.

**Payload индекс обязателен!** Поле `group_by` должно быть проиндексировано. Создайте индекс: `qdrant.createPayloadIndex('chunks', { field_name: 'document_id', field_schema: 'keyword' })`. Без индекса - full scan = медленно.

searchGroups с group_by='document_id', group_size=2, limit=5. В коллекции 3 документа, у каждого 10 чанков. Максимум сколько точек вернётся?

lookup_from: обогащение из другой коллекции

**lookup_from** - параметр searchGroups, который автоматически подгружает payload для каждой группы из другой коллекции. Это паттерн «chunk collection + document collection».

**Зачем две коллекции?** Чанки содержат только текст чанка. Полные метаданные документа (title, URL, author, date, tags) хранятся в отдельной документной коллекции. При поиске Qdrant автоматически обогащает группы данными из документной коллекции.

**Коллекция 'documents' без реального вектора:** если documents нужна только для lookup (не для поиска), можно создать её с minimal vector (size: 1, distance: 'Cosine') и использовать только как хранилище метаданных. Это нормальный паттерн.

Зачем хранить метаданные документа (title, URL) в отдельной коллекции 'documents' вместо payload каждого чанка?

RAG паттерн: chunk search + document grouping

**Полный RAG pipeline с searchGroups** - объединяем всё: гибкие чанки, group by документ, lookup метаданных, формирование контекста для LLM.

**group_size рекомендации:** для RAG обычно group_size=2-3 (несколько чанков дают больше контекста чем один). Для UI «один результат на документ» используйте group_size=1. Для дедупликации с максимальным recall - group_size=1 + limit=20.

Использовать обычный search с limit=100 и дедупликацию в коде для экономии на searchGroups

searchGroups делает дедупликацию на уровне Qdrant - эффективнее и с лучшим recall

С limit=100 вы отправляете 100 точек по сети и фильтруете в коде. searchGroups возвращает только нужные группы - меньше трафика, правильный recall. И ещё: с limit=100 верхние позиции всё равно будут захвачены одним документом - вы теряете diversity

Для RAG: group_by='document_id', group_size=1, limit=10 vs group_size=3, limit=4. Что лучше при ограниченном контекстном окне LLM (4096 токенов)?

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

  • **searchGroups** решает проблему дублирования чанков одного документа в результатах
  • **group_by** - поле payload для группировки, **group_size** - лучших чанков на группу, **limit** - количество групп
  • **with_lookup** - автоматическое обогащение групп данными из другой коллекции
  • **Двух-коллекционный паттерн:** chunks (поиск) + documents (метаданные) - нормализация и легкое обновление
  • **Payload индекс** для group_by поля обязателен для производительности
  • Помните hook? Один запрос, N документов, M чанков - это и есть production RAG

Что дальше

Группировка работает. Следующий шаг - поиск «похожего» без явного query вектора.

  • Recommendations API — Поиск похожих документов по примерам
  • Гибридный поиск — Добавить hybrid search к группировке
  • Фильтрация — Комбинировать фильтры с group by

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

  • Как определить оптимальный group_size для вашей RAG системы? Какие метрики отслеживать?
  • Когда двух-коллекционный паттерн (chunks + documents) оправдан, а когда усложняет без нужды?
  • Как searchGroups влияет на score_threshold - нужно ли его пересматривать?

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

  • qd-13-filters — Group By часто комбинируется с фильтрами для агрегации
  • qd-12-multi-vector — Multi-vector search + group by - частая прод-комбинация
  • pg-08-aggregation — SQL GROUP BY - та же семантика агрегации по полю
  • pg-11-window — Window functions - похожая идея ранжирования внутри групп
  • db-05-sql-basics
Группировка результатов

0

1

Войти