Kies een programmeertaal voor de volgende stap. De clientbibliotheken Azure.Search.Documents zijn beschikbaar in Azure SDK's voor .NET, Python, Java en JavaScript/Typescript.
Bouw een consoletoepassing met behulp van de clientbibliotheek Azure.Search.Documents om een zoekindex te maken, laden en er query's op uit te voeren.
U kunt ook de broncode downloaden om te beginnen met een voltooid project of deze stappen volgen om uw eigen project te maken.
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 naar het pakket Azure.Search.Documents en selecteer versie 11.0 of hoger.
Selecteer Installeren om de assembly toe te voegen aan uw project en oplossing.
Een zoekclient maken
Wijzig in Program.cs de naamruimte in AzureSearch.SDK.Quickstart.v11
en voeg vervolgens 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;
Kopieer de volgende code om twee clients te maken. SearchIndexClient maakt de index en SearchClient laadt een bestaande index en voert er een query op uit. Beide hebben het service-eindpunt en een beheerder-API-sleutel nodig voor verificatie van rechten voor maken/verwijderen.
Omdat de code de URI voor u uitbouwt, geeft u alleen de naam van de zoekservice op in de serviceName
eigenschap.
static void Main(string[] args)
{
string serviceName = "<your-search-service-name>";
string apiKey = "<your-search-service-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
In deze quickstart wordt een index van hotels gemaakt die u met hotelgegevens laadt en waarop u query's uitvoert. In deze stap definieert u de velden in de index. Elke definitie bevat een naam, gegevenstype en kenmerken die bepalen hoe het veld wordt gebruikt.
In dit voorbeeld worden synchrone methoden van de bibliotheek Azure.Search.Documents gebruikt voor eenvoud en leesbaarheid. Voor productiescenario's moet u echter asynchrone methoden gebruiken om uw app op een schaalbare en responsieve manier te laten werken. U kunt bijvoorbeeld CreateIndexAsync gebruiken in plaats van CreateIndex.
Voeg een lege klassedefinitie toe aan uw project: Hotel.cs
Kopieer de volgende code in Hotel.cs om de structuur van een hoteldocument te definiëren. Kenmerken in het veld bepalen hoe deze worden gebruikt in een toepassing. Het IsFilterable
-kenmerk moet bijvoorbeeld worden toegewezen aan elk veld dat een filterexpressie ondersteunt.
using System;
using System.Text.Json.Serialization;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
namespace AzureSearch.Quickstart
{
public partial class Hotel
{
[SimpleField(IsKey = true, IsFilterable = true)]
public string HotelId { get; set; }
[SearchableField(IsSortable = true)]
public string HotelName { get; set; }
[SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
public string Description { get; set; }
[SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)]
[JsonPropertyName("Description_fr")]
public string DescriptionFr { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string Category { get; set; }
[SearchableField(IsFilterable = true, IsFacetable = true)]
public string[] Tags { get; set; }
[SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public bool? ParkingIncluded { get; set; }
[SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public DateTimeOffset? LastRenovationDate { get; set; }
[SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public double? Rating { get; set; }
[SearchableField]
public Address Address { get; set; }
}
}
In de clientbibliotheek Azure.Search.Documents kunt u SearchableField en SimpleField gebruiken om velddefinities te stroomlijnen. Beide zijn afgeleiden van een SearchField en kunnen uw code vereenvoudigen:
SimpleField
kan elk gegevenstype zijn, is altijd niet-doorzoekbaar (wordt genegeerd voor zoekopdrachten in volledige tekst) en kan worden opgehaald (is niet verborgen). Andere kenmerken zijn standaard uitgeschakeld, maar kunnen wel worden ingeschakeld. U kunt een SimpleField
gebruiken voor document-id's of velden die alleen worden gebruikt in filters, facetten of scoreprofielen. Als dat het geval is, moet u ervoor zorgen dat u alle kenmerken toepast die nodig zijn voor het scenario, zoals IsKey = true
voor een document-id. Zie SimpleFieldAttribute.cs in broncode voor meer informatie.
SearchableField
moet een tekenreeks zijn die altijd kan worden doorzocht en opgehaald. Andere kenmerken zijn standaard uitgeschakeld, maar kunnen wel worden ingeschakeld. Omdat dit veldtype kan worden doorzocht, worden synoniemen en het volledige gamma van analyse-eigenschappen ondersteund. Zie SearchableFieldAttribute.cs in broncode voor meer informatie.
Ongeacht of u de basis-API van SearchField
of een van de hulpmodellen gebruikt, u moet filter-, facet- en sorteerkenmerken expliciet inschakelen. IsFilterable, IsSortable en IsFacetable moeten bijvoorbeeld expliciet worden toegeschreven, zoals wordt weergegeven in het vorige voorbeeld.
Voeg een tweede lege klassedefinitie toe aan uw project: Address.cs. Kopieer de volgende code naar de klasse.
using Azure.Search.Documents.Indexes;
namespace AzureSearch.Quickstart
{
public partial class Address
{
[SearchableField(IsFilterable = true)]
public string StreetAddress { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string City { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string StateProvince { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string PostalCode { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string Country { get; set; }
}
}
Maak nog twee klassen: Hotel.Methods.cs en Address.Methods.cs voor ToString()
onderdrukkingen. Deze klassen worden gebruikt voor het weergeven van zoekresultaten in de console-uitvoer. De inhoud van deze klassen wordt niet opgegeven in dit artikel, maar u kunt de code kopiëren uit bestanden in GitHub.
Maak in Program.cs een SearchIndex-object en roep vervolgens de methode CreateIndex aan om de index uit te drukken in uw zoekservice. De index bevat ook een SearchSuggester om automatisch aanvullen in te schakelen voor de opgegeven velden.
// 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);
adminClient.CreateOrUpdateIndex(definition);
}
Documenten laden
Azure AI Search zoekt naar inhoud die is opgeslagen in de service. In deze stap laadt u JSON-documenten die overeenkomen met de hotelindex die u zojuist hebt gemaakt.
In Azure AI Search zijn zoekdocumenten gegevensstructuren die zowel invoer zijn voor het indexeren als uitvoeren van query's. Als u de documenten hebt verkregen via een externe gegevensbron, bestaat de documentinvoer mogelijk uit rijen in een database, blobs in Blob Storage of JSON-documenten op een schijf. In dit voorbeeld nemen we de korte route en gaan we JSON-documenten voor vier hotels in de code zelf insluiten.
Bij het uploaden van documenten moet u een IndexDocumentsBatch-object gebruiken. Een IndexDocumentsBatch
object bevat een verzameling acties, die elk een document en een eigenschap bevatten die Azure AI Search vertelt welke actie moet worden uitgevoerd (uploaden, samenvoegen, verwijderen en samenvoegen).
In Program.cs maakt u een matrix met documenten en indexacties en vervolgens geeft u de matrix door aan IndexDocumentsBatch
. De volgende documenten voldoen aan de index hotels-quickstart, zoals gedefinieerd door de hotelklasse.
// Upload documents in a single Upload request.
private static void UploadDocuments(SearchClient searchClient)
{
IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
IndexDocumentsAction.Upload(
new Hotel()
{
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.",
DescriptionFr = "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 = new[] { "pool", "air conditioning", "concierge" },
ParkingIncluded = false,
LastRenovationDate = new DateTimeOffset(1970, 1, 18, 0, 0, 0, TimeSpan.Zero),
Rating = 3.6,
Address = new Address()
{
StreetAddress = "677 5th Ave",
City = "New York",
StateProvince = "NY",
PostalCode = "10022",
Country = "USA"
}
}),
IndexDocumentsAction.Upload(
new Hotel()
{
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.",
DescriptionFr = "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 = new[] { "pool", "free wifi", "concierge" },
ParkingIncluded = false,
LastRenovationDate = new DateTimeOffset(1979, 2, 18, 0, 0, 0, TimeSpan.Zero),
Rating = 3.60,
Address = new Address()
{
StreetAddress = "140 University Town Center Dr",
City = "Sarasota",
StateProvince = "FL",
PostalCode = "34243",
Country = "USA"
}
}),
IndexDocumentsAction.Upload(
new Hotel()
{
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.",
DescriptionFr = "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 = new[] { "air conditioning", "bar", "continental breakfast" },
ParkingIncluded = true,
LastRenovationDate = new DateTimeOffset(2015, 9, 20, 0, 0, 0, TimeSpan.Zero),
Rating = 4.80,
Address = new Address()
{
StreetAddress = "3393 Peachtree Rd",
City = "Atlanta",
StateProvince = "GA",
PostalCode = "30326",
Country = "USA"
}
}),
IndexDocumentsAction.Upload(
new Hotel()
{
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.",
DescriptionFr = "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 = new[] { "concierge", "view", "24-hour front desk service" },
ParkingIncluded = true,
LastRenovationDate = new DateTimeOffset(1960, 2, 06, 0, 0, 0, TimeSpan.Zero),
Rating = 4.60,
Address = new Address()
{
StreetAddress = "7400 San Pedro Ave",
City = "San Antonio",
StateProvince = "TX",
PostalCode = "78216",
Country = "USA"
}
})
);
try
{
IndexDocumentsResult result = searchClient.IndexDocuments(batch);
}
catch (Exception)
{
// If for some reason any documents are dropped during indexing, you can compensate by delaying and
// retrying. This simple demo just logs the failed document keys and continues.
Console.WriteLine("Failed to index some of the documents: {0}");
}
}
Nadat u het IndexDocumentsBatch-object hebt geïnitialiseerd, kunt u het naar de index sturen door IndexDocuments aan te roepen op uw SearchClient-object.
Voeg de volgende regels toe aan Main()
. Documenten worden geladen met SearchClient, maar voor de bewerking zijn ook beheerdersrechten op de service vereist, die meestal is gekoppeld aan SearchIndexClient. Een manier om deze bewerking in te stellen, is door SearchClient door SearchIndexClient
te halen (adminClient
in dit voorbeeld).
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
// Load documents
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(ingesterClient);
Omdat dit een console-app is waarmee alle opdrachten opeenvolgend worden uitgevoerd, moet u een wachttijd van 2 seconden tussen indexeren en query's toevoegen.
// Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
Console.WriteLine("Waiting for indexing...\n");
System.Threading.Thread.Sleep(2000);
De vertraging van 2 seconden compenseert de indexering (die asynchroon is), zodat alle documenten kunnen worden geïndexeerd voordat de query's worden uitgevoerd. Codering in een vertraging is doorgaans alleen nodig in demo's, testen en voorbeeldtoepassingen.
Een index doorzoeken
U kunt queryresultaten ophalen zodra het eerste document wordt geïndexeerd, maar wacht met het daadwerkelijk testen van uw index totdat alle documenten zijn geïndexeerd.
In deze sectie worden twee functies toegevoegd: querylogica en resultaten. Gebruik voor query's de methode Search. Deze methode gebruikt zoektekst (de querytekenreeks) en andere opties.
De SearchResults-klasse vertegenwoordigt de resultaten.
Maak in Program.cs een WriteDocuments
methode waarmee zoekresultaten naar de console worden afgedrukt.
// Write search results to console
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
foreach (SearchResult<Hotel> result in searchResults.GetResults())
{
Console.WriteLine(result.Document);
}
Console.WriteLine();
}
private static void WriteDocuments(AutocompleteResults autoResults)
{
foreach (AutocompleteItem result in autoResults.Results)
{
Console.WriteLine(result.Text);
}
Console.WriteLine();
}
Maak een RunQueries
methode om query's uit te voeren en resultaten te retourneren. Resultaten zijn Hotel-objecten. In dit voorbeeld ziet u de handtekening en de eerste query van de methode. Deze query demonstreert de Select-parameter waarmee u het resultaat kunt samenstellen met behulp van geselecteerde velden uit het document.
// Run queries, use WriteDocuments to print output
private static void RunQueries(SearchClient srchclient)
{
SearchOptions options;
SearchResults<Hotel> response;
// Query 1
Console.WriteLine("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");
options = new SearchOptions()
{
IncludeTotalCount = true,
Filter = "",
OrderBy = { "" }
};
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Address/City");
response = srchclient.Search<Hotel>("*", options);
WriteDocuments(response);
In de tweede query zoekt u op een term, voegt u een filter toe waarmee documenten worden geselecteerd waarin Waardering groter is dan 4 en vervolgens in aflopende volgorde op Classificatie sorteren. Een filter is een Booleaanse uitdrukking die wordt geëvalueerd over IsFilterable-velden in een index. Filterquery's bevatten waarden of sluiten ze uit. Er is dus geen relevantiescore gekoppeld aan een filterquery.
// Query 2
Console.WriteLine("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");
options = new SearchOptions()
{
Filter = "Rating gt 4",
OrderBy = { "Rating desc" }
};
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Rating");
response = srchclient.Search<Hotel>("hotels", options);
WriteDocuments(response);
De derde query laat zien searchFields
, dat wordt gebruikt om een zoekbewerking voor volledige tekst te bepalen voor specifieke velden.
// Query 3
Console.WriteLine("Query #3: Limit search to specific fields (pool in Tags field)...\n");
options = new SearchOptions()
{
SearchFields = { "Tags" }
};
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Tags");
response = srchclient.Search<Hotel>("pool", options);
WriteDocuments(response);
De vierde query laat zien facets
, die kan worden gebruikt om een facetnavigatiestructuur te structuren.
// Query 4
Console.WriteLine("Query #4: Facet on 'Category'...\n");
options = new SearchOptions()
{
Filter = ""
};
options.Facets.Add("Category");
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Category");
response = srchclient.Search<Hotel>("*", options);
WriteDocuments(response);
In de vijfde query retourneert u een specifiek document. Een documentzoekactie is een typisch antwoord op OnClick
gebeurtenissen in een resultatenset.
// Query 5
Console.WriteLine("Query #5: Look up a specific document...\n");
Response<Hotel> lookupResponse;
lookupResponse = srchclient.GetDocument<Hotel>("3");
Console.WriteLine(lookupResponse.Value.HotelId);
De laatste query toont de syntaxis voor automatisch aanvullen en simuleert een gedeeltelijke gebruikersinvoer van sa die wordt omgezet in twee mogelijke overeenkomsten in de bronvelden die zijn gekoppeld aan de suggestie die u in de index hebt gedefinieerd.
// Query 6
Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
var autoresponse = srchclient.Autocomplete("sa", "sg");
WriteDocuments(autoresponse);
Toevoegen RunQueries
aan Main()
.
// Call the RunQueries method to invoke a series of queries
Console.WriteLine("Starting queries...\n");
RunQueries(srchclient);
// End the program
Console.WriteLine("{0}", "Complete. Press any key to end this program...\n");
Console.ReadKey();
De vorige query's tonen meerdere manieren om termen in een query te koppelen: zoekopdracht in volledige tekst, filters en automatisch aanvullen.
Zoekopdrachten in volledige tekst en filters worden uitgevoerd met behulp van de methode SearchClient.Search. Een zoekquery kan worden doorgegeven in de searchText
-tekenreeks, terwijl een filterexpressie kan worden doorgegeven in de eigenschap Filter van de klasse Search Options. Als u wilt filteren zonder te zoeken, geeft u "*"
door voor de searchText
-parameter van de Zoekmethode. Als u wilt zoeken zonder te filteren, laat u de Filter
eigenschap uitgeschakeld of geeft u een SearchOptions
instantie helemaal niet door.
Het programma uitvoeren
Druk op F5 om de app opnieuw te bouwen en het programma volledig 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 om een zoekindex te maken, laden en er query's op uit te voeren.
U kunt ook een voltooid notebook downloaden en uitvoeren.
Uw omgeving instellen
Gebruik Visual Studio Code met de Python-extensie of een equivalente IDE, met Python 3.10 of hoger.
We raden een virtuele omgeving aan voor deze quickstart:
Visual Studio Code starten.
Open het opdrachtenpalet (Ctrl+Shift+P).
Zoek naar Python: Omgeving maken.
Selecteer Venv.
Selecteer een Python-interpreter. Kies versie 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 het eindpunt en de API-sleutel voor uw service 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
from azure.core.credentials import AzureKeyCredential
credential = AzureKeyCredential(search_api_key)
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
)
# 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),
])
]
scoring_profiles = []
suggester = [{'name': 'sg', 'source_fields': ['Tags', 'Address/City', 'Address/Country']}]
# Create the search index
index = SearchIndex(name=index_name, fields=fields, suggesters=suggester, scoring_profiles=scoring_profiles)
result = index_client.create_or_update_index(index)
print(f' {result.name} created')
Een nettolading van documenten maken
Gebruik een indexactie voor het bewerkingstype, zoals uploaden of samenvoegen en uploaden. Documenten zijn afkomstig van het Voorbeeld HotelsData op GitHub.
# Create a documents payload
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
# Upload documents to the 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
Gebruik de zoekmethode van de klasse search.client.
In dit voorbeeld wordt een lege zoekopdracht uitgevoerd (), die een ongerankeerde lijst retourneertsearch=*
(zoekscore = 1,0) van willekeurige documenten. Omdat er geen criteria zijn, worden alle documenten opgenomen in de resultaten.
# 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 termquery uitvoeren
Met de volgende query worden volledige termen toegevoegd aan de zoekexpressie ("wifi"). Met deze query wordt opgegeven dat de resultaten alleen die velden bevatten in de select
-instructie. Het beperken van de velden die worden geretourneerd, minimaliseert de hoeveelheid gegevens die via de kabel wordt verzonden en vermindert de zoeklatentie.
results = search_client.search(query_type='simple',
search_text="wifi" ,
select='HotelName,Description,Tags',
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 filter toevoegen
Voeg een filterexpressie toe en retourneert alleen die hotels met een classificatie die groter is dan vier, gesorteerd in aflopende volgorde.
# Add a filter
results = search_client.search(
search_text="hotels",
select='HotelId,HotelName,Rating',
filter='Rating gt 4',
order_by='Rating desc')
for result in results:
print("{}: {} - {} rating".format(result["HotelId"], result["HotelName"], result["Rating"]))
Bereik van veld toevoegen
Toevoegen search_fields
aan het uitvoeren van een bereikquery voor specifieke velden.
# Add search_fields to scope query matching to the HotelName field
results = search_client.search(
search_text="sublime",
search_fields=['HotelName'],
select='HotelId,HotelName')
for result in results:
print("{}: {}".format(result["HotelId"], result["HotelName"]))
Facetten toevoegen
Facetten worden gegenereerd voor positieve overeenkomsten die in zoekresultaten worden gevonden. Er zijn geen nulovereenkomsten. Als zoekresultaten de term wifi niet bevatten, wordt wifi niet weergegeven in de facetnavigatiestructuur.
# Return facets
results = search_client.search(search_text="*", facets=["Category"])
facets = results.get_facets()
for facet in facets["Category"]:
print(" {}".format(facet))
Een document opzoeken
Een document retourneren op basis van de sleutel. Deze bewerking is handig als u drill through wilt opgeven wanneer een gebruiker een item in een zoekresultaat selecteert.
# Look up a specific document by ID
result = search_client.get_document(key="3")
print("Details for hotel '3' are:")
print("Name: {}".format(result["HotelName"]))
print("Rating: {}".format(result["Rating"]))
print("Category: {}".format(result["Category"]))
Automatisch aanvullen toevoegen
Automatisch aanvullen kan potentiële overeenkomsten bieden wanneer de gebruiker in het zoekvak typt.
Automatisch aanvullen maakt gebruik van een suggestie (sg
) om te weten welke velden mogelijke overeenkomsten bevatten voor suggestieaanvragen. In deze quickstart zijn Tags
deze velden , . Address/City
Address/Country
Als u automatisch aanvullen wilt simuleren, geeft u de letters sa door als een gedeeltelijke tekenreeks. Met de methode voor automatisch aanvullen van SearchClient worden mogelijke overeenkomende termen geretourneerd.
# Autocomplete a query
search_suggestion = 'sa'
results = search_client.autocomplete(
search_text=search_suggestion,
suggester_name="sg",
mode='twoTerms')
print("Autocomplete for:", search_suggestion)
for result in results:
print (result['text'])
Bouw een Java-consoletoepassing met behulp van de bibliotheek Azure.Search.Documents om een zoekindex te maken, laden en er query's op uit te voeren.
U kunt ook de broncode downloaden om te beginnen met een voltooid project of deze stappen volgen om uw eigen project te maken.
Uw omgeving instellen
Gebruik de volgende hulpprogramma's om deze quickstart te maken.
Het project maken
Visual Studio Code starten.
Open het opdrachtenpalet met Ctrl+Shift+P. Zoek naar Java-project maken.
Selecteer Maven.
Selecteer maven-archetype-quickstart.
Selecteer de nieuwste versie, momenteel 1.4.
Voer azure.search.sample in als de groeps-id.
Voer azuresearchquickstart in als de artefact-id.
Selecteer de map waarin u het project wilt maken.
Voltooi het maken van het project in de geïntegreerde terminal. Druk op Enter om de standaardwaarde voor '1.0-SNAPSHOT' te accepteren en typ vervolgens 'y' om de eigenschappen voor uw project te bevestigen.
Open de map waarin u het project hebt gemaakt.
Maven-afhankelijkheden opgeven
Open het pom.xml-bestand en voeg de volgende afhankelijkheden toe.
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-search-documents</artifactId>
<version>11.7.3</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core</artifactId>
<version>1.53.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
Wijzig de Java-versie van de compiler in 11.
<maven.compiler.source>1.11</maven.compiler.source>
<maven.compiler.target>1.11</maven.compiler.target>
Een zoekclient maken
Open de App
klasse onder src, main, java, azure, search, sample. Voeg de volgende importrichtlijnen toe.
import java.util.Arrays;
import java.util.ArrayList;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.util.Context;
import com.azure.search.documents.SearchClient;
import com.azure.search.documents.SearchClientBuilder;
import com.azure.search.documents.models.SearchOptions;
import com.azure.search.documents.indexes.SearchIndexClient;
import com.azure.search.documents.indexes.SearchIndexClientBuilder;
import com.azure.search.documents.indexes.models.IndexDocumentsBatch;
import com.azure.search.documents.indexes.models.SearchIndex;
import com.azure.search.documents.indexes.models.SearchSuggester;
import com.azure.search.documents.util.AutocompletePagedIterable;
import com.azure.search.documents.util.SearchPagedIterable;
Het volgende voorbeeld bevat tijdelijke aanduidingen voor een naam van een zoekservice, een beheer-API-sleutel die machtigingen voor maken en verwijderen en indexnaam verleent. Vervang geldige waarden voor alle drie de tijdelijke aanduidingen. Maak twee clients: SearchIndexClient maakt de index en SearchClient laadt en voert query's uit op een bestaande index. Beide hebben het service-eindpunt en een beheerders-API-sleutel nodig voor verificatie met rechten voor maken en verwijderen.
public static void main(String[] args) {
var searchServiceEndpoint = "<YOUR-SEARCH-SERVICE-URL>";
var adminKey = new AzureKeyCredential("<YOUR-SEARCH-SERVICE-ADMIN-KEY>");
String indexName = "<YOUR-SEARCH-INDEX-NAME>";
SearchIndexClient searchIndexClient = new SearchIndexClientBuilder()
.endpoint(searchServiceEndpoint)
.credential(adminKey)
.buildClient();
SearchClient searchClient = new SearchClientBuilder()
.endpoint(searchServiceEndpoint)
.credential(adminKey)
.indexName(indexName)
.buildClient();
}
Een index maken
In deze quickstart wordt een index van hotels gemaakt die u met hotelgegevens laadt en waarop u query's uitvoert. In deze stap definieert u de velden in de index. Elke definitie bevat een naam, gegevenstype en kenmerken die bepalen hoe het veld wordt gebruikt.
In dit voorbeeld worden synchrone methoden van de bibliotheek azure-search-documents gebruikt voor eenvoud en leesbaarheid. Voor productiescenario's moet u echter asynchrone methoden gebruiken om uw app op een schaalbare en responsieve manier te laten werken. U gebruikt bijvoorbeeld SearchAsyncClient in plaats van SearchClient.
Voeg een lege klassedefinitie toe aan uw project: Hotel.java
Kopieer de volgende code naar Hotel.java
het definiëren van de structuur van een hoteldocument. Kenmerken in het veld bepalen hoe deze worden gebruikt in een toepassing. De aantekening IsFilterable moet bijvoorbeeld worden toegewezen aan elk veld dat een filterexpressie ondersteunt
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package azure.search.sample;
import com.azure.search.documents.indexes.SearchableField;
import com.azure.search.documents.indexes.SimpleField;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import java.time.OffsetDateTime;
/**
* Model class representing a hotel.
*/
@JsonInclude(Include.NON_NULL)
public class Hotel {
/**
* Hotel ID
*/
@JsonProperty("HotelId")
@SimpleField(isKey = true)
public String hotelId;
/**
* Hotel name
*/
@JsonProperty("HotelName")
@SearchableField(isSortable = true)
public String hotelName;
/**
* Description
*/
@JsonProperty("Description")
@SearchableField(analyzerName = "en.microsoft")
public String description;
/**
* French description
*/
@JsonProperty("DescriptionFr")
@SearchableField(analyzerName = "fr.lucene")
public String descriptionFr;
/**
* Category
*/
@JsonProperty("Category")
@SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
public String category;
/**
* Tags
*/
@JsonProperty("Tags")
@SearchableField(isFilterable = true, isFacetable = true)
public String[] tags;
/**
* Whether parking is included
*/
@JsonProperty("ParkingIncluded")
@SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
public Boolean parkingIncluded;
/**
* Last renovation time
*/
@JsonProperty("LastRenovationDate")
@SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
public OffsetDateTime lastRenovationDate;
/**
* Rating
*/
@JsonProperty("Rating")
@SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
public Double rating;
/**
* Address
*/
@JsonProperty("Address")
public Address address;
@Override
public String toString()
{
try
{
return new ObjectMapper().writeValueAsString(this);
}
catch (JsonProcessingException e)
{
e.printStackTrace();
return "";
}
}
}
In de clientbibliotheek van Azure.Search.Documents kunt u velddefinities stroomlijnen met behulp van de velden SearchableField en SimpleField.
SimpleField
kan elk gegevenstype zijn, is altijd niet-doorzoekbaar (wordt genegeerd voor zoekopdrachten in volledige tekst) en kan worden opgehaald (is niet verborgen). Andere kenmerken zijn standaard uitgeschakeld, maar kunnen wel worden ingeschakeld. U kunt een SimpleField gebruiken voor document-id's of velden die alleen worden gebruikt in filters, facetten of scoreprofielen. Als dit het geval is, moet u alle kenmerken toepassen die nodig zijn voor het scenario, zoals IsKey = true voor een document-id.
SearchableField
moet een tekenreeks zijn die altijd kan worden doorzocht en opgehaald. Andere kenmerken zijn standaard uitgeschakeld, maar kunnen wel worden ingeschakeld. Omdat dit veldtype kan worden doorzocht, worden synoniemen en het volledige gamma van analyse-eigenschappen ondersteund.
Ongeacht of u de basis-API van SearchField
of een van de hulpmodellen gebruikt, u moet filter-, facet- en sorteerkenmerken expliciet inschakelen. Bijvoorbeeld, isFilterable
isSortable
en isFacetable
moet expliciet worden toegeschreven, zoals wordt weergegeven in de vorige steekproef.
Voeg een tweede lege klassedefinitie toe aan uw project: Address.java
. Kopieer de volgende code naar de klasse.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package azure.search.sample;
import com.azure.search.documents.indexes.SearchableField;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
* Model class representing an address.
*/
@JsonInclude(Include.NON_NULL)
public class Address {
/**
* Street address
*/
@JsonProperty("StreetAddress")
@SearchableField
public String streetAddress;
/**
* City
*/
@JsonProperty("City")
@SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
public String city;
/**
* State or province
*/
@JsonProperty("StateProvince")
@SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
public String stateProvince;
/**
* Postal code
*/
@JsonProperty("PostalCode")
@SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
public String postalCode;
/**
* Country
*/
@JsonProperty("Country")
@SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
public String country;
}
Maak App.java
in de main
methode een SearchIndex
object en roep vervolgens de createOrUpdateIndex
methode aan om de index in uw zoekservice te maken. De index bevat ook een SearchSuggester
functie om automatisch aanvullen in te schakelen voor de opgegeven velden.
// Create Search Index for Hotel model
searchIndexClient.createOrUpdateIndex(
new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
.setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));
Documenten laden
Azure AI Search zoekt naar inhoud die is opgeslagen in de service. In deze stap laadt u JSON-documenten die overeenkomen met de hotelindex die u zojuist hebt gemaakt.
In Azure AI Search zijn zoekdocumenten gegevensstructuren die zowel invoer zijn voor het indexeren als uitvoeren van query's. Als u de documenten hebt verkregen via een externe gegevensbron, bestaat de documentinvoer mogelijk uit rijen in een database, blobs in Blob Storage of JSON-documenten op een schijf. In dit voorbeeld nemen we de korte route en gaan we JSON-documenten voor vier hotels in de code zelf insluiten.
Bij het uploaden van documenten moet u een IndexDocumentsBatch-object gebruiken. Een IndexDocumentsBatch
object bevat een verzameling IndexActions, die elk een document en een eigenschap bevatten die Azure AI Search vertelt welke actie moet worden uitgevoerd (uploaden, samenvoegen, verwijderen en samenvoegen).
Maak App.java
documenten en indexacties in, en geef ze vervolgens door aan IndexDocumentsBatch
. De volgende documenten voldoen aan de index hotels-quickstart, zoals gedefinieerd door de hotelklasse.
// Upload documents in a single Upload request.
private static void uploadDocuments(SearchClient searchClient)
{
var hotelList = new ArrayList<Hotel>();
var hotel = new Hotel();
hotel.hotelId = "1";
hotel.hotelName = "Stay-Kay City Hotel";
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.";
hotel.descriptionFr = "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.";
hotel.category = "Boutique";
hotel.tags = new String[] { "pool", "air conditioning", "concierge" };
hotel.parkingIncluded = false;
hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1970, 1, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
hotel.rating = 3.6;
hotel.address = new Address();
hotel.address.streetAddress = "677 5th Ave";
hotel.address.city = "New York";
hotel.address.stateProvince = "NY";
hotel.address.postalCode = "10022";
hotel.address.country = "USA";
hotelList.add(hotel);
hotel = new Hotel();
hotel.hotelId = "2";
hotel.hotelName = "Old Century Hotel";
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.";
hotel.descriptionFr = "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.";
hotel.category = "Boutique";
hotel.tags = new String[] { "pool", "free wifi", "concierge" };
hotel.parkingIncluded = false;
hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1979, 2, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
hotel.rating = 3.60;
hotel.address = new Address();
hotel.address.streetAddress = "140 University Town Center Dr";
hotel.address.city = "Sarasota";
hotel.address.stateProvince = "FL";
hotel.address.postalCode = "34243";
hotel.address.country = "USA";
hotelList.add(hotel);
hotel = new Hotel();
hotel.hotelId = "3";
hotel.hotelName = "Gastronomic Landscape Hotel";
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.";
hotel.descriptionFr = "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.";
hotel.category = "Resort and Spa";
hotel.tags = new String[] { "air conditioning", "bar", "continental breakfast" };
hotel.parkingIncluded = true;
hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2015, 9, 20), LocalTime.of(0, 0)), ZoneOffset.UTC);
hotel.rating = 4.80;
hotel.address = new Address();
hotel.address.streetAddress = "3393 Peachtree Rd";
hotel.address.city = "Atlanta";
hotel.address.stateProvince = "GA";
hotel.address.postalCode = "30326";
hotel.address.country = "USA";
hotelList.add(hotel);
hotel = new Hotel();
hotel.hotelId = "4";
hotel.hotelName = "Sublime Palace Hotel";
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.";
hotel.descriptionFr = "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.";
hotel.category = "Boutique";
hotel.tags = new String[] { "concierge", "view", "24-hour front desk service" };
hotel.parkingIncluded = true;
hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1960, 2, 06), LocalTime.of(0, 0)), ZoneOffset.UTC);
hotel.rating = 4.60;
hotel.address = new Address();
hotel.address.streetAddress = "7400 San Pedro Ave";
hotel.address.city = "San Antonio";
hotel.address.stateProvince = "TX";
hotel.address.postalCode = "78216";
hotel.address.country = "USA";
hotelList.add(hotel);
var batch = new IndexDocumentsBatch<Hotel>();
batch.addMergeOrUploadActions(hotelList);
try
{
searchClient.indexDocuments(batch);
}
catch (Exception e)
{
e.printStackTrace();
// If for some reason any documents are dropped during indexing, you can compensate by delaying and
// retrying. This simple demo just logs failure and continues
System.err.println("Failed to index some of the documents");
}
}
Nadat u het IndexDocumentsBatch
object hebt geïnitialiseerd, kunt u het naar de index verzenden door indexDocuments op uw SearchClient
object aan te roepen.
Voeg de volgende regels toe aan Main()
. Het laden van documenten wordt uitgevoerd met behulp van SearchClient
.
// Upload sample hotel documents to the Search Index
uploadDocuments(searchClient);
Omdat dit een console-app is waarmee alle opdrachten opeenvolgend worden uitgevoerd, moet u een wachttijd van 2 seconden tussen indexeren en query's toevoegen.
// Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
System.out.println("Waiting for indexing...\n");
try
{
Thread.sleep(2000);
}
catch (InterruptedException e)
{
}
De vertraging van 2 seconden compenseert de indexering (die asynchroon is), zodat alle documenten kunnen worden geïndexeerd voordat de query's worden uitgevoerd. Codering in een vertraging is doorgaans alleen nodig in demo's, testen en voorbeeldtoepassingen.
Een index doorzoeken
U kunt queryresultaten ophalen zodra het eerste document wordt geïndexeerd, maar wacht met het daadwerkelijk testen van uw index totdat alle documenten zijn geïndexeerd.
In deze sectie worden twee functies toegevoegd: querylogica en resultaten. Gebruik voor query's de methode Search. Deze methode gebruikt zoektekst (de querytekenreeks) en andere opties.
Maak App.java
in de console een WriteDocuments
methode waarmee zoekresultaten naar de console worden afgedrukt.
// Write search results to console
private static void WriteSearchResults(SearchPagedIterable searchResults)
{
searchResults.iterator().forEachRemaining(result ->
{
Hotel hotel = result.getDocument(Hotel.class);
System.out.println(hotel);
});
System.out.println();
}
// Write autocomplete results to console
private static void WriteAutocompleteResults(AutocompletePagedIterable autocompleteResults)
{
autocompleteResults.iterator().forEachRemaining(result ->
{
String text = result.getText();
System.out.println(text);
});
System.out.println();
}
Maak een RunQueries
methode om query's uit te voeren en resultaten te retourneren. Resultaten zijn Hotel
objecten. In dit voorbeeld ziet u de handtekening en de eerste query van de methode. Deze query demonstreert de Select
parameter waarmee u het resultaat kunt opstellen met behulp van geselecteerde velden uit het document.
// Run queries, use WriteDocuments to print output
private static void RunQueries(SearchClient searchClient)
{
// Query 1
System.out.println("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");
SearchOptions options = new SearchOptions();
options.setIncludeTotalCount(true);
options.setFilter("");
options.setOrderBy("");
options.setSelect("HotelId", "HotelName", "Address/City");
WriteSearchResults(searchClient.search("*", options, Context.NONE));
}
In de tweede query zoekt u op een term, voegt u een filter toe waarmee documenten worden geselecteerd waarin Waardering groter is dan 4 en vervolgens in aflopende volgorde op Classificatie sorteren. Filter is een Booleaanse expressie die wordt geëvalueerd op isFilterable
velden in een index. Filterquery's bevatten waarden of sluiten ze uit. Er is dus geen relevantiescore gekoppeld aan een filterquery.
// Query 2
System.out.println("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");
options = new SearchOptions();
options.setFilter("Rating gt 4");
options.setOrderBy("Rating desc");
options.setSelect("HotelId", "HotelName", "Rating");
WriteSearchResults(searchClient.search("hotels", options, Context.NONE));
De derde query laat zien searchFields
, dat wordt gebruikt om een zoekbewerking voor volledige tekst te bepalen voor specifieke velden.
// Query 3
System.out.println("Query #3: Limit search to specific fields (pool in Tags field)...\n");
options = new SearchOptions();
options.setSearchFields("Tags");
options.setSelect("HotelId", "HotelName", "Tags");
WriteSearchResults(searchClient.search("pool", options, Context.NONE));
De vierde query laat zien facets
, die kan worden gebruikt om een facetnavigatiestructuur te structuren.
// Query 4
System.out.println("Query #4: Facet on 'Category'...\n");
options = new SearchOptions();
options.setFilter("");
options.setFacets("Category");
options.setSelect("HotelId", "HotelName", "Category");
WriteSearchResults(searchClient.search("*", options, Context.NONE));
In de vijfde query retourneert u een specifiek document.
// Query 5
System.out.println("Query #5: Look up a specific document...\n");
Hotel lookupResponse = searchClient.getDocument("3", Hotel.class);
System.out.println(lookupResponse.hotelId);
System.out.println();
De laatste query toont de syntaxis voor automatisch aanvullen, waarbij een gedeeltelijke gebruikersinvoer van s wordt gesimsimeerd die wordt omgezet in twee mogelijke overeenkomsten in de sourceFields
gekoppelde aan de suggestie die u in de index hebt gedefinieerd.
// Query 6
System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");
WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));
Toevoegen RunQueries
aan Main()
.
// Call the RunQueries method to invoke a series of queries
System.out.println("Starting queries...\n");
RunQueries(searchClient);
// End the program
System.out.println("Complete.\n");
De vorige query's tonen meerdere manieren om termen in een query te koppelen: zoekopdracht in volledige tekst, filters en automatisch aanvullen.
Zoekopdrachten en filters voor volledige tekst worden uitgevoerd met behulp van de zoekmethode SearchClient.search . Een zoekquery kan worden doorgegeven in de searchText
tekenreeks, terwijl een filterexpressie kan worden doorgegeven in de filter
eigenschap van de klasse SearchOptions . Als u wilt filteren zonder te zoeken, geeft u '*' door voor de searchText
parameter van de search
methode. Als u wilt zoeken zonder te filteren, laat u de filter
eigenschap uitgeschakeld of geeft u een SearchOptions
instantie helemaal niet door.
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 System.out.println
, met de toevoeging van querygegevens en resultaten.
Bouw een Node.js-toepassing met behulp van de bibliotheek @azure/search-documents om een zoekindex te maken, laden en er query's op uit te voeren.
U kunt ook de broncode downloaden om te beginnen met een voltooid project of deze stappen volgen om uw eigen project te maken.
Uw omgeving instellen
We hebben de volgende hulpprogramma's gebruikt om deze quickstart te maken.
Het project maken
Visual Studio Code starten.
Open het opdrachtenpalet met Ctrl+Shift+P en open de geïntegreerde terminal.
Maak een ontwikkelingsmap en geef deze de quickstart voor de naam:
mkdir quickstart
cd quickstart
Initialiseer een leeg project met npm door de volgende opdracht uit te voeren. Als u het project volledig wilt initialiseren, drukt u meerdere keren op Enter om de standaardwaarden te accepteren, met uitzondering van de licentie, die u moet instellen op MIT.
npm init
Installeer @azure/search-documents
, de JavaScript/TypeScript SDK voor Azure AI Search.
npm install @azure/search-documents
Installeren dotenv
, die wordt gebruikt voor het importeren van de omgevingsvariabelen, zoals de naam van uw zoekservice en API-sleutel.
npm install dotenv
Ga naar de snelstartmap en controleer of u het project en de bijbehorende afhankelijkheden hebt geconfigureerd door te controleren of uw package.json-bestand er ongeveer als volgt uitziet:
{
"name": "quickstart",
"version": "1.0.0",
"description": "Azure AI Search Quickstart",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"Azure",
"Search"
],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"@azure/search-documents": "^11.3.0",
"dotenv": "^16.0.2"
}
}
Maak het bestand .env om de parameters van de zoekservice op te slaan:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
Vervang de YOUR-SEARCH-SERVICE-URL
waarde door de naam van de URL van uw zoekservice-eindpunt. Vervang door <YOUR-SEARCH-ADMIN-API-KEY>
de beheersleutel die u eerder hebt vastgelegd.
Maak het bestand index.js
Vervolgens maken we een index.js-bestand , het hoofdbestand dat als host fungeert voor onze code.
Importeer boven aan dit bestand de @azure/search-documents
-bibliotheek:
const { SearchIndexClient, SearchClient, AzureKeyCredential, odata } = require("@azure/search-documents");
Vervolgens moet het dotenv
-pakket als volgt worden gelezen in de parameters van het bestand .env:
// Load the .env file if it exists
require("dotenv").config();
// Getting endpoint and apiKey from .env file
const endpoint = process.env.SEARCH_API_ENDPOINT || "";
const apiKey = process.env.SEARCH_API_KEY || "";
Met behulp van onze import-en omgevingsvariabelen kunt u de hoofdfunctie definiëren.
De meeste functionaliteit in de SDK is asynchroon, dus we maken onze hoofdfunctie async
. We nemen ook een main().catch()
op onder de hoofdfunctie om eventuele fouten te ondervangen en te registreren:
async function main() {
console.log(`Running Azure AI Search JavaScript quickstart...`);
if (!endpoint || !apiKey) {
console.log("Make sure to set valid values for endpoint and apiKey with proper authorization.");
return;
}
// remaining quickstart code will go here
}
main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Met deze basis kunnen we een index gaan maken.
Index maken
Maak een bestand hotels_quickstart_index.json. Dit bestand definieert hoe Azure AI Search werkt met de documenten die u in de volgende stap laadt. Elk veld wordt geïdentificeerd door een name
en beschikt over een opgegeven type
. Elk veld heeft ook een reeks indexkenmerken die aangeven of Azure AI Search kan zoeken, filteren, sorteren en facet op het veld. De meeste velden zijn eenvoudige gegevenstypen, maar een aantal, zoals AddressType
, is van een complex type waarmee u uitgebreide gegevensstructuren in uw index kunt maken. Meer informatie over ondersteunde gegevenstypen en indexkenmerken die worden beschreven in Create Index (REST).
Voeg de volgende inhoud toe aan hotels_quickstart_index.json of download het bestand.
{
"name": "hotels-quickstart",
"fields": [
{
"name": "HotelId",
"type": "Edm.String",
"key": true,
"filterable": true
},
{
"name": "HotelName",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": true,
"facetable": false
},
{
"name": "Description",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": false,
"facetable": false,
"analyzerName": "en.lucene"
},
{
"name": "Description_fr",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": false,
"facetable": false,
"analyzerName": "fr.lucene"
},
{
"name": "Category",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Tags",
"type": "Collection(Edm.String)",
"searchable": true,
"filterable": true,
"sortable": false,
"facetable": true
},
{
"name": "ParkingIncluded",
"type": "Edm.Boolean",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "LastRenovationDate",
"type": "Edm.DateTimeOffset",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Rating",
"type": "Edm.Double",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Address",
"type": "Edm.ComplexType",
"fields": [
{
"name": "StreetAddress",
"type": "Edm.String",
"filterable": false,
"sortable": false,
"facetable": false,
"searchable": true
},
{
"name": "City",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "StateProvince",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "PostalCode",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Country",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
}
]
}
],
"suggesters": [
{
"name": "sg",
"searchMode": "analyzingInfixMatching",
"sourceFields": [
"HotelName"
]
}
]
}
Als u de indexdefinitie hebt geïmplementeerd, wilt u hotels_quickstart_index. json boven in het bestand index.js importeren, zodat de hoofdfunctie de indexdefinitie kan openen.
const indexDefinition = require('./hotels_quickstart_index.json');
In de hoofdfunctie maken we vervolgens een SearchIndexClient
, die wordt gebruikt voor het maken en beheren van indexen voor Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
De index moet worden verwijderd als deze al bestaat. Deze bewerking is een veelvoorkomende procedure voor test-/democode.
Dit doet u door een eenvoudige functie te definiëren die probeert om de index te verwijderen.
async function deleteIndexIfExists(indexClient, indexName) {
try {
await indexClient.deleteIndex(indexName);
console.log('Deleting index...');
} catch {
console.log('Index does not exist yet.');
}
}
Als u de functie wilt uitvoeren, halen we de indexnaam op uit de indexdefinitie en geven we de indexName
door met de indexClient
aan de functie deleteIndexIfExists()
.
const indexName = indexDefinition["name"];
console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);
Daarna kunt u de index maken met behulp van de methode createIndex()
.
console.log('Creating index...');
let index = await indexClient.createIndex(indexDefinition);
console.log(`Index named ${index.name} has been created.`);
De voorbeeldtoepassing uitvoeren
U bent nu klaar om de voorbeeldtoepassing uit te voeren. Gebruik een terminalvenster om de volgende opdrachten uit te voeren:
node index.js
Als u de broncode hebt gedownload en de vereiste pakketten nog niet hebt geïnstalleerd, voert u eerst npm install
uit.
U ziet nu een reeks berichten waarin de acties worden beschreven die door het programma worden uitgevoerd.
Open het Overzicht van uw zoekservice in Azure Portal. Selecteer het tabblad Indexen . Als het goed is, ziet u ongeveer het volgende voorbeeld:
In de volgende stap gaat u gegevens aan de index toevoegen.
Documenten laden
In Azure AI Search zijn documenten gegevensstructuren die zowel invoer zijn voor het indexeren als uitvoeren van query's. U kunt dergelijke gegevens naar de index pushen of een Indexeerfunctie gebruiken. In dat geval kunnen we de documenten via een programma naar de index pushen.
De documentinvoer bestaat mogelijk uit rijen in een database, blobs in Blob Storage of, zoals in dit voorbeeld, JSON-documenten op een schijf. U kunt hotels.json downloaden of uw eigen hotels.json-bestand maken met de volgende inhoud:
{
"value": [
{
"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.6,
"Address": {
"StreetAddress": "677 5th Ave",
"City": "New York",
"StateProvince": "NY",
"PostalCode": "10022"
}
},
{
"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.6,
"Address": {
"StreetAddress": "140 University Town Center Dr",
"City": "Sarasota",
"StateProvince": "FL",
"PostalCode": "34243"
}
},
{
"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.8,
"Address": {
"StreetAddress": "3393 Peachtree Rd",
"City": "Atlanta",
"StateProvince": "GA",
"PostalCode": "30326"
}
},
{
"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.6,
"Address": {
"StreetAddress": "7400 San Pedro Ave",
"City": "San Antonio",
"StateProvince": "TX",
"PostalCode": "78216"
}
}
]
}
Net als bij wat we hebben gedaan met de indexDefinition
, moeten we ook importeren hotels.json
bovenaan index.js , zodat de gegevens kunnen worden geopend in onze hoofdfunctie.
const hotelData = require('./hotels.json');
Als u gegevens in de zoekindex wilt indexeren, moet u nu een SearchClient
maken. Terwijl de SearchIndexClient
wordt gebruikt voor het maken en beheren van een index, wordt de SearchClient
gebruikt voor het uploaden van documenten en het uitvoeren van query's op de index.
Er zijn twee manieren om een SearchClient
maken. De eerste optie is het maken van een geheel nieuwe SearchClient
:
const searchClient = new SearchClient(endpoint, indexName, new AzureKeyCredential(apiKey));
U kunt ook de methode getSearchClient()
van de SearchIndexClient
gebruiken om de SearchClient
te maken:
const searchClient = indexClient.getSearchClient(indexName);
Nu de client is gedefinieerd, uploadt u de documenten in de zoekindex. In dit geval gebruiken we de mergeOrUploadDocuments()
methode, waarmee de documenten worden geüpload of samengevoegd met een bestaand document als er al een document met dezelfde sleutel bestaat.
console.log('Uploading documents...');
let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Voer het programma opnieuw uit met node index.js
. U ziet nu een iets andere reeks berichten dan in stap 1. Nu bestaat de index wel en u zou een bericht moeten zien over het verwijderen van de index voordat de nieuwe index wordt gemaakt en hierin gegevens worden geplaatst.
Voordat we de query's in de volgende stap uitvoeren, definieert u een functie om het programma één seconde te laten wachten. Dit is alleen bedoeld voor test- en demonstratiedoeleinden om te controleren of de indexering is voltooid en of de documenten beschikbaar zijn in de index voor onze query's.
function sleep(ms) {
var d = new Date();
var d2 = null;
do {
d2 = new Date();
} while (d2 - d < ms);
}
Als u het programma één seconde wilt laten wachten, roept u de functie sleep
aan zoals hieronder:
sleep(1000);
Een index doorzoeken
Als er een index is gemaakt en documenten zijn geüpload, bent u klaar om query's naar de index te verzenden. In deze sectie verzenden we vijf verschillende query's naar de zoekindex om verschillende onderdelen van de queryfunctionaliteit te demonstreren die voor u beschikbaar zijn.
De query's worden als volgt geschreven in een sendQueries()
functie die we in de hoofdfunctie aanroepen:
await sendQueries(searchClient);
Query's worden verzonden met behulp van de methode search()
van searchClient
. De eerste parameter is de zoektekst en de tweede parameter specificeert zoekopties.
De eerste query zoekt *
, wat gelijk is aan ‘zoeken in alle’ en selecteert drie van de velden in de index. Het is een best practice om alleen de velden te select
die u nodig hebt, omdat het ophalen van overbodige gegevens een latentie kan veroorzaken bij uw query's.
De searchOptions
voor deze query is includeTotalCount
ook ingesteld op true
, waarmee het aantal gevonden overeenkomende resultaten wordt geretourneerd.
async function sendQueries(searchClient) {
console.log('Query #1 - search everything:');
let searchOptions = {
includeTotalCount: true,
select: ["HotelId", "HotelName", "Rating"]
};
let searchResults = await searchClient.search("*", searchOptions);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
console.log(`Result count: ${searchResults.count}`);
// remaining queries go here
}
De resterende query's die hieronder worden beschreven, moeten ook worden toegevoegd aan de functie sendQueries()
. Ze zijn hier gescheiden voor leesbaarheid.
In de volgende query geven we de zoekterm "wifi"
op en nemen we ook een filter op om alleen resultaten te retourneren waarvan de status gelijk is aan 'FL'
. Resultaten worden ook gerangschikt op de Rating
van het hotel.
console.log('Query #2 - Search with filter, orderBy, and select:');
let state = 'FL';
searchOptions = {
filter: odata`Address/StateProvince eq ${state}`,
orderBy: ["Rating desc"],
select: ["HotelId", "HotelName", "Rating"]
};
searchResults = await searchClient.search("wifi", searchOptions);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
Vervolgens kan de zoekopdracht worden beperkt tot één doorzoekbaar veld met behulp van de parameter searchFields
. Deze methode is een uitstekende optie om uw query efficiënter te maken als u weet dat u alleen geïnteresseerd bent in overeenkomsten in bepaalde velden.
console.log('Query #3 - Limit searchFields:');
searchOptions = {
select: ["HotelId", "HotelName", "Rating"],
searchFields: ["HotelName"]
};
searchResults = await searchClient.search("Sublime Palace", searchOptions);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
console.log();
Een andere veelgebruikte optie die in een query moet worden opgenomen, is facets
. Met facetten kunt u filters maken op uw gebruikersinterface, zodat gebruikers eenvoudig kunnen zien welke waarden ze kunnen filteren.
console.log('Query #4 - Use facets:');
searchOptions = {
facets: ["Category"],
select: ["HotelId", "HotelName", "Rating"],
searchFields: ["HotelName"]
};
searchResults = await searchClient.search("*", searchOptions);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
De laatste query maakt gebruik van de methode getDocument()
van de searchClient
. Zo kunt u een document efficiënt ophalen met de bijbehorende sleutel.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument(key='3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
De voorbeeldtoepassing uitvoeren
Voer het programma uit met behulp van node index.js
. Naast de vorige stappen worden de query's verzonden en worden de resultaten naar de console geschreven.
Bouw een Node.js-toepassing met behulp van de bibliotheek @azure/search-documents om een zoekindex te maken, laden en er query's op uit te voeren.
U kunt ook de broncode downloaden om te beginnen met een voltooid project of deze stappen volgen om uw eigen project te maken.
Uw omgeving instellen
We hebben de volgende hulpprogramma's gebruikt om deze quickstart te maken.
Het project maken
Visual Studio Code starten.
Open het opdrachtenpalet met Ctrl+Shift+P en open de geïntegreerde terminal.
Maak een ontwikkelingsmap en geef deze de quickstart voor de naam:
mkdir quickstart
cd quickstart
Initialiseer een leeg project met npm door de volgende opdracht uit te voeren. Als u het project volledig wilt initialiseren, drukt u meerdere keren op Enter om de standaardwaarden te accepteren, met uitzondering van de licentie, die u moet instellen op MIT.
npm init
Installeer @azure/search-documents
, de JavaScript/TypeScript SDK voor Azure AI Search.
npm install @azure/search-documents
Installeren dotenv
, die wordt gebruikt voor het importeren van de omgevingsvariabelen, zoals de naam van uw zoekservice en API-sleutel.
npm install dotenv
Ga naar de snelstartmap en controleer of u het project en de bijbehorende afhankelijkheden hebt geconfigureerd door te controleren of uw package.json-bestand er ongeveer als volgt uitziet:
{
"name": "quickstart",
"version": "1.0.0",
"description": "Azure AI Search Quickstart",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"Azure",
"Search"
],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"@azure/search-documents": "^12.1.0",
"dotenv": "^16.4.5"
}
}
Maak het bestand .env om de parameters van de zoekservice op te slaan:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
Vervang de YOUR-SEARCH-SERVICE-URL
waarde door de naam van de URL van uw zoekservice-eindpunt. Vervang door <YOUR-SEARCH-ADMIN-API-KEY>
de beheersleutel die u eerder hebt vastgelegd.
Index.ts-bestand maken
Vervolgens maken we een index.ts-bestand . Dit is het hoofdbestand dat als host fungeert voor onze code.
Importeer boven aan dit bestand de @azure/search-documents
-bibliotheek:
import {
AzureKeyCredential,
ComplexField,
odata,
SearchClient,
SearchFieldArray,
SearchIndex,
SearchIndexClient,
SearchSuggester,
SimpleField
} from "@azure/search-documents";
Vervolgens moet het dotenv
-pakket als volgt worden gelezen in de parameters van het bestand .env:
// Load the .env file if it exists
import dotenv from 'dotenv';
dotenv.config();
// Getting endpoint and apiKey from .env file
const endpoint = process.env.SEARCH_API_ENDPOINT || "";
const apiKey = process.env.SEARCH_API_KEY || "";
Met behulp van onze import-en omgevingsvariabelen kunt u de hoofdfunctie definiëren.
De meeste functionaliteit in de SDK is asynchroon, dus we maken onze hoofdfunctie async
. We nemen ook een main().catch()
op onder de hoofdfunctie om eventuele fouten te ondervangen en te registreren:
async function main() {
console.log(`Running Azure AI Search JavaScript quickstart...`);
if (!endpoint || !apiKey) {
console.log("Make sure to set valid values for endpoint and apiKey with proper authorization.");
return;
}
// remaining quickstart code will go here
}
main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Met deze basis kunnen we een index gaan maken.
Index maken
Maak een bestand hotels_quickstart_index.json. Dit bestand definieert hoe Azure AI Search werkt met de documenten die u in de volgende stap laadt. Elk veld wordt geïdentificeerd door een name
en beschikt over een opgegeven type
. Elk veld heeft ook een reeks indexkenmerken die aangeven of Azure AI Search kan zoeken, filteren, sorteren en facet op het veld. De meeste velden zijn eenvoudige gegevenstypen, maar een aantal, zoals AddressType
, is van een complex type waarmee u uitgebreide gegevensstructuren in uw index kunt maken. Meer informatie over ondersteunde gegevenstypen en indexkenmerken die worden beschreven in Create Index (REST).
Voeg de volgende inhoud toe aan hotels_quickstart_index.json of download het bestand.
{
"name": "hotels-quickstart",
"fields": [
{
"name": "HotelId",
"type": "Edm.String",
"key": true,
"filterable": true
},
{
"name": "HotelName",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": true,
"facetable": false
},
{
"name": "Description",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": false,
"facetable": false,
"analyzerName": "en.lucene"
},
{
"name": "Description_fr",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": false,
"facetable": false,
"analyzerName": "fr.lucene"
},
{
"name": "Category",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Tags",
"type": "Collection(Edm.String)",
"searchable": true,
"filterable": true,
"sortable": false,
"facetable": true
},
{
"name": "ParkingIncluded",
"type": "Edm.Boolean",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "LastRenovationDate",
"type": "Edm.DateTimeOffset",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Rating",
"type": "Edm.Double",
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Address",
"type": "Edm.ComplexType",
"fields": [
{
"name": "StreetAddress",
"type": "Edm.String",
"filterable": false,
"sortable": false,
"facetable": false,
"searchable": true
},
{
"name": "City",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "StateProvince",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "PostalCode",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
},
{
"name": "Country",
"type": "Edm.String",
"searchable": true,
"filterable": true,
"sortable": true,
"facetable": true
}
]
}
],
"suggesters": [
{
"name": "sg",
"searchMode": "analyzingInfixMatching",
"sourceFields": [
"HotelName"
]
}
]
}
Nu de indexdefinitie is ingesteld, willen we hotels_quickstart_index.json boven aan index.ts importeren, zodat de hoofdfunctie toegang heeft tot de indexdefinitie.
// Importing the index definition and sample data
import indexDefinition from './hotels_quickstart_index.json';
interface HotelIndexDefinition {
name: string;
fields: SimpleField[] | ComplexField[];
suggesters: SearchSuggester[];
};
const hotelIndexDefinition: HotelIndexDefinition = indexDefinition as HotelIndexDefinition;
In de hoofdfunctie maken we vervolgens een SearchIndexClient
, die wordt gebruikt voor het maken en beheren van indexen voor Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
De index moet worden verwijderd als deze al bestaat. Deze bewerking is een veelvoorkomende procedure voor test-/democode.
Dit doet u door een eenvoudige functie te definiëren die probeert om de index te verwijderen.
async function deleteIndexIfExists(indexClient: SearchIndexClient, indexName: string): Promise<void> {
try {
await indexClient.deleteIndex(indexName);
console.log('Deleting index...');
} catch {
console.log('Index does not exist yet.');
}
}
Als u de functie wilt uitvoeren, halen we de indexnaam op uit de indexdefinitie en geven we de indexName
door met de indexClient
aan de functie deleteIndexIfExists()
.
// Getting the name of the index from the index definition
const indexName: string = hotelIndexDefinition.name;
console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);
Daarna kunt u de index maken met behulp van de methode createIndex()
.
console.log('Creating index...');
let index = await indexClient.createIndex(hotelIndexDefinition);
console.log(`Index named ${index.name} has been created.`);
De voorbeeldtoepassing uitvoeren
Op dit moment bent u klaar om het voorbeeld te bouwen en uit te voeren. Gebruik een terminalvenster om de volgende opdrachten uit te voeren om uw bron te bouwen en tsc
vervolgens uw bron uit te voeren met node
:
tsc
node index.ts
Als u de broncode hebt gedownload en de vereiste pakketten nog niet hebt geïnstalleerd, voert u eerst npm install
uit.
U ziet nu een reeks berichten waarin de acties worden beschreven die door het programma worden uitgevoerd.
Open het Overzicht van uw zoekservice in Azure Portal. Selecteer het tabblad Indexen . Als het goed is, ziet u ongeveer het volgende voorbeeld:
In de volgende stap gaat u gegevens aan de index toevoegen.
Documenten laden
In Azure AI Search zijn documenten gegevensstructuren die zowel invoer zijn voor het indexeren als uitvoeren van query's. U kunt dergelijke gegevens naar de index pushen of een Indexeerfunctie gebruiken. In dat geval kunnen we de documenten via een programma naar de index pushen.
De documentinvoer bestaat mogelijk uit rijen in een database, blobs in Blob Storage of, zoals in dit voorbeeld, JSON-documenten op een schijf. U kunt hotels.json downloaden of uw eigen hotels.json-bestand maken met de volgende inhoud:
{
"value": [
{
"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.6,
"Address": {
"StreetAddress": "677 5th Ave",
"City": "New York",
"StateProvince": "NY",
"PostalCode": "10022"
}
},
{
"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.6,
"Address": {
"StreetAddress": "140 University Town Center Dr",
"City": "Sarasota",
"StateProvince": "FL",
"PostalCode": "34243"
}
},
{
"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.8,
"Address": {
"StreetAddress": "3393 Peachtree Rd",
"City": "Atlanta",
"StateProvince": "GA",
"PostalCode": "30326"
}
},
{
"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.6,
"Address": {
"StreetAddress": "7400 San Pedro Ave",
"City": "San Antonio",
"StateProvince": "TX",
"PostalCode": "78216"
}
}
]
}
Net als bij indexDefinition moeten we ook bovenaan index.ts importeren hotels.json
, zodat de gegevens kunnen worden geopend in onze hoofdfunctie.
import hotelData from './hotels.json';
interface Hotel {
HotelId: string;
HotelName: string;
Description: string;
Description_fr: string;
Category: string;
Tags: string[];
ParkingIncluded: string | boolean;
LastRenovationDate: string;
Rating: number;
Address: {
StreetAddress: string;
City: string;
StateProvince: string;
PostalCode: string;
};
};
const hotels: Hotel[] = hotelData["value"];
Als u gegevens in de zoekindex wilt indexeren, moet u nu een SearchClient
maken. Terwijl de SearchIndexClient
wordt gebruikt voor het maken en beheren van een index, wordt de SearchClient
gebruikt voor het uploaden van documenten en het uitvoeren van query's op de index.
Er zijn twee manieren om een SearchClient
maken. De eerste optie is het maken van een geheel nieuwe SearchClient
:
const searchClient = new SearchClient<Hotel>(endpoint, indexName, new AzureKeyCredential(apiKey));
U kunt ook de methode getSearchClient()
van de SearchIndexClient
gebruiken om de SearchClient
te maken:
const searchClient = indexClient.getSearchClient<Hotel>(indexName);
Nu de client is gedefinieerd, uploadt u de documenten in de zoekindex. In dit geval gebruiken we de mergeOrUploadDocuments()
methode, waarmee de documenten worden geüpload of samengevoegd met een bestaand document als er al een document met dezelfde sleutel bestaat. Controleer vervolgens of de bewerking is geslaagd omdat ten minste het eerste document bestaat.
console.log("Uploading documents...");
const indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotels);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Voer het programma opnieuw uit met tsc && node index.ts
. U ziet nu een iets andere reeks berichten dan in stap 1. Nu bestaat de index wel en u zou een bericht moeten zien over het verwijderen van de index voordat de nieuwe index wordt gemaakt en hierin gegevens worden geplaatst.
Voordat we de query's in de volgende stap uitvoeren, definieert u een functie om het programma één seconde te laten wachten. Dit is alleen bedoeld voor test- en demonstratiedoeleinden om te controleren of de indexering is voltooid en of de documenten beschikbaar zijn in de index voor onze query's.
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Als u het programma één seconde wilt laten wachten, roept u de sleep
functie aan:
sleep(1000);
Een index doorzoeken
Als er een index is gemaakt en documenten zijn geüpload, bent u klaar om query's naar de index te verzenden. In deze sectie verzenden we vijf verschillende query's naar de zoekindex om verschillende onderdelen van de queryfunctionaliteit te demonstreren die voor u beschikbaar zijn.
De query's worden als volgt geschreven in een sendQueries()
functie die we in de hoofdfunctie aanroepen:
await sendQueries(searchClient);
Query's worden verzonden met behulp van de methode search()
van searchClient
. De eerste parameter is de zoektekst en de tweede parameter specificeert zoekopties.
De eerste query zoekt *
, wat gelijk is aan ‘zoeken in alle’ en selecteert drie van de velden in de index. Het is een best practice om alleen de velden te select
die u nodig hebt, omdat het ophalen van overbodige gegevens een latentie kan veroorzaken bij uw query's.
De searchOptions
voor deze query heeft ook includeTotalCount
ingesteld op true
, waardoor het aantal gevonden resultaten wat overeenkomt wordt geretourneerd.
async function sendQueries(
searchClient: SearchClient<Hotel>
): Promise<void> {
// Query 1
console.log('Query #1 - search everything:');
const selectFields: SearchFieldArray<Hotel> = [
"HotelId",
"HotelName",
"Rating",
];
const searchOptions1 = {
includeTotalCount: true,
select: selectFields
};
let searchResults = await searchClient.search("*", searchOptions1);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
console.log(`Result count: ${searchResults.count}`);
// remaining queries go here
}
De resterende query's die hieronder worden beschreven, moeten ook worden toegevoegd aan de functie sendQueries()
. Ze zijn hier gescheiden voor leesbaarheid.
In de volgende query geven we de zoekterm "wifi"
op en nemen we ook een filter op om alleen resultaten te retourneren waarvan de status gelijk is aan 'FL'
. Resultaten worden ook gerangschikt op de Rating
van het hotel.
console.log('Query #2 - search with filter, orderBy, and select:');
let state = 'FL';
const searchOptions2 = {
filter: odata`Address/StateProvince eq ${state}`,
orderBy: ["Rating desc"],
select: selectFields
};
searchResults = await searchClient.search("wifi", searchOptions2);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
Vervolgens kan de zoekopdracht worden beperkt tot één doorzoekbaar veld met behulp van de parameter searchFields
. Deze methode is een uitstekende optie om uw query efficiënter te maken als u weet dat u alleen geïnteresseerd bent in overeenkomsten in bepaalde velden.
console.log('Query #3 - limit searchFields:');
const searchOptions3 = {
select: selectFields,
searchFields: ["HotelName"] as const
};
searchResults = await searchClient.search("Sublime Palace", searchOptions3);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
Een andere veelgebruikte optie die in een query moet worden opgenomen, is facets
. Met facetten kunt u zelfgestuurd inzoomen op de resultaten in uw gebruikersinterface. De resultaten van facetten kunnen worden omgezet in selectievakjes in het resultaatvenster.
console.log('Query #4 - limit searchFields and use facets:');
const searchOptions4 = {
facets: ["Category"],
select: selectFields,
searchFields: ["HotelName"] as const
};
searchResults = await searchClient.search("*", searchOptions4);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
De laatste query maakt gebruik van de methode getDocument()
van de searchClient
. Zo kunt u een document efficiënt ophalen met de bijbehorende sleutel.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument('3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Het voorbeeld opnieuw uitvoeren
Bouw en voer het programma uit met tsc && node index.ts
. Naast de vorige stappen worden de query's verzonden en worden de resultaten naar de console geschreven.
Wanneer u in uw eigen abonnement werkt, is het een goed idee om aan het einde van een project te bepalen of u de gemaakte resources nog nodig hebt. Resources die actief blijven, kunnen u geld kosten. U kunt resources afzonderlijk verwijderen, maar u kunt ook de resourcegroep verwijderen als u de volledige resourceset wilt verwijderen.
Als u een gratis service gebruikt, moet u er rekening mee houden dat u beperkt bent tot drie indexen, indexeerfuncties en gegevensbronnen. U kunt afzonderlijke items in de portal verwijderen om onder de limiet te blijven.
In deze quickstart hebt u een set taken doorlopen om een index te maken, deze te laden met documenten en query's uit te voeren. In verschillende fasen hebben we korte routes genomen om de code te vereenvoudigen voor leesbaarheid en begrijpelijkheid. Nu u bekend bent met de basisconcepten, kunt u een zelfstudie uitproberen waarmee de Azure AI Search-API's in een web-app worden aangeroepen.