Полнотекстовый поиск в поиске ИИ Azure

Полнотекстовый поиск — это подход к получению информации, которая соответствует обычному тексту, хранящемуся в индексе. Например, учитывая строку запроса "отели в Сан-Диего на пляже", поисковая система ищет токенизованные строки на основе этих терминов. Чтобы сделать сканирование более эффективными, строки запроса проходят лексический анализ: нижний регистр всех терминов, удаление слов остановки, таких как "the", и сокращение терминов до примитивных корневых форм. При обнаружении соответствующих терминов поисковая система извлекает документы, ранжирует их по порядку релевантности и возвращает первые результаты.

Выполнение запроса может быть сложным. Эта статья предназначена для разработчиков, которые нуждаются в более глубоком понимании того, как работает полнотекстовый поиск в службе "Поиск ИИ Azure". Для текстовых запросов поиск Azure AI легко обеспечивает ожидаемые результаты в большинстве сценариев, но иногда вы можете получить результат, который кажется "отключенным" как-то. В таких ситуациях наличие фона на четырех этапах выполнения запроса Lucene (анализ запросов, лексический анализ, сопоставление документов, оценка) поможет определить конкретные изменения в параметрах запроса или конфигурации индекса, которые создают нужный результат.

Примечание.

Поиск ИИ Azure использует Apache Lucene для полнотекстового поиска, но интеграция Lucene не является исчерпывающей. Мы выборочно предоставляем и расширяем функциональные возможности Lucene, чтобы обеспечить сценарии, важные для поиска ИИ Azure.

Схема архитектуры и ее обзор

Выполнение запроса состоит из четырех этапов:

  1. синтаксический анализ запроса;
  2. Лексический анализ
  3. извлечение документа;
  4. Очки

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

На схеме ниже представлены компоненты, используемые для обработки поискового запроса.

Lucene query architecture diagram in Azure AI Search.

Ключевые компоненты Описание функций
Средства синтаксического анализа запроса Отделяют термины запроса от операторов и создают структуру запроса (дерево запроса), которая отправляется в поисковую систему.
Анализаторы Выполняют лексический анализ терминов запроса, что может включать их преобразование, удаление или расширение.
Указатель Эффективная структура данных, используемая для хранения и упорядочивания доступных для поиска терминов, извлеченных из индексированных документов.
Поисковая система Извлекает и оценивает совпадающие документы на основе содержимого обращенного индекса.

Схема поискового запроса

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

В следующем примере приведен запрос поиска, который можно отправить в службу "Поиск ИИ Azure" с помощью REST API.

POST /indexes/hotels/docs/search?api-version=2020-06-30
{
    "search": "Spacious, air-condition* +\"Ocean view\"",
    "searchFields": "description, title",
    "searchMode": "any",
    "filter": "price ge 60 and price lt 300",
    "orderby": "geo.distance(location, geography'POINT(-159.476235 22.227659)')", 
    "queryType": "full" 
}

Для этого запроса поисковая система выполняет следующие операции:

  1. Находит документы, где цена составляет не менее $60 и менее $ 300.

  2. Выполняет запрос. В этом примере поисковый запрос содержит следующие фразы и термины: "Spacious, air-condition* +\"Ocean view\"" (пользователи обычно не вводят знаки пунктуации, но здесь они помогут нам объяснить, каким образом такой запрос обрабатывают анализаторы).

    Для этого запроса поисковая система сканирует поля описания и заголовка, указанные в searchFields, для документов, содержащих "Ocean view", а также в терминах "spacious", начинающихся с префикса "air-condition". Параметр searchMode используется для сопоставления с любым термином (по умолчанию) или всеми из них, в тех случаях, когда термин не является явным образом обязательным (+).

  3. Заказывает результирующий набор отелей по близости к заданному географическому расположению, а затем возвращает результаты вызывающему приложению.

Большая часть этой статьи заключается в обработке поискового запроса: "Spacious, air-condition* +\"Ocean view\"" Фильтрация и упорядочение выходят за рамки этого руководства. Дополнительные сведения см. в статье о поиске документов с помощью интерфейса REST API службы поиска Azure.

Этап 1. Синтаксический анализ запроса

