Гайд · TNWS AI
Как фильтровать векторный поиск Vespa по tenant без утечки в RAG
YQL-фильтр вместе с nearestNeighbor, серверный tenant, pre-filtering, отрицательный ACL-тест и проверка полного top-k.
Какую задачу решаем и где применимо
Русскоязычный поисковый запрос: «как фильтровать vector search Vespa по tenant». Материал проверен по официальной документации Vespa, актуальной на 19 сентября 2026 года. Для Vespa с полем tenant_id типа int с attribute и fast-search и документным вектором embedding. Пример использует целочисленный tenant для ясного условия tenant_id = 42; в реальной системе значение должно поступать от доверенной backend-сессии, а не из аргумента пользователя.
В Vespa nearestNeighbor сочетается с фильтрами языка YQL. По умолчанию поиск с фильтрами использует pre-filtering при ranking.matching.postFilterThreshold=1.0; отдельные параметры профиля могут изменить стратегию, поэтому не предполагайте её по одной форме YQL. Отфильтровывать доступ только после передачи результатов в LLM небезопасно: содержимое уже могло попасть в prompt или логи.
До начала эксперимента подготовьте маленький набор документов с известными source_id и один отрицательный пример. Сохраните версию schema, embedding-модели, набор входных вопросов и ожидаемые IDs: так результат можно воспроизвести после обновления системы, а не оценивать по одному удачному ответу. Все значения для маленького tensor в шаблоне — иллюстрация контрактов, не показатели качества модели.
Пошаговое выполнение
- Добавьте в схему
tenant_idкак фильтруемый attribute и проверьте его наличие в каждом документе. - На сервере сопоставьте аутентифицированный принципал разрешённому tenant ID.
- Соедините nearestNeighbor и
tenant_id = 42черезandвнутриwhereYQL. - В тестовом профиле зафиксируйте pre-filtering и сравните его с контролируемым post-filtering, сохранив latency и IDs.
- Поместите наиболее близкий чужой документ в тест; удостоверьтесь, что он ни разу не попадает в контекст.
Эти шаги предполагают доступ к собственному тестовому приложению Vespa. Для Vespa Cloud и самостоятельной установки способы деплоя отличаются; не угадывайте имена кнопок консоли. Используйте показанный интерфейс schema, YQL или CLI, сверяя конкретное окружение и permissions с документацией. При деплое сохраняйте предыдущее определение, чтобы сопоставить результаты и откатить неудачное изменение без смешения двух причин.
Готовый шаблон
vespa query 'yql=select source_id,text,tenant_id from article where {totalTargetHits:20}nearestNeighbor(embedding,q) and tenant_id = 42' 'input.query(q)=[0.10,0.20,0.30]' 'ranking=semantic' 'hits=5' 'ranking.matching.postFilterThreshold=1.0'
Шаблон адаптируйте к своей размерности и именам документов. Если он содержит ручной трёхмерный вектор, он полезен для smoke-теста схемы и синтаксиса, но не заменяет настоящий embedding вопроса. Секреты провайдера, токены Vespa и данные закрытых клиентов не вставляйте ни в публичный prompt, ни в статью, ни в логи запроса.
Конкретный вход и ожидаемый выход
Вход: семь текстов tenant 42 и самый близкий вектор чужого tenant 17 с закрытым договором. Ожидается, что top-5 содержит только tenant_id=42, а закрытый документ не появляется ни в логах генератора, ни в запросе LLM; если у tenant менее пяти документов, короткий ответ допустим.
Обязательный фильтр доступа — не удобная SEO-настройка, а часть границы безопасности. Если tenant_id отсутствует, отклоняйте запрос или документ согласно политике, но не расширяйте выдачу на весь корпус. Инженерный нюанс: слишком редкий tenant меняет оптимальную стратегию поиска, и Vespa может перейти от ANN к exact в зависимости от порогов. Замерьте это на распределении размеров арендаторов, а не только на усреднённой нагрузке. На одном и том же gold set отдельно проверяйте отсутствие чужих IDs, полноту своих результатов и p95. Запросы без identity и с поддельным tenant ID должны проваливаться до обращения к Vespa. Prompt не исправит ошибку авторизации: найденный текст следует считать недоверенными данными.
Проверка результата
- Tenant берётся только из проверенной backend identity.
- Чужой ближайший документ не появляется даже при пустом результате своего tenant.
- Отсутствующий tenant не переводит запрос в режим поиска по всему индексу.
- Стратегия фильтра и p95 измерены на малых и больших tenant.
Успех означает прохождение всех перечисленных пунктов на положительных и отрицательных кейсах. Снимите фактические IDs, число hits и latency до и после изменения; если есть LLM-ответ, проверьте цитаты вручную. Пустой результат из-за ошибки типов, времени ожидания, прав доступа или отсутствующей записи нельзя выдавать за низкую релевантность. Удобно хранить отдельный отчёт по каждым case_id, иначе невозможно обнаружить регрессию на редких формулировках.
Типичные ошибки: чего не делать
- Брать tenant_id из пользовательского тела запроса.
- Фильтровать доступ после передачи кандидатов в LLM.
- Повторять пустой поиск без tenant-фильтра.
Не исправляйте нерелевантную выдачу произвольным повышением top-k: сперва отделите ошибку модели, схемы, фильтра и ранжирования. Не отключайте проверку tenant ради красивого теста. Не делайте вывод о производительности на крошечном демонстрационном корпусе; проверяйте рабочий объём, конкурентную нагрузку и p95, а также расход памяти/скорость обновлений там, где они существенно меняются.
FAQ
Где задаётся фильтр?
В YQL where совместно с nearestNeighbor.
Можно ли полагаться только на prompt?
Нет, prompt не заменяет серверную авторизацию.
Что делать с пустым результатом?
Возвращать отсутствие разрешённых данных, не снимать ACL.
Официальные источники
Частые вопросы
Где задаётся фильтр?
В YQL `where` совместно с nearestNeighbor.
Можно ли полагаться только на prompt?
Нет, prompt не заменяет серверную авторизацию.
Что делать с пустым результатом?
Возвращать отсутствие разрешённых данных, не снимать ACL.
Читайте также
Как хранить chunks для RAG в Vespa с проверяемыми source_id
Схема chunk-документов, parent ID, versioned embeddings, готовый prompt и тест цитат по исходным фрагментам.
Как измерить Recall@10 ANN-поиска Vespa через exact baseline
Два сопоставимых nearestNeighbor-запроса с approximate:false, формула Recall@10 и ограничения exact baseline.
Как настроить HNSW Vespa: links, insert и exploreAdditionalHits
Индексные и запросные параметры HNSW в Vespa с измерением Recall@10, памяти, скорости загрузки и p95.
Комментарии
Пока тихо. Скажите первое слово