Создайте консольное приложение с помощью клиентской библиотеки Azure.Search.Documents для добавления семантического ранжирования в существующий индекс поиска.
Кроме того, можно скачать исходный код , чтобы начать работу с готовым проектом.
Настройка среды
Запустите Visual Studio и создайте проект для консольного приложения.
В разделе Инструменты>Диспетчер пакетов NuGet выберите Управление пакетами NugGet для решения....
Выберите Обзор.
Найдите пакет Azure.Search.Documents и выберите последнюю стабильную версию.
Выберите " Установить" , чтобы добавить сборку в проект и решение.
Создание клиента для поиска
В Program.cs добавьте следующие using
директивы.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
Создайте два клиента: SearchIndexClient создает индекс, а SearchClient загружает и запрашивает существующий индекс.
Оба клиента нуждаются в конечной точке службы и ключе API администратора для проверки подлинности с правами создания и удаления. Однако код создает универсальный код ресурса (URI) для вас, поэтому укажите только имя службы поиска для serviceName
свойства. Не включайте или .search.windows.net
не включайтеhttps://
.
static void Main(string[] args)
{
string serviceName = "<YOUR-SEARCH-SERVICE-NAME>";
string apiKey = "<YOUR-SEARCH-ADMIN-API-KEY>";
string indexName = "hotels-quickstart";
// Create a SearchIndexClient to send create/delete index commands
Uri serviceEndpoint = new Uri($"https://{serviceName}.search.windows.net/");
AzureKeyCredential credential = new AzureKeyCredential(apiKey);
SearchIndexClient adminClient = new SearchIndexClient(serviceEndpoint, credential);
// Create a SearchClient to load and query documents
SearchClient srchclient = new SearchClient(serviceEndpoint, indexName, credential);
. . .
}
Создание индекса
Создайте или обновите схему индекса для включения SemanticConfiguration
. Если вы обновляете существующий индекс, это изменение не требует переиндексирования, так как структура документов не изменяется.
// Create hotels-quickstart index
private static void CreateIndex(string indexName, SearchIndexClient adminClient)
{
FieldBuilder fieldBuilder = new FieldBuilder();
var searchFields = fieldBuilder.Build(typeof(Hotel));
var definition = new SearchIndex(indexName, searchFields);
var suggester = new SearchSuggester("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" });
definition.Suggesters.Add(suggester);
definition.SemanticSearch = new SemanticSearch
{
Configurations =
{
new SemanticConfiguration("my-semantic-config", new()
{
TitleField = new SemanticField("HotelName"),
ContentFields =
{
new SemanticField("Description"),
new SemanticField("Description_fr")
},
KeywordsFields =
{
new SemanticField("Tags"),
new SemanticField("Category")
}
})
}
};
adminClient.CreateOrUpdateIndex(definition);
}
Следующий код создает индекс в службе поиска:
// Create index
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, adminClient);
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
Загрузка документов
Поиск azure AI выполняет поиск по содержимому, хранящемуся в службе. Код для отправки документов идентичен краткому руководству по C# для полнотекстового поиска , поэтому здесь не нужно дублировать его. У вас должно быть четыре отеля с именами, адресами и описаниями. Решение должно иметь типы для отелей и адресов.
Поиск в индексе
Ниже приведен запрос, вызывающий семантический рангер, с параметрами поиска для указания параметров:
Console.WriteLine("Example of a semantic query.");
options = new SearchOptions()
{
QueryType = Azure.Search.Documents.Models.SearchQueryType.Semantic,
SemanticSearch = new()
{
SemanticConfigurationName = "my-semantic-config",
QueryCaption = new(QueryCaptionType.Extractive)
}
};
options.Select.Add("HotelName");
options.Select.Add("Category");
options.Select.Add("Description");
// response = srchclient.Search<Hotel>("*", options);
response = srchclient.Search<Hotel>("what hotel has a good restaurant on site", options);
WriteDocuments(response);
Для сравнения ниже приведены результаты запроса, использующего ранжирование по умолчанию BM25 на основе частоты терминов и близости. Учитывая запрос "что отель имеет хороший ресторан на сайте", алгоритм ранжирования BM25 возвращает совпадения в порядке, показанном на этом снимке экрана:
В отличие от этого, при применении семантического ранжирования к тому же запросу ("что отель имеет хороший ресторан на сайте"), результаты повторно выполняются на основе семантической релевантности запроса. На этот раз лучший результат — отель с рестораном, который лучше соответствует ожиданиям пользователей.
Запуск программы
Нажмите клавишу F5, чтобы перестроить приложение и запустить полнофункциональную программу.
Выходные данные содержат сообщения из Console.WriteLine, а также сведения о запросе и результаты.
Используйте записную книжку Jupyter и библиотеку документов azure-search-documents в пакете SDK Azure для Python, чтобы узнать о семантической ранжировании.
Кроме того, можно скачать и запустить завершенную записную книжку.
Настройка среды
Используйте Visual Studio Code с расширением Python или эквивалентной интегрированной среды разработки с Python 3.10 или более поздней версии.
Для этого краткого руководства рекомендуется использовать виртуальную среду:
Запустите Visual Studio Code.
Создайте файл ipynb.
Откройте палитру команд с помощью клавиш CTRL+SHIFT+P.
Поиск Python : создание среды.
Выберите Venv.
Выбор интерпретатора Python Выберите 3.10 или более поздней версии.
Для настройки может потребоваться несколько минут. Если возникнут проблемы, ознакомьтесь со средами Python в VS Code.
Установка пакетов и установка переменных
Установите пакеты, включая документы azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet
! pip install azure-identity --quiet
! pip install python-dotenv --quiet
Укажите ключи конечной точки и API:
search_endpoint: str = "PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE"
search_api_key: str = "PUT-YOUR-SEARCH-SERVICE-ADMIN-API-KEY-HERE"
index_name: str = "hotels-quickstart"
Создание индекса
Создайте или обновите схему индекса для включения SemanticConfiguration
. Если вы обновляете существующий индекс, это изменение не требует переиндексирования, так как структура документов не изменяется.
from azure.search.documents.indexes import SearchIndexClient
from azure.search.documents import SearchClient
from azure.search.documents.indexes.models import (
ComplexField,
SimpleField,
SearchFieldDataType,
SearchableField,
SearchIndex,
SemanticConfiguration,
SemanticField,
SemanticPrioritizedFields,
SemanticSearch
)
# Create a search schema
index_client = SearchIndexClient(
endpoint=search_endpoint, credential=credential)
fields = [
SimpleField(name="HotelId", type=SearchFieldDataType.String, key=True),
SearchableField(name="HotelName", type=SearchFieldDataType.String, sortable=True),
SearchableField(name="Description", type=SearchFieldDataType.String, analyzer_name="en.lucene"),
SearchableField(name="Description_fr", type=SearchFieldDataType.String, analyzer_name="fr.lucene"),
SearchableField(name="Category", type=SearchFieldDataType.String, facetable=True, filterable=True, sortable=True),
SearchableField(name="Tags", collection=True, type=SearchFieldDataType.String, facetable=True, filterable=True),
SimpleField(name="ParkingIncluded", type=SearchFieldDataType.Boolean, facetable=True, filterable=True, sortable=True),
SimpleField(name="LastRenovationDate", type=SearchFieldDataType.DateTimeOffset, facetable=True, filterable=True, sortable=True),
SimpleField(name="Rating", type=SearchFieldDataType.Double, facetable=True, filterable=True, sortable=True),
ComplexField(name="Address", fields=[
SearchableField(name="StreetAddress", type=SearchFieldDataType.String),
SearchableField(name="City", type=SearchFieldDataType.String, facetable=True, filterable=True, sortable=True),
SearchableField(name="StateProvince", type=SearchFieldDataType.String, facetable=True, filterable=True, sortable=True),
SearchableField(name="PostalCode", type=SearchFieldDataType.String, facetable=True, filterable=True, sortable=True),
SearchableField(name="Country", type=SearchFieldDataType.String, facetable=True, filterable=True, sortable=True),
])
]
semantic_config = SemanticConfiguration(
name="my-semantic-config",
prioritized_fields=SemanticPrioritizedFields(
title_field=SemanticField(field_name="HotelName"),
keywords_fields=[SemanticField(field_name="Category")],
content_fields=[SemanticField(field_name="Description")]
)
)
# Create the semantic settings with the configuration
semantic_search = SemanticSearch(configurations=[semantic_config])
semantic_settings = SemanticSearch(configurations=[semantic_config])
scoring_profiles = []
suggester = [{'name': 'sg', 'source_fields': ['Tags', 'Address/City', 'Address/Country']}]
# Create the search index with the semantic settings
index = SearchIndex(name=index_name, fields=fields, suggesters=suggester, scoring_profiles=scoring_profiles, semantic_search=semantic_search)
result = index_client.create_or_update_index(index)
print(f' {result.name} created')
Создание полезных данных документов
Документы JSON можно отправить в индекс поиска. Документы должны соответствовать схеме индекса.
documents = [
{
"@search.action": "upload",
"HotelId": "1",
"HotelName": "Stay-Kay City Hotel",
"Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
"Description_fr": "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
"Category": "Boutique",
"Tags": [ "pool", "air conditioning", "concierge" ],
"ParkingIncluded": "false",
"LastRenovationDate": "1970-01-18T00:00:00Z",
"Rating": 3.60,
"Address": {
"StreetAddress": "677 5th Ave",
"City": "New York",
"StateProvince": "NY",
"PostalCode": "10022",
"Country": "USA"
}
},
{
"@search.action": "upload",
"HotelId": "2",
"HotelName": "Old Century Hotel",
"Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts.",
"Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
"Category": "Boutique",
"Tags": [ "pool", "free wifi", "concierge" ],
"ParkingIncluded": "false",
"LastRenovationDate": "1979-02-18T00:00:00Z",
"Rating": 3.60,
"Address": {
"StreetAddress": "140 University Town Center Dr",
"City": "Sarasota",
"StateProvince": "FL",
"PostalCode": "34243",
"Country": "USA"
}
},
{
"@search.action": "upload",
"HotelId": "3",
"HotelName": "Gastronomic Landscape Hotel",
"Description": "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel's restaurant services.",
"Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
"Category": "Resort and Spa",
"Tags": [ "air conditioning", "bar", "continental breakfast" ],
"ParkingIncluded": "true",
"LastRenovationDate": "2015-09-20T00:00:00Z",
"Rating": 4.80,
"Address": {
"StreetAddress": "3393 Peachtree Rd",
"City": "Atlanta",
"StateProvince": "GA",
"PostalCode": "30326",
"Country": "USA"
}
},
{
"@search.action": "upload",
"HotelId": "4",
"HotelName": "Sublime Palace Hotel",
"Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Palace is part of a lovingly restored 1800 palace.",
"Description_fr": "Le Sublime Palace Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Palace fait partie d'un Palace 1800 restauré avec amour.",
"Category": "Boutique",
"Tags": [ "concierge", "view", "24-hour front desk service" ],
"ParkingIncluded": "true",
"LastRenovationDate": "1960-02-06T00:00:00Z",
"Rating": 4.60,
"Address": {
"StreetAddress": "7400 San Pedro Ave",
"City": "San Antonio",
"StateProvince": "TX",
"PostalCode": "78216",
"Country": "USA"
}
}
]
Отправка документов в индекс
search_client = SearchClient(endpoint=search_endpoint,
index_name=index_name,
credential=credential)
try:
result = search_client.upload_documents(documents=documents)
print("Upload of new document succeeded: {}".format(result[0].succeeded))
except Exception as ex:
print (ex.message)
index_client = SearchIndexClient(
endpoint=search_endpoint, credential=credential)
Выполните первый запрос
Начните с пустого запроса в качестве шага проверки, доказав, что индекс работает. Вы должны получить неупорядоченный список имен и описаний отелей с количеством 4, указывающих на наличие четырех документов в индексе.
# Run an empty query (returns selected fields, all documents)
results = search_client.search(query_type='simple',
search_text="*" ,
select='HotelName,Description',
include_total_count=True)
print ('Total Documents Matching Query:', results.get_count())
for result in results:
print(result["@search.score"])
print(result["HotelName"])
print(f"Description: {result['Description']}")
Выполнение текстового запроса
Для сравнения выполните текстовый запрос с оценкой релевантности BM25. При предоставлении строки запроса вызывается полнотекстовый поиск. Ответ состоит из ранжированных результатов, где более высокие оценки присваиваются документам с большим количеством экземпляров соответствующих терминов или более важными терминами.
В этом запросе на то, что отель имеет хороший ресторан на сайте, Sublime Palace Hotel выходит сверху, потому что его описание включает сайт. Термины, которые происходят редко, вызывают оценку поиска документа.
# Run a text query (returns a BM25-scored result set)
results = search_client.search(query_type='simple',
search_text="what hotel has a good restaurant on site" ,
select='HotelName,HotelId,Description',
include_total_count=True)
for result in results:
print(result["@search.score"])
print(result["HotelName"])
print(f"Description: {result['Description']}")
Выполнение семантического запроса
Теперь добавьте семантический рейтинг. Новые параметры включают query_type
и semantic_configuration_name
.
Это тот же запрос, но обратите внимание, что семантический рангер правильно определяет гастрономический альбомный отель в качестве более релевантного результата, учитывая первоначальный запрос. Этот запрос также возвращает заголовки, созданные моделями. Входные данные слишком минимальны в этом примере, чтобы создать интересные субтитры, но пример успешно демонстрирует синтаксис.
# Runs a semantic query (runs a BM25-ranked query and promotes the most relevant matches to the top)
results = search_client.search(query_type='semantic', semantic_configuration_name='my-semantic-config',
search_text="what hotel has a good restaurant on site",
select='HotelName,Description,Category', query_caption='extractive')
for result in results:
print(result["@search.reranker_score"])
print(result["HotelName"])
print(f"Description: {result['Description']}")
captions = result["@search.captions"]
if captions:
caption = captions[0]
if caption.highlights:
print(f"Caption: {caption.highlights}\n")
else:
print(f"Caption: {caption.text}\n")
Возврат семантических ответов
В этом окончательном запросе возвращаются семантические ответы.
Семантический рангер может создавать ответы на строку запроса, которая имеет характеристики вопроса. Созданный ответ извлекается из содержимого. Чтобы получить семантический ответ, вопрос и ответ должны быть тесно согласованы, и модель должна найти содержимое, которое четко отвечает на этот вопрос. Если потенциальные ответы не соответствуют порогу достоверности, модель не возвращает ответ. В демонстрационных целях вопрос в этом примере предназначен для получения ответа, чтобы увидеть синтаксис.
# Run a semantic query that returns semantic answers
results = search_client.search(query_type='semantic', semantic_configuration_name='my-semantic-config',
search_text="what hotel is in a historic building",
select='HotelName,Description,Category', query_caption='extractive', query_answer="extractive",)
semantic_answers = results.get_answers()
for answer in semantic_answers:
if answer.highlights:
print(f"Semantic Answer: {answer.highlights}")
else:
print(f"Semantic Answer: {answer.text}")
print(f"Semantic Answer Score: {answer.score}\n")
for result in results:
print(result["@search.reranker_score"])
print(result["HotelName"])
print(f"Description: {result['Description']}")
captions = result["@search.captions"]
if captions:
caption = captions[0]
if caption.highlights:
print(f"Caption: {caption.highlights}\n")
else:
print(f"Caption: {caption.text}\n")