Как было отмечено, строка запроса — это первая строка.

 "search": "Spacious, air-condition* +\"Ocean view\"", 

Средство синтаксического анализа запросов отделяет операторы (* и + в нашем примере) от поисковых терминов, а затем заново формирует поисковый запрос, создавая вложенные запросы поддерживаемого типа:

  • запрос термина — для автономных терминов (например, spacious);
  • запрос фразы — для терминов, заключенных в кавычки (например, ocean view);
  • запрос префикса — для терминов, за которыми следует оператор префикса * (например, air-condition).

Полный список поддерживаемых типов запросов см . в синтаксисе запросов Lucene

Операторы, связанные с вложенными запросами, определяют, обязательно ли должен быть удовлетворен запрос, чтобы документ рассматривался в качестве подходящего. Например, запрос +"Ocean view" является обязательным, так как указан оператор +.

Средство синтаксического анализа запросов перестраивает вложенные запросы в дерево запроса (внутреннюю структуру, представляющую запрос), которое передается в поисковую систему. На первом этапе синтаксического анализа запроса дерево запроса выглядит следующим образом:

Conceptual diagram of a boolean query with searchmode set to any.

Поддерживаемые средства синтаксического анализа запроса для упрощенного и полного языка запросов Lucene

Поиск по искусственному интеллекту Azure предоставляет два разных языка запросов ( simple по умолчанию) и full. Задавая параметр queryType для поискового запроса, вы сообщаете средству синтаксического анализа запросов выбранный язык запросов для верной интерпретации операторов и синтаксиса.

  • Язык простых запросов является интуитивно понятным и надежным. В большинстве случаев он подходит для интерпретации введенных пользователем данных как есть, то есть без обработки на стороне клиента. Он поддерживает те же операторы запросов,что и поисковые системы в Интернете.

  • Язык расширенных запросов Lucene. Чтобы задать этот язык, необходимо установить параметр queryType=full. Этот язык поддерживает большее количество типов операторов и запросов, например поиск нечетких соответствий, запросы с подстановочными знаками, регулярными выражениями и запросы, относящиеся к полям. Например, регулярное выражение, отправленное в простой синтаксис запросов, будет интерпретироваться как строка запроса, а не как выражение. В нашем примере запроса используется язык расширенных запросов Lucene.

Влияние параметра searchMode на средство синтаксического анализа

Другим параметром запроса поиска, влияющим на синтаксический анализ, является параметр searchMode. Он управляет оператором по умолчанию для логических запросов: any (по умолчанию) или all.

Если "searchMode=any", который является значением по умолчанию, разделитель пространства между просторным и кондиционером имеет значение OR (||), что эквивалентно тексту примера запроса:

Spacious,||air-condition*+"Ocean view" 

Явные операторы, например + в +"Ocean view", являются однозначными в конструкции логического запроса (для обязательного соответствия). Но как же будут интерпретироваться оставшиеся термины: spacious и air-condition? Нужно ли поисковой системе искать соответствия, где содержатся все термины: ocean view, spaciousи air-condition? Или же нужно найти ocean view и какой-либо из оставшихся терминов?

По умолчанию ("searchMode=any"), поисковая система предполагает более широкую интерпретацию. Будет выполняться поиск соответствия по какому-либо из терминов, что представляет семантику оператора or. Исходное дерево запроса выше с двумя необязательными операциями соответствует режиму по умолчанию.

Предположим, что теперь задано значение searchMode=all. В этом случае пробел интерпретируется как оператор and. Каждый из оставшихся терминов обязательно должен находиться в документе для соответствия запросу. Результирующий пример запроса будет интерпретирован следующим образом:

+Spacious,+air-condition*+"Ocean view"

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

Conceptual diagram of a boolean query with searchmode set to all.

Примечание.

Выбор "searchMode=any" на "searchMode=all" является решением, наиболее подходящим для выполнения репрезентативных запросов. Пользователи, которые, скорее всего, включают операторы (распространенные при поиске в хранилищах документов), могут найти результаты более интуитивно понятными, если searchMode=all сообщает логическим конструкциям запросов. Дополнительные сведения о взаимодействии между searchMode и операторами см. в синтаксисе простого запроса.

Этап 2. Лексический анализ

