Skapa ett konsolprogram med hjälp av klientbiblioteket Azure.Search.Documents för att lägga till semantisk rangordning i ett befintligt sökindex.
Du kan också ladda ned källkoden för att börja med ett färdigt projekt.
Konfigurera din miljö
Starta Visual Studio och skapa ett nytt projekt för en konsolapp.
I Verktyg>NuGet Package Manager väljer du Hantera NuGet-paket för lösning....
Välj bläddra.
Sök efter paketet Azure.Search.Documents och välj den senaste stabila versionen.
Välj Installera för att lägga till sammansättningen i projektet och lösningen.
Skapa en sökklient
Lägg till följande using
direktiv i Program.cs.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
Skapa två klienter: SearchIndexClient skapar indexet och SearchClient läser in och frågar ett befintligt index.
Båda klienterna behöver tjänstslutpunkten och en administratörs-API-nyckel för autentisering med behörighet att skapa/ta bort. Koden skapar dock URI:n åt dig, så ange endast söktjänstens namn för serviceName
egenskapen. Inkludera https://
inte eller .search.windows.net
.
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);
. . .
}
Skapa ett index
Skapa eller uppdatera ett indexschema för att inkludera en SemanticConfiguration
. Om du uppdaterar ett befintligt index kräver den här ändringen ingen omindexering eftersom strukturen för dina dokument är oförändrad.
// 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);
}
Följande kod skapar indexet för söktjänsten:
// Create index
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, adminClient);
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
Läsa in dokument
Azure AI Search söker efter innehåll som lagras i tjänsten. Koden för att ladda upp dokument är identisk med C#-snabbstarten för fulltextsökning så vi behöver inte duplicera den här. Du bör ha fyra hotell med namn, adresser och beskrivningar. Din lösning bör ha typer för hotell och adresser.
Sök i ett index
Här är en fråga som anropar semantisk ranker, med sökalternativ för att ange parametrar:
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);
Som jämförelse finns här resultat från en fråga som använder BM25-standardrankningen baserat på termfrekvens och närhet. Med tanke på frågan "vilket hotell har en bra restaurang på plats" returnerar BM25-rankningsalgoritmen matchningar i den ordning som visas i den här skärmbilden:
När semantisk rangordning däremot tillämpas på samma fråga ("vilket hotell har en bra restaurang på plats" rangordnas resultaten om baserat på semantisk relevans för frågan. Den här gången är det högsta resultatet hotellet med restaurangen, vilket överensstämmer bättre med användarnas förväntningar.
Köra programmet
Tryck på F5 för att återskapa appen och köra programmet i sin helhet.
Utdata innehåller meddelanden från Console.WriteLine, med tillägg av frågeinformation och resultat.
Använd en Jupyter-anteckningsbok och biblioteket azure-search-documents i Azure SDK för Python för att lära dig mer om semantisk rangordning.
Du kan också ladda ned och köra en färdig notebook-fil.
Konfigurera din miljö
Använd Visual Studio Code med Python-tillägget eller motsvarande IDE med Python 3.10 eller senare.
Vi rekommenderar en virtuell miljö för den här snabbstarten:
Starta Visual Studio Code.
Skapa en ny ipynb-fil.
Öppna kommandopaletten med hjälp av Ctrl+Skift+P.
Sök efter Python: Skapa miljö.
Välj Venv.
Välj en Python-tolk. Välj 3.10 eller senare.
Det kan ta en minut att konfigurera. Om du stöter på problem kan du läsa Python-miljöer i VS Code.
Installera paket och ange variabler
Installera paket, inklusive azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet
! pip install azure-identity --quiet
! pip install python-dotenv --quiet
Ange dina slutpunkts- och API-nycklar:
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"
Skapa ett index
Skapa eller uppdatera ett indexschema för att inkludera en SemanticConfiguration
. Om du uppdaterar ett befintligt index kräver den här ändringen ingen omindexering eftersom strukturen för dina dokument är oförändrad.
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])
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')
Skapa en nyttolast för dokument
Du kan skicka JSON-dokument till ett sökindex. Dokument måste matcha indexschemat.
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"
}
}
]
Ladda upp dokument till indexet
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)
Kör din första fråga
Börja med en tom fråga som ett verifieringssteg som bevisar att indexet fungerar. Du bör få en osorterad lista med hotellnamn och beskrivningar, med ett antal på 4 som anger att det finns fyra dokument i indexet.
# 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']}")
Köra en textfråga
I jämförelsesyfte kör du en textfråga med BM25-relevansbedömning. Fulltextsökning anropas när du anger en frågesträng. Svaret består av rankade resultat, där högre poäng tilldelas till dokument som har fler instanser av matchande termer eller viktigare termer.
I den här frågan för vilket hotell som har en bra restaurang på plats, kommer Sublime Palace Hotel ut på toppen eftersom beskrivningen innehåller webbplats. Termer som inträffar sällan höjer sökpoängen för dokumentet.
# 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']}")
Köra en semantisk fråga
Lägg nu till semantisk rangordning. Nya parametrar inkluderar query_type
och semantic_configuration_name
.
Det är samma fråga, men observera att den semantiska rankaren korrekt identifierar Gastronomic Landscape Hotel som ett mer relevant resultat med tanke på den första frågan. Den här frågan returnerar även undertexter som genererats av modellerna. Indata är för minimala i det här exemplet för att skapa intressanta undertexter, men exemplet lyckas visa syntaxen.
# 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")
Returnera semantiska svar
I den här sista frågan returnerar du semantiska svar.
Semantisk ranker kan generera svar på en frågesträng som har en frågas egenskaper. Det genererade svaret extraheras ordagrant från ditt innehåll. För att få ett semantiskt svar måste frågan och svaret vara nära anpassade, och modellen måste hitta innehåll som tydligt besvarar frågan. Om potentiella svar inte uppfyller ett förtroendetröskelvärde returnerar modellen inte något svar. I demonstrationssyfte är frågan i det här exemplet utformad för att få ett svar så att du kan se syntaxen.
# 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")