Поделиться через


Добавление фильтра в векторном запросе в поиске ИИ Azure

Вы можете определить векторный запрос, содержащий выражение фильтра для добавления условий включения или исключения в запросы. В этой статье раскрываются следующие темы:

В этой статье используется REST для иллюстрации. Примеры кода на других языках см . в репозитории GitHub azure-search-vector-samples для комплексных решений, включающих векторные запросы.

Обозреватель поиска также можно использовать в портал Azure для запроса содержимого вектора. Если вы используете представление JSON, можно добавить фильтры и указать режим фильтра.

Принцип работы фильтрации в векторном запросе

Фильтры применяются к filterable невекторным полям, строковым или числовым полям, чтобы включить или исключить документы поиска на основе критериев фильтра. Хотя поле вектора не фильтруется само по себе, фильтры можно применять к другим полям в том же индексе, включая или исключая документы, которые также содержат векторные поля.

Фильтры применяются до или после выполнения запроса на vectorFilterMode основе параметра.

Определение фильтра

Фильтры определяют область векторного запроса. Фильтры задаются и итерируются по строке невектора и числовым полям, атрибутируемым как filterable в индексе, но назначение фильтра определяет , что выполняется векторный запрос: все пространство, доступное для поиска, или содержимое результата поиска.

Если у вас нет исходных полей с текстовыми или числовыми значениями, проверьте метаданные документа, такие как свойства LastModified или CreatedBy, которые могут оказаться полезными в фильтре метаданных.

2024-07-01 — стабильная версия для этого API. Он имеет:

В следующем примере вектор представляет эту строку запроса: "то, что службы Azure поддерживают полнотекстовый поиск". Запрос предназначен для contentVector поля. Фактический вектор имеет 1536 внедрения, поэтому он обрезан в этом примере для удобства чтения.

Критерии фильтра применяются к фильтруемому текстовому полю (category в этом примере), прежде чем поисковая система выполнит векторный запрос.

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "count": true,
    "select": "title, content, category",
    "filter": "category eq 'Databases'",
    "vectorFilterMode": "preFilter",
    "vectorQueries": [
        {
            "kind": "vector",
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "exhaustive": true,
            "fields": "contentVector",
            "k": 5
        }
    ]
}

Настройка vectorFilterMode

Параметр запроса vectorFilterMode определяет, применяется ли фильтр до или после выполнения векторного запроса.

Использование режима префильтровки

Префиксирование применяет фильтры перед выполнением запроса, уменьшая область поверхности поиска, по которой алгоритм векторного поиска ищет аналогичное содержимое.

В векторном запросе preFilter используется значение по умолчанию.

Схема префильтров.

Использование режима postfilter

После фильтрации фильтры применяются после выполнения запроса, сужая результаты поиска.

Схема постфильтров.

Тестовая проверка режимов векторного фильтра

Чтобы понять условия, при которых один режим фильтрации работает лучше, чем другой, мы выполнили ряд тестов для оценки результатов запроса по небольшим, средним и большим индексам.

  • Small (100 000 документов, индекс 2,5 ГБ, 1536 измерений)
  • Средний (1 миллион документов, индекс 25 ГБ, 1536 измерений)
  • Большой (1 миллиард документов, индекс 1,9 ТБ, 96 измерений)

Для небольших и средних рабочих нагрузок мы использовали службу Standard 2 (S2) с одной секцией и одной репликой. Для большой рабочей нагрузки мы использовали службу Standard 3 (S3) с 12 секциями и одной репликой.

Индексы имели идентичное построение: одно ключевое поле, одно векторное поле, одно текстовое поле и одно числовое фильтруемое поле. Следующий индекс определяется с помощью синтаксиса 2023-11-03.

def get_index_schema(self, index_name, dimensions):
    return {
        "name": index_name,
        "fields": [
            {"name": "id", "type": "Edm.String", "key": True, "searchable": True},
            {"name": "content_vector", "type": "Collection(Edm.Single)", "dimensions": dimensions,
              "searchable": True, "retrievable": True, "filterable": False, "facetable": False, "sortable": False,
              "vectorSearchProfile": "defaulthnsw"},
            {"name": "text", "type": "Edm.String", "searchable": True, "filterable": False, "retrievable": True,
              "sortable": False, "facetable": False},
            {"name": "score", "type": "Edm.Double", "searchable": False, "filterable": True,
              "retrievable": True, "sortable": True, "facetable": True}
        ],
      "vectorSearch": {
        "algorithms": [
            {
              "name": "defaulthnsw",
              "kind": "hnsw",
              "hnswParameters": { "metric": "euclidean" }
            }
          ],
          "profiles": [
            {
              "name": "defaulthnsw",
              "algorithm": "defaulthnsw"
            }
        ]
      }
    }

В запросах мы использовали идентичный фильтр для операций префильтратора и postfilter. Мы использовали простой фильтр, чтобы гарантировать, что изменения производительности были вызваны режимом фильтрации, а не сложностью фильтрации.

Результаты измерялись в запросах в секунду (QPS).

Общие выводы

  • Префильтрация почти всегда медленнее, чем послефильтровка, за исключением небольших индексов, где производительность приблизительно равна.

  • При более крупных наборах данных префильтровка значительно медленнее.

  • Поэтому почему префильтруйте значение по умолчанию, если это почти всегда медленнее? Префиксирование гарантирует, что k результаты возвращаются, если они существуют в индексе, где предвзятость благоприятствует отзыву и точности по скорости.

  • Postfiltering предназначен для клиентов, которые:

    • скорость выделения значений (послефильтровка может возвращать меньше k результатов)
    • использование фильтров, которые не являются чрезмерно выборочными
    • имеют индексы достаточного размера, чтобы производительность префильтрации неприемлема

Сведения

  • Учитывая набор данных с 100 000 векторами в 1536 измерениях:

    • При фильтрации более 30% набора данных префиксирование и послефильтровка были сопоставимыми.
    • При фильтрации менее 0,1% набора данных префильтровка составила около 50 % медленнее, чем послефильтровка.
  • Учитывая набор данных с 1 миллионами векторов на 1536 измерениях:

    • При фильтрации более 30% набора данных префиксирование составило около 30 % медленнее.
    • При фильтрации менее 2% набора данных префильтровка составила около семи раз медленнее.
  • Учитывая набор данных с 1 миллиардами векторов на 96 измерениях:

    • При фильтрации более 5% набора данных предварительная фильтрация составила около 50 % медленнее.
    • При фильтрации менее 10% набора данных предварительная фильтрация была примерно в семь раз медленнее.

На следующем графике показан относительный QPS префильтратора, вычисляемый как префильтратор QPS, разделенный на QPS послефильтратора.

Диаграмма с производительностью QPS для небольших, средних и больших индексов для относительного QPS.

Вертикальная ось — это QPS префильтрации по протоколу QPS после фильтрации. Например, значение 0,0 означает, что префильтровка составляет 100 % медленнее, 0,5 на вертикальной оси означает, что префильтровка составляет 50 % медленнее, 1,0 означает, что префильтровка и после фильтрации эквивалентны.

Горизонтальная ось представляет частоту фильтрации или процент кандидатов документов после применения фильтра. Например, означает, 1.00% что один процент корпуса поиска был выбран критериями фильтра.