Лексические анализаторы обрабатывают запросы терминов и запросы фраз после формирования дерева запроса. Анализатор принимает текстовые входные данные, предоставленные ему синтаксическим анализатором, обрабатывает их, а затем отправляет обратно термины, снабженные маркером, для их последующего включения в дерево запроса.

Наиболее распространенная форма лексического анализа — *лингвистический анализ, который преобразует термины запросов на основе правил, относящихся к заданному языку:

  • сокращает термин запроса, оставляя только корень слова;
  • удаляет слова, которые не представляют смысла (стоп-слова, например артикли the и and в английском языке);
  • разбивает составные слова на части;
  • преобразовывает слова с верхним регистром в нижний.

Цель всех этих операций — стереть различия между текстовыми входными данными, предоставленными пользователем, и терминами, сохраненными в индексе. Эти операции выходят за рамки обработки текста и требуют глубоких знаний самого языка. Чтобы добавить этот уровень лингвистической осведомленности, поиск ИИ Azure поддерживает длинный список анализаторов языка как Lucene, так и Майкрософт.

Примечание.

Требования анализа могут варьироваться от минимальных до четко детализированных в зависимости от вашего сценария. Вы можете контролировать уровень сложности лексического анализа, выбрав один из стандартных анализаторов или же создав свой собственный пользовательский анализатор. Анализаторы могут использоваться в пределах полей, поддерживающих поиск, и задаются как часть определения поля. Таким образом, вы можете изменять лексический анализ на основе поля. Если конкретное определение не указано, используется стандартный анализатор Lucene.

В нашем примере перед анализом исходное дерево запросов имеет термин "Просторный", с верхним регистром "S" и запятой, которую средство синтаксического анализа запросов интерпретирует как часть термина запроса (запятая не считается оператором языка запросов).

Когда анализатор по умолчанию обрабатывает этот термин, "ocean view" и "spacious" преобразуются в нижний регистр, а запятая удаляется. Измененное дерево запросов выглядит следующим образом:

Conceptual diagram of a boolean query with analyzed terms.

Проверка поведения анализатора

Поведение анализатора можно проверить с помощью API анализа. Укажите текст, который нужно проанализировать, чтобы увидеть, какие термины создаются анализатором. Например, чтобы увидеть, каким образом стандартный анализатор будет обрабатывать текст "air-condition", вы можете использовать запрос ниже.

{
    "text": "air-condition",
    "analyzer": "standard"
}

Стандартный анализатор разбивает входной текст на два следующих маркера, создавая для них атрибуты — startOffset и endOffset (используемые для выделения совпадений), а также атрибут position (для поиска совпадения фразы).

{
  "tokens": [
    {
      "token": "air",
      "startOffset": 0,
      "endOffset": 3,
      "position": 0
    },
    {
      "token": "condition",
      "startOffset": 4,
      "endOffset": 13,
      "position": 1
    }
  ]
}

Исключения лексического анализа

Лексический анализ применяется только к типам запросов, требующим поиска либо термина, либо фразы. Его нельзя применить к типам запросов с неполными терминами — запросам по префиксу, подстановочному знаку, регулярному выражению или поиску нечетких соответствий. Такие типы запросов, в том числе запрос префикса с термином air-condition* в нашем примере, добавляются непосредственно в дерево запроса, минуя этап анализа. Единственное преобразование для терминов запроса такого типа — преобразование в нижний регистр.

Этап 3. Извлечение документа

Извлечение документа относится к поиску документов с совпадающими терминами в индексе. Лучше всего этот этап рассмотреть на примере. Начнем с индекса отелей. Итак, у нас есть следующая схема:

{
    "name": "hotels",
    "fields": [
        { "name": "id", "type": "Edm.String", "key": true, "searchable": false },
        { "name": "title", "type": "Edm.String", "searchable": true },
        { "name": "description", "type": "Edm.String", "searchable": true }
    ] 
} 

Предположим, что этот индекс содержит следующие четыре документа:

{
    "value": [
        {
            "id": "1",
            "title": "Hotel Atman",
            "description": "Spacious rooms, ocean view, walking distance to the beach."
        },
        {
            "id": "2",
            "title": "Beach Resort",
            "description": "Located on the north shore of the island of Kauaʻi. Ocean view."
        },
        {
            "id": "3",
            "title": "Playa Hotel",
            "description": "Comfortable, air-conditioned rooms with ocean view."
        },
        {
            "id": "4",
            "title": "Ocean Retreat",
            "description": "Quiet and secluded"
        }
    ]
}

Как индексируются термины

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

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

  1. В зависимости от конфигурации анализатора текстовые входные данные передаются в анализатор, преобразуются в нижний регистр, знаки пунктуации в них удаляются и т. д.
  2. Токены являются выходными данными текстового анализа.
  3. Термины добавляются в индекс.

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

Примечание.

Поиск ИИ Azure позволяет указать различные анализаторы для индексирования и поиска с помощью дополнительных indexAnalyzer параметров поля searchAnalyzer . Если их не указать, анализатор с заданным свойством analyzer будет использоваться для двух операций — индексирования и поиска.

Обращенный индекс для примеров документов

Возвращаясь к нашему примеру, для поля заголовка обращенный индекс будет выглядеть следующим образом:

Термин Список документов
atman 1
пляж 2
hotel 1, 3
ocean 4
playa 3
resort 3
retreat 4

В поле заголовка только hotel встречается в двух документах — 1 и 3.

Для поля описания индекс выглядит следующим образом:

Термин Список документов
air 3
и 4
пляж 1
conditioned 3
comfortable 3
distance 1
island 2
kauaʻi 2
located 2
north 2
ocean 1, 2, 3
из 2
on 2
quiet 4
rooms 1, 3
secluded 4
берег 2
spacious 1
мыши 1, 2
до 1
view 1, 2, 3
walking 1
на 3

Соответствие терминов запроса индексированным терминам

Учитывая инвертированные индексы выше, давайте вернемся к образцу запроса и посмотрим, как найдены соответствующие документы для нашего примера запроса. Вспомним, что конечное дерево запроса выглядит следующим образом:

Conceptual diagram of a boolean query with analyzed terms.

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

  • Запрос термина "spacious" соответствует документу 1 (Hotel Atman).

  • Запрос префикса "air-condition*" не соответствует ни одному документу.

    Именно такие случаи и запутывают разработчиков. Несмотря на то, что термин кондиционера существует в документе, он разделен на два термина по анализатору по умолчанию. Помните, что запросы префикса, содержащие частичные термины, не анализируются. Именно поэтому при поиске в обращенном индексе термины с префиксом "air-condition" не найдены.

  • Для запроса фразы "ocean view" был выполнен поиск по терминам "ocean" и "view" и проверка на приблизительные соответствия в исходном документе. Документы 1, 2 и 3 содержат совпадение в поле описания. Обратите внимание, документ 4 содержит термин ocean в заголовке, но соответствие не найдено, так как мы искали фразу "ocean view", а не отдельные слова.

Примечание.

Поисковый запрос выполняется независимо от всех полей, доступных для поиска в индексе поиска ИИ Azure, если вы не ограничиваете поля, заданные параметром searchFields , как показано в примере поискового запроса. Возвращаются документы, содержащие совпадение в любом из выбранных полей.

В целом для рассматриваемого запроса возвращаются документы 1, 2 и 3.

Этап 4. Оценка

Каждому документу в результирующем наборе поиска присваивается оценка релевантности. Функция оценки релевантности — задать более высокий приоритет документам, которые лучше соответствуют вопросам пользователей, выраженным в поисковом запросе. Оценка вычисляется на основе статистических свойств терминов, для которых найдены соответствия. Основным элементом формулы оценки является TF-IDF (частота встречаемости термина — обратная частота документа). В запросах, содержащих редкие и распространенные термины, TF-IDF придает большую важность результатам для терминов, которые встречаются нечасто. Например, в гипотетическом индексе со всеми статьями Wikipedia среди документов, содержащих поисковой термин the president, документы, содержащие president, будут более релевантными по сравнению с теми, которые содержат the.

Пример оценки

Вспомните три документа, которые соответствовали примеру запроса:

