Как работает многогранный (faceted) поиск в RAG с фильтрами?
Краткий тезис
Многогранный (faceted) поиск — это техника, при которой результаты поиска фильтруются по нескольким атрибутам (фасетам), таким как автор, дата, категория, источник. В RAG-системах faceted поиск реализуется через метаданные, которые прикрепляются к каждому чанку. Фильтрация может выполняться до векторного поиска (pre-filter) или после него (post-filter). Pre-filter эффективнее при высокой селективности фильтров, post-filter проще в реализации, но может быть дорогим. Правильное применение фасетов повышает релевантность retrieval и снижает шум.
1. Термин: Фасет (facet) и метаданные
Фасет — это атрибут или категория, по которой можно отфильтровать данные. В контексте RAG фасеты хранятся как метаданные чанка: например, { "author": "Иванов", "date": "2024-01-15", "category": "техническая документация", "language": "ru" }. Метаданные добавляются на этапе индексации и позволяют сужать область поиска без изменения векторного представления.
Зачем нужны фасеты в RAG
- Уменьшают количество нерелевантных чанков, особенно когда база разнородна (документы разных типов, языков, периодов).
- Позволяют пользователю явно указать контекст (например, «только статьи за последний год»).
- Улучшают precision (точность) retrieval, не снижая recall (полноту) для нужного подмножества.
2. Pre-filtering (фильтрация до векторного поиска)
Pre-filter — сначала применяются фильтры по метаданным, затем поиск|векторный поиск выполняется только в отфильтрованном подмножестве.
Как работает
- Пользовательский запрос содержит как текстовую часть, так и фильтры (например,
category = "новости" AND year >= 2023). - Система извлекает из векторной БД все чанки, удовлетворяющие фильтрам (используя индекс по метаданным).
- На этом подмножестве выполняется поиск по косинусной близости или другому векторному расстоянию.
- Возвращаются top-k результатов.
Преимущества
- Высокая производительность, если фильтры селективны (отсекают >90% данных).
- Гарантируется, что все результаты соответствуют фильтрам.
- Не тратится время на вычисление расстояний для заведомо неподходящих чанков.
Недостатки
- Если фильтры слишком узкие, может не остаться чанков для поиска → пустой результат.
- Требует поддержки фильтрации на уровне векторной БД (не все БД умеют эффективно комбинировать фильтры и векторный поиск).
3. Post-filtering (фильтрация после векторного поиска)
Post-filter — сначала выполняется векторный поиск по всей базе, затем из top-N результатов отбрасываются те, что не проходят фильтры.
Как работает
- Векторный поиск возвращает, скажем, top-100 чанков по близости к запросу.
- Из этих 100 отбираются только те, у которых метаданные соответствуют фильтрам.
- Если после фильтрации осталось меньше k, можно либо вернуть меньше результатов, либо увеличить N.
Преимущества
- Простая реализация — фильтрация на стороне приложения или через SQL-подобные условия после поиска.
- Не требует специальной поддержки в векторной БД (подходит для FAISS без метаданных).
Недостатки
- Низкая производительность при больших N и жёстких фильтрах (приходится искать много лишнего).
- Риск потерять релевантные чанки, которые не попали в top-N из-за фильтра (если фильтр отсекает большинство результатов, нужное может быть на 101-м месте).
- Увеличение latency из-за двойного прохода.
4. Сравнение pre-filter и post-filter
| Критерий | Pre-filter | Post-filter |
|---|---|---|
| Производительность | Высокая при селективных фильтрах | Низкая при жёстких фильтрах |
| Гарантия соответствия фильтрам | Да (все результаты) | Да (после отсева) |
| Риск пустого результата | Есть (если фильтр слишком узкий) | Меньше (можно увеличить N) |
| Сложность реализации | Требует поддержки БД | Проще, часто на стороне клиента |
| Точность (precision) | Высокая (фильтр до поиска) | Может быть ниже (фильтр после) |
| Пример БД | Pinecone (с filter), Weaviate, Qdrant | FAISS + внешний фильтр, Elasticsearch |
Когда что выбирать
- Pre-filter — когда фильтры обязательны и селективны (например, «только документы на русском языке»).
- Post-filter — когда фильтры опциональны или слабо селективны (например, «автор = Иванов», если Иванов написал 80% базы).
5. Реализация в популярных векторных БД
Pinecone — поддерживает pre-filter через параметр filter в запросе. Пример:
index.query(
vector=query_embedding,
filter={"category": {"$eq": "news"}, "year": {"$gte": 2023}},
top_k=10
)
Weaviate — использует синтаксис where для фильтрации. Можно комбинировать с nearVector или nearText. Pre-filter по умолчанию.
Qdrant — поддерживает filter в search_points. Есть режимы pre-filter и post-filter (настраивается).
Elasticsearch — гибридный поиск: сначала фильтр по метаданным (через bool query), затем knn по отфильтрованным документам.
FAISS — не имеет встроенной фильтрации. Для post-filter нужно хранить метаданные отдельно (например, в pandas DataFrame) и отсеивать после поиска.
6. Пример кода: faceted поиск с pre-filter (Pinecone)
import pinecone
from sentence_transformers import SentenceTransformer
# Инициализация
pinecone.init(api_key="...", environment="...")
index = pinecone.Index("my-rag-index")
model = SentenceTransformer('all-MiniLM-L6-v2')
# Запрос пользователя
query_text = "Как настроить VPN?"
query_vector = model.encode(query_text).tolist()
# Фильтры: только документы за 2024 год, категория "инструкции"
filters = {
"year": {"$gte": 2024},
"category": {"$eq": "инструкции"}
}
# Pre-filter поиск
results = index.query(
vector=query_vector,
filter=filters,
top_k=5,
include_metadata=True
)
# Вывод результатов
for match in results['matches']:
print(f"ID: {match['id']}, Score: {match['score']}, Author: {match['metadata']['author']}")
7. Продвинутые техники
Динамические фасеты — фасеты, которые вычисляются на лету на основе запроса. Например, если пользователь ищет «отчёты за прошлый квартал», система может автоматически определить фасет date и применить фильтр.
Комбинированные фильтры — логические комбинации (AND, OR, NOT) нескольких фасетов. Например: (category = "техника" OR category = "программирование") AND language = "ru".
Гибридный поиск с фасетами — сочетание векторного поиска и полнотекстового (BM25) с фильтрацией. В Elasticsearch это делается через knn + bool query.
Кэширование результатов фильтрации — если одни и те же фильтры применяются часто, можно кэшировать ID чанков, удовлетворяющих фильтру, и выполнять векторный поиск только по ним.
8. Проблемы и ограничения
- Curse of dimensionality при фильтрации — если фильтр отсекает очень мало данных (например, 1%), pre-filter может быть неэффективен, так как построение индекса по метаданным и поиск по малому подмножеству могут быть медленнее, чем полный поиск.
- Несбалансированные фасеты — если один фасет (например,
language) имеет очень неравномерное распределение (99% документов на английском), фильтр на редкий язык может дать пустой результат. - Сложность поддержки метаданных — нужно аккуратно заполнять метаданные при индексации, иначе фильтры будут работать некорректно.
- Ограничения БД — не все векторные БД поддерживают сложные фильтры (например,
$in, $regex). Приходится делать post-filter.
9. Когда использовать faceted поиск в RAG
- Мультиязычные базы — фильтр по языку.
- Разнородные источники — фильтр по типу документа (PDF, HTML, видео-транскрипт).
- Временные ряды — фильтр по дате (последние новости, архивные данные).
- Персонализация — фильтр по автору или отделу (только документы, созданные пользователем или его командой).
- Безопасность — фильтр по уровню доступа (public, internal, confidential).
Пет-проект для закрепления
Задача Реализовать RAG-систему для корпоративной базы знаний, где пользователь может фильтровать результаты по отделу (HR, IT, Finance) и по дате (последние 30 дней, последний год, всё время).
Инструменты
- Python, Sentence Transformers, FAISS (или Pinecone free tier)
- Streamlit для UI
- Pandas для хранения метаданных (если FAISS)
Шаги:
- Собрать 100–200 текстовых документов, разбить на чанки, присвоить каждому метаданные:
department(HR/IT/Finance) иdate(YYYY-MM-DD). - Создать векторный индекс (FAISS) и отдельный DataFrame с метаданными.
- Реализовать pre-filter: по выбранным фильтрам отфильтровать DataFrame, получить ID чанков, затем выполнить поиск по FAISS только по этим ID (используя
faiss.IndexIDMap). - Реализовать post-filter для сравнения: сначала поиск по всему индексу, затем отсев по метаданным.
- Сделать Streamlit-интерфейс: поле ввода, чекбоксы для отделов, выпадающий список для периода дат, кнопка поиска.
- Вывести результаты с указанием метаданных и сходства.
Ожидаемый результат Работающее приложение, где можно выбрать «IT + последние 30 дней» и получить только релевантные чанки из IT-документов за последний месяц. Сравнить latency pre-filter и post-filter при разных объёмах данных.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 377 | Как организовать индексацию метаданных в RAG? |
| 379 | Как реализовать гибридный поиск (векторный + BM25) в RAG? |
| 380 | Что такое Self-Querying Retriever и как он работает? |
| 381 | Как использовать агентные паттерны для динамического выбора источника? |
| 382 | Как обрабатывать запросы, требующие объединения данных из нескольких источников? |
| 383 | Как реализовать многошаговый retrieval с обратной связью? |
Навигация
- Предыдущий: 377
- Следующий: 379
- Индекс: 00. Индекс разборов