Примеры синтаксиса полного поиска Lucene (расширенные запросы в поиске ИИ Azure)

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

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

Примечание.

Многие специализированные конструкции запросов, обеспечиваемые благодаря полному синтаксису запросов Lucene, не поддерживают анализ текста, что может оказаться неожиданным, если вы хотите использовать выделение корней слов или лемматизацию. Лексический анализ выполняется только для полными терминами (запрос термина или запрос фразы). Типы запросов с неполными терминами (запрос с префиксом, запрос с подстановочными знаками, запрос с регулярными выражениями, нечеткий запрос) добавляются непосредственно к дереву запроса в обход этапа анализа. Единственное преобразование для частичных терминов запроса — преобразование в нижний регистр.

Образец индекса гостиниц

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

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

Заголовки запросов должны иметь следующие значения:

Ключ Значение
Тип контента application/json
api-key <your-search-service-api-key>, либо запрос, либо ключ администратора

Параметры URI должны включать конечную точку службы поиска с именем индекса, коллекциями документов, командой поиска и версией API, как показано в следующем примере:

https://{{service-name}}.search.windows.net/indexes/hotels-sample-index/docs/search?api-version=2023-11-01

Текст запроса должен быть сформирован как допустимый текст JSON:

{
    "search": "*",
    "queryType": "full",
    "select": "HotelId, HotelName, Category, Tags, Description",
    "count": true
}
  • Если для параметра "search" задано значение *, это означает неопределенный запрос, эквивалентный нулевому или пустому поиску. Это не особенно полезно, но это самый простой поиск, который можно сделать, и он отображает все извлекаемые поля в индексе со всеми значениями.

  • параметр "queryType" имеет значение "full" — вызывается полноценное средство синтаксического анализа запросов Lucene, которое требуется для этого синтаксиса.

  • параметр "select" представляет собой разделенный запятыми список полей и используется для компоновки результатов поиска, включая только те поля, которые полезны в контексте результатов поиска.

  • Параметр "count" возвращает количество документов, соответствующих критериям поиска. В пустой строке поиска число всех документов в индексе (50 в индексе hotels-sample-index).

Область поиска по полям — отдельные встроенные выражения поиска для определенного поля. В этом примере выполняется поиск названий гостиниц с термином "гостиница", но не "мотель". Вы можете указать несколько полей, используя AND.

При использовании этого синтаксиса запроса можно опустить searchFields параметр, если поля, которые нужно запросить, находятся в самом выражении поиска. Если вы включаете searchFields в поле поиск, fieldName:searchExpression всегда имеет приоритет над searchFields.

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "HotelName:(hotel NOT motel) AND Category:'Resort and Spa'",
    "queryType": "full",
    "select": "HotelName, Category",
    "count": true
}

Ответ на этот запрос должен выглядеть примерно так, как показано в следующем примере, отфильтрованном на "Курорте и спа", возвращая отели, которые включают "hotel" в имя, исключая результаты, которые включают "мотель" в имя.

"@odata.count": 4,
"value": [
    {
        "@search.score": 4.481559,
        "HotelName": "Nova Hotel & Spa",
        "Category": "Resort and Spa"
    },
    {
        "@search.score": 2.4524608,
        "HotelName": "King's Palace Hotel",
        "Category": "Resort and Spa"
    },
    {
        "@search.score": 2.3970203,
        "HotelName": "Triple Landscape Hotel",
        "Category": "Resort and Spa"
    },
    {
        "@search.score": 2.2953436,
        "HotelName": "Peaceful Market Hotel & Spa",
        "Category": "Resort and Spa"
    }
]

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

  • HotelName:(hotel NOT motel)
  • Address/StateProvince:("WA" OR "CA")
  • Tags:("free wifi" NOT "free parking") AND "coffee in lobby"

Добавьте фразу в кавычках, если необходимо, чтобы обе строки считались одной сущностью, как в приведенном случае поиска двух разных мест в поле "Address/StateProvince". В зависимости от клиента может потребоваться экранирование (\) кавычек.

Поле, указанное в fieldName:searchExpression, должно быть доступным для поиска. Дополнительные сведения об атрибутах определений полей см. в разделе Создание индекса (REST API).

Нечеткий поиск работает с похожими терминами, включая слова с ошибками. Чтобы выполнить поиск нечетких соответствий, необходимо добавить символ тильды ~ в конце слова. Дополнительно можно поставить цифру от 0 до 2, указывающую расстояние редактирования. Например, blue~ или blue~1 вернет результаты с blue, blues и glue.

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "Tags:conserge~",
    "queryType": "full",
    "select": "HotelName, Category, Tags",
    "searchFields": "HotelName, Category, Tags",
    "count": true
}

Ответом на этот запрос будет "concierge" в соответствующих документах, обрезанных для краткости:

"@odata.count": 12,
"value": [
    {
        "@search.score": 1.1832147,
        "HotelName": "Secret Point Motel",
        "Category": "Boutique",
        "Tags": [
            "pool",
            "air conditioning",
            "concierge"
        ]
    },
    {
        "@search.score": 1.1819803,
        "HotelName": "Twin Dome Motel",
        "Category": "Boutique",
        "Tags": [
            "pool",
            "free wifi",
            "concierge"
        ]
    },
    {
        "@search.score": 1.1773309,
        "HotelName": "Smile Hotel",
        "Category": "Suite",
        "Tags": [
            "view",
            "concierge",
            "laundry service"
        ]
    },

Фразы не поддерживаются напрямую, но можно указать нечеткое соответствие для каждого термина многокомпонентной фразы, например search=Tags:landy~ AND sevic~. Это выражение запроса находит 15 совпадений с "laundry service".

Примечание.

Запросы с нечетким соответствием не анализируются. Типы запросов с неполными терминами (запрос с префиксом, запрос с подстановочными знаками, запрос с регулярными выражениями, нечеткий запрос) добавляются непосредственно к дереву запроса в обход этапа анализа. Единственное преобразование для частичных терминов запроса — преобразование в нижний регистр.

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

Данный запрос позволяет найти слова "hotel" и "airport", расположенные в пределах 5 слов друг от друга в документе. Кавычки экранируются (\") для сохранения фразы:

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "Description: \"hotel airport\"~5",
    "queryType": "full",
    "select": "HotelName, Description",
    "searchFields": "HotelName, Description",
    "count": true
}

Результат запроса должен выглядеть, как в примере ниже:

"@odata.count": 2,
"value": [
    {
        "@search.score": 0.6331726,
        "HotelName": "Trails End Motel",
        "Description": "Only 8 miles from Downtown.  On-site bar/restaurant, Free hot breakfast buffet, Free wireless internet, All non-smoking hotel. Only 15 miles from airport."
    },
    {
        "@search.score": 0.43032226,
        "HotelName": "Catfish Creek Fishing Cabins",
        "Description": "Brand new mattresses and pillows.  Free airport shuttle. Great hotel for your business needs. Comp WIFI, atrium lounge & restaurant, 1 mile from light rail."
    }
]

Пример 4. Повышение приоритета терминов

Повышение терминов относится к ранжированию документа выше, если он содержит увеличенный термин, относительно документов, которые не содержат термин. Чтобы повысить термин, используйте подсказку, ^символ с коэффициентом повышения (число) в конце термина, который выполняется поиск. Коэффициент увеличения по умолчанию равен 1, и хотя он должен быть положительным, он может быть меньше 1 (например, 0,2). Повышение приоритета терминов отличается от профилей повышения, так как они повышают приоритет определенных полей, а не определенных терминов.

В этом запросе "до" выполните поиск по запросу "beach access" и обратите внимание, что есть семь документов, соответствующих одному или обоим терминам.

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "beach access",
    "queryType": "full",
    "select": "HotelName, Description, Tags",
    "searchFields": "HotelName, Description, Tags",
    "count": true
}

На самом деле, есть только один документ, который соответствует "access", и потому что это единственное совпадение, это размещение является высоким (второе положение), даже если документ отсутствует термин "пляж".

"@odata.count": 7,
"value": [
    {
        "@search.score": 2.2723424,
        "HotelName": "Nova Hotel & Spa",
        "Description": "1 Mile from the airport.  Free WiFi, Outdoor Pool, Complimentary Airport Shuttle, 6 miles from the beach & 10 miles from downtown."
    },
    {
        "@search.score": 1.5507699,
        "HotelName": "Old Carrabelle Hotel",
        "Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center."
    },
    {
        "@search.score": 1.5358944,
        "HotelName": "Whitefish Lodge & Suites",
        "Description": "Located on in the heart of the forest. Enjoy Warm Weather, Beach Club Services, Natural Hot Springs, Airport Shuttle."
    },
    {
        "@search.score": 1.3433652,
        "HotelName": "Ocean Air Motel",
        "Description": "Oceanfront hotel overlooking the beach features rooms with a private balcony and 2 indoor and outdoor pools. Various shops and art entertainment are on the boardwalk, just steps away."
    },

В запросе "после" выполните этот поиск снова, при этом повышая приоритет результатов, содержащих термин "beach", относительно результатов, содержащих слово "access". search=Description:beach^2 access — доступная для чтения версия запроса. В зависимости от вашего клиента, вам может понадобиться выразить ^2 в виде %5E2.

После увеличения приоритета термина "beach" совпадение с Old Carrabelle Hotel перемещается на шестое место.

Пример 5. Регулярное выражение

Операция поиска по регулярным выражениям позволяет найти совпадение в зависимости от содержимого между косыми чертами "/", как указано в документации класса RegExp.

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "HotelName:/(Mo|Ho)tel/",
    "queryType": "full",
    "select": "HotelName",
    "count": true
}

Результат запроса должен выглядеть, как в примере ниже:

    "@odata.count": 22,
    "value": [
        {
            "@search.score": 1.0,
            "HotelName": "Days Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Triple Landscape Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Smile Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Pelham Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Sublime Cliff Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Twin Dome Motel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Nova Hotel & Spa"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Scarlet Harbor Hotel"
        },

Примечание.

Запросы с регулярными выражениями не анализируются. Единственное преобразование для частичных терминов запроса — преобразование в нижний регистр.

Вы можете использовать общепризнанный синтаксис для поиска с использованием нескольких подстановочных знаков (*) или одного (?). Обратите внимание, что средство синтаксического анализа запросов Lucene поддерживает использование этих символов для поиска одного слова, а не фразы.

В этом запросе найдите названия гостиниц, содержащие префикс "sc". Нельзя использовать * символ или ? символ в качестве первого символа поиска.

POST /indexes/hotel-samples-index/docs/search?api-version=2023-11-01
{
    "search": "HotelName:sc*",
    "queryType": "full",
    "select": "HotelName",
    "count": true
}

Результат запроса должен выглядеть, как в примере ниже:

    "@odata.count": 2,
    "value": [
        {
            "@search.score": 1.0,
            "HotelName": "Scarlet Harbor Hotel"
        },
        {
            "@search.score": 1.0,
            "HotelName": "Scottish Inn"
        }
    ]

Примечание.

Запросы с подстановочными знаками не анализируются. Единственное преобразование для частичных терминов запроса — преобразование в нижний регистр.

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

Попробуйте указать запросы в коде. В следующей ссылке описывается настройка поисковых запросов с помощью пакетов SDK Azure.

Дополнительные справочные материалы по синтаксису, архитектуре запросов и примерам см. в следующих ссылках: