Как фильтровать по несуществующим свойствам в стадии агрегации $vectorSearch в MongoDB?
При использовании стадии агрегации $vectorSearch в MongoDB с параметром filter оператор $exists не поддерживается. Однако существует альтернативный подход - проверка, является ли значение свойства null, например:
{ property: null }
или
{ property: { $eq: null } }
Этот подход корректно работает со стадией агрегации $match, успешно извлекая документы, которые либо:
- Не имеют поля
property, установленного в какое-либо значение - Имеют поле
propertyявно установленное в null
Однако при использовании того же синтаксиса фильтрации с $vectorSearch поведение отличается. Фильтр не соответствует документам, у которых поле property отсутствует вовсе.
Вопрос
Существует ли способ использовать $vectorSearch с filter, который соответствует документам на основе свойства, которое не существует?
Рассмотренные альтернативные подходы
-
Установка значений свойств в null или какое-либо другое значение по умолчанию, последующий запрос на основе этого значения
- Это потребует обновления существующих запросов
$match, использующих$existsдля этого свойства
- Это потребует обновления существующих запросов
-
Добавление стадии
$matchпосле стадии$vectorSearch- Это не является оптимальным, когда вы хотите ограничить количество документов, возвращаемых
$vectorSearch, так как это может исключить документы, которые в противном случае соответствовали бы критериям векторного поиска
- Это не является оптимальным, когда вы хотите ограничить количество документов, возвращаемых
Технический контекст
- Версия MongoDB: (не указана)
- Случай использования: Фильтрация результатов векторного поиска по существованию поля
- Проблема: Различное поведение между
$matchи$vectorSearchпри фильтрации по null/несуществующим полям
MongoDB: Фильтрация несуществующих свойств в $vectorSearch
Стадия агрегации $vectorSearch в MongoDB, к сожалению, не поддерживает фильтрацию по несуществующим свойствам с использованием традиционных операторов $exists. Текущее обходное решение - использовать проверки на нулевые значения, такие как { property: null }, но это соответствует только документам, в которых поле существует и явно установлено в null, а не документам, в которых поле полностью отсутствует. Для комплексной фильтрации несуществующих полей в векторных поисках вам потребуется либо предобработать данные для установки значений по умолчанию, либо объединить несколько стадий агрегации для достижения желаемого поведения фильтрации.
Содержание
- Основная проблема с фильтрацией $vectorSearch
- Текущие обходные решения и их ограничения
- Альтернативные подходы
- Лучшие практики для фильтрации векторного поиска
- Будущие возможности MongoDB
- Заключение
Основная проблема с фильтрацией $vectorSearch
Стадия агрегации $vectorSearch в MongoDB имеет другое поведение фильтрации по сравнению с традиционными стадиями $match при работе с несуществующими полями. Это ограничение связано с тем, как векторный поисковый механизм обрабатывает документы и применяет фильтры.
Почему $exists не работает в $vectorSearch
Оператор $exists не поддерживается в фильтрах $vectorSearch, потому что векторный поисковый механизм operates на другом уровне, чем традиционная обработка запросов MongoDB. При использовании $vectorSearch MongoDB сначала обрабатывает векторный поиск сходства, а затем применяет фильтр, но эта обработка фильтра не включает полный диапазон операторов MongoDB.
Согласно документации MongoDB, стадия $vectorSearch поддерживает подмножество операторов запросов, совместимых с моделью обработки векторного поискового механизма.
Ограничение фильтрации по нулевым значениям
При использовании { property: null } или { property: { $eq: null } } в $vectorSearch, он соответствует только документам, в которых:
- Поле существует и было явно установлено в
null - Он не соответствует документам, в которых поле полностью отсутствует
Это отличается от стандартного поведения MongoDB, где { property: null } соответствовал бы обоим сценариям.
// Это работает в $match, но НЕ в $vectorSearch
{
$vectorSearch: {
"index": "vector_index",
"path": "embedding",
"queryVector": [0.1, 0.2, 0.3],
"numCandidates": 100,
"limit": 10,
"filter": {
"property": null // Соответствует только документам, где свойство существует И равно null
}
}
}
Текущие обходные решения и их ограничения
Предобработка данных со значениями по умолчанию
Наиболее надежным обходным решением является предобработка данных для обеспечения существования всех релевантных полей, даже если они установлены в значение по умолчанию.
// Обновляем все документы, в которых отсутствует поле property
db.collection.updateMany(
{ property: { $exists: false } },
{ $set: { property: null } }
);
// Теперь $vectorSearch может работать с фильтрацией по null
db.collection.aggregate([
{
$vectorSearch: {
"index": "vector_index",
"path": "embedding",
"queryVector": [0.1, 0.2, 0.3],
"numCandidates": 100,
"limit": 10,
"filter": { "property": null }
}
}
]);
Плюсы:
- Просто и надежно
- Делает векторную фильтрацию последовательной с обычными запросами
- Нет влияния на производительность запросов
Минусы:
- Требует изменения данных
- Добавляет накладные расходы на хранение для значений по умолчанию
- Необходимо поддерживать согласованность данных
Альтернативные подходы
Подход с объединенным конвейером агрегации
Вы можете использовать двухэтапный подход, в котором сначала выполняется $vectorSearch с более разрешающим фильтром, а затем применяется дополнительная фильтрация на последующей стадии $match.
db.collection.aggregate([
{
$vectorSearch: {
"index": "vector_index",
"path": "embedding",
"queryVector": [0.1, 0.2, 0.3],
"numCandidates": 50, // Уменьшено для ограничения обработки
"limit": 100 // Более высокий начальный лимит
}
},
{
$match: {
$or: [
{ "property": null },
{ "property": { $exists: false } }
]
}
},
{
$limit: 10 // Окончательный лимит после фильтрации
}
]);
Плюсы:
- Не требует изменения данных
- Можно использовать все операторы запросов MongoDB
- Более гибкие возможности фильтрации
Минусы:
- Менее эффективно, так как векторный поиск обрабатывает больше документов, чем необходимо
- Может увеличить задержку запроса
- Использует больше памяти и вычислительных ресурсов
Использование условных обновлений на уровне приложения
Обрабатывайте логику фильтрации в коде вашего приложения до или после векторного поиска.
// Подход на уровне приложения
async function filterByNonExistentProperty() {
// Шаг 1: Получаем результаты векторного поиска
const vectorResults = await db.collection.aggregate([
{
$vectorSearch: {
"index": "vector_index",
"path": "embedding",
"queryVector": [0.1, 0.2, 0.3],
"numCandidates": 100,
"limit": 50
}
}
]).toArray();
// Шаг 2: Фильтруем результаты в приложении
const filteredResults = vectorResults.filter(doc => {
return !doc.hasOwnProperty('property') || doc.property === null;
});
return filteredResults.slice(0, 10); // Применяем окончательный лимит
}
Плюсы:
- Полный контроль над логикой фильтрации
- Нет зависимостей от версии MongoDB
- Можно реализовать сложные правила фильтрации
Минусы:
- Увеличение сетевого трафика (передается больше данных)
- Более высокое использование памяти приложением
- Более медленное время отклика из-за обработки на стороне клиента
Лучшие практики для фильтрации векторного поиска
Соображения по проектированию схемы
При планировании схемы для векторного поиска рассмотрите эти шаблоны проектирования:
-
Последовательность схемы: Убедитесь, что все документы, которые должны быть доступны для поиска, имеют необходимые поля, даже если установлены в значения по умолчанию.
-
Именование полей: Используйте последовательные соглашения об именовании полей, которые четко указывают на необязательные против обязательных полей.
-
Структура документа: Рассмотрите возможность встраивания связанных данных для уменьшения необходимости в сложной фильтрации.
// Хорошая схема проектирования для векторного поиска
{
"_id": ObjectId("..."),
"embedding": [0.1, 0.2, 0.3],
"metadata": {
"category": "document",
"tags": ["important"],
"optionalField": null // Всегда присутствует, может быть null
},
"searchable": true // Всегда присутствующее булево поле
}
Оптимизация производительности
Для рабочих нагрузок с фильтрацией векторного поиска:
-
Стратегия индексации: Создавайте составные индексы, которые поддерживают как векторное сходство, так и критерии фильтрации.
-
Выборочность фильтра: Используйте высокоизбирательные фильтры на ранних этапах конвейера для уменьшения количества обрабатываемых документов.
-
Настройка numCandidates: Настраивайте параметр
numCandidatesв зависимости от выборочности вашего фильтра.
// Оптимизированный векторный поиск с фильтрацией
db.collection.aggregate([
{
$vectorSearch: {
"index": "vector_index",
"path": "embedding",
"queryVector": [0.1, 0.2, 0.3],
"numCandidates": 200, // Выше для избирательных фильтров
"limit": 20,
"filter": {
"searchable": true,
"metadata.optionalField": null
}
}
}
]);
Будущие возможности MongoDB
Обновления версий MongoDB
По мере развития MongoDB возможности векторного поиска продолжают улучшаться. Недавние версии расширили параметры фильтрации, доступные в $vectorSearch:
- MongoDB 7.0+: Улучшенная поддержка операторов в фильтрах векторного поиска
- Atlas Vector Search: Расширенные возможности фильтрации в облачной службе
- Оптимизации производительности: Улучшенная обработка сложных условий фильтрации
Появляющиеся решения
Команда разработки MongoDB активно работает над устранением этих ограничений:
-
Расширенная поддержка операторов: Будущие версии могут поддерживать больше операторов, таких как
$exists, непосредственно в$vectorSearch. -
Улучшенная обработка null: Улучшенная обработка различий между null и отсутствующими полями.
-
Улучшения производительности: Более эффективная фильтрация внутри самого векторного поискового механизма.
Заключение
Фильтрация по несуществующим свойствам в стадии агрегации exists` или традиционную фильтрацию по null для соответствия отсутствующим полям, существует несколько практических обходных решений:
- Предобрабатывайте ваши данные для обеспечения последовательного присутствия полей, что делает фильтрацию по null надежной
- Используйте объединенные конвейеры агрегации для разделения векторного поиска и сложной фильтрации
- Реализуйте фильтрацию на уровне приложения для максимальной гибкости, когда это позволяет производительность
Наиболее надежным решением для производственных сред обычно является предобработка данных, поскольку она обеспечивает последовательное поведение и оптимальную производительность. Однако для сценариев разработки или когда изменение данных нецелесообразно, подход с объединенным конвейером предлагает работоспособную альтернативу.
По мере продолжения развития MongoDB возможностей векторного поиска, следование за последней документацией и функциями версий поможет вам воспользоваться улучшенными опциями фильтрации в будущих выпусках.