search=Spacious, air-condition* +"Ocean view"  
{
  "value": [
    {
      "@search.score": 0.25610128,
      "id": "1",
      "title": "Hotel Atman",
      "description": "Spacious rooms, ocean view, walking distance to the beach."
    },
    {
      "@search.score": 0.08951007,
      "id": "3",
      "title": "Playa Hotel",
      "description": "Comfortable, air-conditioned rooms with ocean view."
    },
    {
      "@search.score": 0.05967338,
      "id": "2",
      "title": "Ocean Resort",
      "description": "Located on a cliff on the north shore of the island of Kauai. Ocean view."
    }
  ]
}

Документ 1 лучше всего соответствовал запросу, так как в его поле описания содержится и термин spacious, и обязательная фраза ocean view. Следующие два документа содержат только фразу ocean view. Наверное, неожиданно, что оценка релевантности для документов 2 и 3 различна, хотя они одинаковым образом соответствовали запросу. Так произошло из-за того, что формула оценки не ограничивается лишь компонентом TF-IDF. В этом случае документу 3 была присвоена оценка выше, так как его описание короче. Ознакомьтесь с практической формулой оценки Lucene, чтобы узнать, как длина поля и другие факторы влияют на оценку релевантности.

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

В примере объясняется, почему это важно. Поиск с использованием подстановочных знаков, включая поиск с использованием префикса, является однозначным по определению, так как входное содержимое представляет частичную строку с потенциальными совпадениями в больших количествах разрозненных терминов (например, термин "tour*", для которого находятся соответствия tours, tourettes и tourmaline). Учитывая характер этих результатов, нет способа разумно определить, какие термины являются более ценными, чем другие. Именно поэтому при оценке результатов в запросах с подстановочными знаками, префиксами и регулярными выражениями стоит игнорировать частоту встречаемости термина. Во множественном поисковом запросе, который включает частичные и полные термины, результаты из неполных входных данных объединяются с постоянной оценкой, чтобы избежать смещения по отношению к потенциально неожиданным соответствиям.

Настройка релевантности

Существует два способа настройки показателей релевантности в службе "Поиск ИИ Azure":

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

  2. Повышение приоритета слов (доступно только в синтаксисе расширенных запросов Lucene) достигается с помощью оператора ^, который можно применить к любой части дерева запроса. В нашем примере вместо поиска по префиксу air-condition* можно выполнить поиск по точному термину air-condition или префиксу, но документы с соответствием точному термину будут ранжированы выше, так как для запроса применен оператор повышения приоритета — air-condition^2||air-condition*. Дополнительные сведения о повышении терминов в запросе.

Оценка в распределенном индексе

Все индексы в поиске ИИ Azure автоматически разделяются на несколько сегментов, что позволяет быстро распределять индекс между несколькими узлами во время увеличения или уменьшения масштаба службы. Когда инициирован поисковый запрос, он выполняется отдельно для каждого сегмента. Затем результаты из каждого сегмента объединяются и упорядочиваются по оценке (если не определен другой порядок). Важно знать, что функция оценки весовая частота запроса к его обратной частоте документа во всех документах в сегменте, а не во всех сегментах!

Это значит, что оценка релевантности может отличаться для идентичных документов, если они находятся в разных сегментах. К счастью, подобные различия обычно исчезают по мере увеличения документов в индексе, что происходит благодаря более равномерному распределению термина. Невозможно предположить, в какой именно сегмент будет помещен любой из документов. Но так как, вероятнее всего, ключ документа не меняется, он всегда будет присвоен одному сегменту.

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

Заключение

Успех коммерческих поисковых систем вызвал ожидания полнотекстового поиска по частным данным. Теперь мы ожидаем, что независимо от типа поиска система будет распознавать наши намерения, даже если используются термины с ошибками или же неполные термины. Мы даже можем ожидать совпадений на основе почти эквивалентных терминов или синонимов, которые мы никогда не указали.

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

В этой статье рассматриваются полнотекстовый поиск в контексте поиска ИИ Azure. Мы надеемся, вы достаточно хорошо разобрались с этим вопросом и сможете применить полученные знания для разрешения распространенных проблем запросов.

Следующие шаги

См. также

Search Documents (Azure Search Service REST API) (Поиск по документам (REST API службы поиска Azure))

Синтаксис простых запросов

Lucene query syntax in Azure Search (Синтаксис запросов Lucene в службе поиска Azure)

Обработка результатов поиска