Bouw een consoletoepassing met behulp van de clientbibliotheek Azure.Search.Documents om semantische classificatie toe te voegen aan een bestaande zoekindex.
U kunt ook de broncode downloaden om te beginnen met een voltooid project.
Uw omgeving instellen
Start Visual Studio en maak een nieuw project voor een console-app.
Selecteer onder Hulpprogramma's>NuGet-pakketbeheer de optie NuGet-pakketten voor oplossing beheren....
Selecteer Bladeren.
Zoek het pakket Azure.Search.Documents en selecteer de meest recente stabiele versie.
Selecteer Installeren om de assembly toe te voegen aan uw project en oplossing.
Een zoekclient maken
Voeg in Program.cs de volgende using
instructies toe.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
Maak twee clients: SearchIndexClient maakt de index en SearchClient laadt en voert query's uit op een bestaande index.
Beide clients hebben het service-eindpunt en een beheerders-API-sleutel nodig voor verificatie met rechten voor maken/verwijderen. De code bouwt echter de URI voor u uit, dus geef alleen de naam van de zoekservice voor de serviceName
eigenschap op. Neem deze niet op https://
of .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);
. . .
}
Een index maken
Een indexschema maken of bijwerken om een SemanticConfiguration
. Als u een bestaande index bijwerkt, hoeft deze wijziging niet opnieuw te worden geïndexeerd omdat de structuur van uw documenten ongewijzigd is.
// 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);
}
Met de volgende code wordt de index voor uw zoekservice gemaakt:
// Create index
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, adminClient);
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
Documenten laden
Azure AI Search zoekt naar inhoud die is opgeslagen in de service. De code voor het uploaden van documenten is identiek aan de C#-snelstartgids voor zoeken in volledige tekst, zodat we deze hier niet hoeven te dupliceren. U moet vier hotels met namen, adressen en beschrijvingen hebben. Uw oplossing moet typen hebben voor hotels en adressen.
Een index doorzoeken
Hier volgt een query die semantische rangschikking aanroept, met zoekopties voor het opgeven van parameters:
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);
Ter vergelijking zijn hier resultaten van een query die gebruikmaakt van de standaard BM25-classificatie, op basis van de termfrequentie en nabijheid. Gezien de query 'welk hotel een goed restaurant op locatie heeft', retourneert het BM25-classificatie-algoritme overeenkomsten in de volgorde die wordt weergegeven in deze schermopname:
Wanneer daarentegen semantische classificatie wordt toegepast op dezelfde query ('welk hotel heeft een goed restaurant op site'),worden de resultaten opnieuw gerangschikt op basis van semantische relevantie voor de query. Dit keer is het belangrijkste resultaat het hotel met het restaurant, dat beter aansluit op de verwachtingen van de gebruiker.
Het programma uitvoeren
Druk op F5 om de app opnieuw te bouwen en het programma in zijn geheel uit te voeren.
De uitvoer bevat berichten van Console.WriteLine, met toevoeging van query-informatie en -resultaten.
Gebruik een Jupyter-notebook en de bibliotheek azure-search-documents in de Azure SDK voor Python voor meer informatie over semantische classificatie.
U kunt ook een voltooid notebook downloaden en uitvoeren.
Uw omgeving instellen
Gebruik Visual Studio Code met de Python-extensie of equivalente IDE, met Python 3.10 of hoger.
We raden een virtuele omgeving aan voor deze quickstart:
Visual Studio Code starten.
Maak een nieuw ipynb-bestand.
Open het opdrachtenpalet met Ctrl+Shift+P.
Zoek naar Python: Omgeving maken.
Selecteer Venv.
Selecteer een Python-interpreter. Kies 3.10 of hoger.
Het kan even duren voordat het is ingesteld. Als u problemen ondervindt, raadpleegt u Python-omgevingen in VS Code.
Pakketten installeren en variabelen instellen
Installeer pakketten, waaronder azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet
! pip install azure-identity --quiet
! pip install python-dotenv --quiet
Geef uw eindpunt- en API-sleutels op:
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"
Een index maken
Een indexschema maken of bijwerken om een SemanticConfiguration
. Als u een bestaande index bijwerkt, hoeft deze wijziging niet opnieuw te worden geïndexeerd omdat de structuur van uw documenten ongewijzigd is.
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')
Een nettolading van documenten maken
U kunt JSON-documenten naar een zoekindex pushen. Documenten moeten overeenkomen met het indexschema.
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"
}
}
]
Documenten uploaden naar de index
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)
Uw eerste query uitvoeren
Begin met een lege query als verificatiestap om aan te tonen dat de index operationeel is. U krijgt een niet-geordende lijst met hotelnamen en beschrijvingen, met een telling van 4 die aangeeft dat er vier documenten in de index zijn.
# 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']}")
Een tekstquery uitvoeren
Voer voor vergelijkingsdoeleinden een tekstquery uit met BM25-relevantiescore. Zoeken in volledige tekst wordt aangeroepen wanneer u een querytekenreeks opgeeft. Het antwoord bestaat uit gerangschikte resultaten, waarbij hogere scores worden toegekend aan documenten met meer exemplaren van overeenkomende termen of belangrijkere termen.
In deze query voor wat hotel een goed restaurant op locatie heeft, komt Sublie palace Hotel bovenaan omdat de beschrijving site bevat. Termen die niet vaak voorkomen, verhogen de zoekscore van het document.
# 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']}")
Een semantische query uitvoeren
Voeg nu semantische rangschikking toe. Nieuwe parameters bevatten query_type
en semantic_configuration_name
.
Het is dezelfde query, maar u ziet dat de semantische ranker gastronomische landschapshotel correct identificeert als een relevanter resultaat op basis van de eerste query. Deze query retourneert ook bijschriften die zijn gegenereerd door de modellen. De invoer is te minimaal in dit voorbeeld om interessante bijschriften te maken, maar het voorbeeld slaagt erin om de syntaxis te demonstreren.
# 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")
Semantische antwoorden retourneren
In deze laatste query retourneert u semantische antwoorden.
Semantische ranker kan antwoorden genereren op een querytekenreeks die de kenmerken van een vraag heeft. Het gegenereerde antwoord wordt letterlijk uit uw inhoud geëxtraheerd. Om een semantisch antwoord te krijgen, moet de vraag en het antwoord nauwkeurig worden afgestemd en moet het model inhoud vinden die duidelijk antwoord geeft op de vraag. Als potentiële antwoorden niet voldoen aan een drempelwaarde voor betrouwbaarheid, retourneert het model geen antwoord. Voor demonstratiedoeleinden is de vraag in dit voorbeeld ontworpen om een antwoord te krijgen, zodat u de syntaxis kunt zien.
# 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")