Välj ett programmeringsspråk för nästa steg. Klientbiblioteken för Azure.Search.Documents är tillgängliga i Azure SDK:er för .NET, Python, Java och JavaScript/Typescript.
Skapa ett konsolprogram med hjälp av klientbiblioteket Azure.Search.Documents för att skapa, läsa in och köra frågor mot ett sökindex.
Du kan också ladda ned källkoden för att börja med ett färdigt projekt eller följa dessa steg för att skapa din egen.
Konfigurera din miljö
Starta Visual Studio och skapa ett nytt projekt för en konsolapp.
I Verktyg>NuGet Package Manager väljer du Hantera NuGet-paket för lösning....
Välj bläddra.
Sök efter Azure.Search.Documents-paketet och välj version 11.0 eller senare.
Välj Installera för att lägga till sammansättningen i projektet och lösningen.
Skapa en sökklient
I Program.cs ändrar du namnområdet till AzureSearch.SDK.Quickstart.v11
och lägger sedan till följande using
direktiv.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
Kopiera följande kod för att skapa två klienter. SearchIndexClient skapar indexet och SearchClient läser in och frågar ett befintligt index. Båda behöver tjänstslutpunkten och en administratörs-API-nyckel för autentisering med behörighet att skapa/ta bort.
Eftersom koden skapar URI:n åt dig anger du bara söktjänstens namn i serviceName
egenskapen.
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);
. . .
}
Skapa ett index
Den här snabbstarten skapar ett Hotell-index som du läser in med hotelldata och kör frågor mot. I det här steget definierar du fälten i indexet. Varje fältdefinition innehåller ett namn, en datatyp och attribut som avgör hur fältet används.
I det här exemplet används synkrona metoder i biblioteket Azure.Search.Documents för enkelhet och läsbarhet. För produktionsscenarier bör du dock använda asynkrona metoder för att hålla appen skalbar och dynamisk. Du skulle till exempel använda CreateIndexAsync i stället för CreateIndex.
Lägg till en tom klassdefinition i projektet: Hotel.cs
Kopiera följande kod till Hotel.cs för att definiera strukturen för ett hotelldokument. Attribut i fältet avgör hur det används i ett program. Attributet måste till exempel IsFilterable
tilldelas till varje fält som stöder ett filteruttryck.
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; }
}
}
I azure.search.documents-klientbiblioteket kan du använda SearchableField och SimpleField för att effektivisera fältdefinitioner. Båda är derivat av ett SearchField och kan förenkla koden:
SimpleField
kan vara vilken datatyp som helst, är alltid inte sökbar (den ignoreras för fulltextsökningsfrågor) och kan hämtas (den är inte dold). Andra attribut är inaktiverade som standard, men kan aktiveras. Du kan använda ett SimpleField
för dokument-ID eller fält som endast används i filter, fasetter eller bedömningsprofiler. I så fall bör du tillämpa eventuella attribut som är nödvändiga för scenariot, till exempel IsKey = true
för ett dokument-ID. Mer information finns i SimpleFieldAttribute.cs i källkoden.
SearchableField
måste vara en sträng och är alltid sökbar och hämtningsbar. Andra attribut är inaktiverade som standard, men kan aktiveras. Eftersom den här fälttypen är sökbar stöder den synonymer och det fullständiga komplementet av analysverktygsegenskaper. Mer information finns i SearchableFieldAttribute.cs i källkoden.
Oavsett om du använder det grundläggande SearchField
API:et eller någon av hjälpmodellerna måste du uttryckligen aktivera attribut för filter, fasetter och sortering. Till exempel måste IsFilterable, IsSortable och IsFacetable uttryckligen tillskrivas, som du ser i föregående exempel.
Lägg till en andra tom klassdefinition i projektet: Address.cs. Kopiera följande kod till klassen.
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; }
}
}
Skapa ytterligare två klasser: Hotel.Methods.cs och Address.Methods.cs för ToString()
åsidosättningar. Dessa klasser används för att återge sökresultat i konsolens utdata. Innehållet i dessa klasser finns inte i den här artikeln, men du kan kopiera koden från filer i GitHub.
I Program.cs skapar du ett SearchIndex-objekt och anropar sedan metoden CreateIndex för att uttrycka indexet i söktjänsten. Indexet innehåller också en SearchSuggester för att aktivera automatisk komplettering i de angivna fälten.
// 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);
}
Läsa in dokument
Azure AI Search söker efter innehåll som lagras i tjänsten. I det här steget läser du in JSON-dokument som överensstämmer med det hotellindex som du nyss skapade.
I Azure AI Search är sökdokument datastrukturer som både är indata för indexering och utdata från frågor. Som hämtats från en extern datakälla kan dokumentindata vara rader i en databas, blobar i Blob Storage eller JSON-dokument på disk. I det här exemplet tar vi en genväg och bäddar in JSON-dokument för fyra hotell i själva koden.
När du laddar upp dokument måste du använda ett IndexDocumentsBatch-objekt . Ett IndexDocumentsBatch
objekt innehåller en samling åtgärder, som var och en innehåller ett dokument och en egenskap som talar om för Azure AI Search vilken åtgärd som ska utföras (ladda upp, slå samman, ta bort och slå sammanEllerUpload).
I Program.cs skapar du en matris med dokument och indexåtgärder och skickar sedan matrisen till IndexDocumentsBatch
. Följande dokument överensstämmer med indexet hotels-quickstart enligt definitionen i hotellklassen.
// 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}");
}
}
När du har initierat Objektet IndexDocumentsBatch kan du skicka det till indexet genom att anropa IndexDocuments på ditt SearchClient-objekt .
Lägg till följande rader i Main()
. Inläsning av dokument görs med Hjälp av SearchClient, men åtgärden kräver även administratörsbehörighet för tjänsten, som vanligtvis är associerad med SearchIndexClient. Ett sätt att konfigurera den här åtgärden är att hämta SearchClient genom SearchIndexClient
(adminClient
i det här exemplet).
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
// Load documents
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(ingesterClient);
Eftersom det här är en konsolapp som kör alla kommandon sekventiellt lägger du till en väntetid på 2 sekunder mellan indexering och frågor.
// 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);
Fördröjningen på 2 sekunder kompenserar för indexering, vilket är asynkront, så att alla dokument kan indexeras innan frågorna körs. Kodning i en fördröjning är vanligtvis bara nödvändigt i demonstrationer, tester och exempelprogram.
Sök i ett index
Du kan få frågeresultat så snart det första dokumentet indexeras, men den faktiska testningen av indexet bör vänta tills alla dokument har indexerats.
Det här avsnittet lägger till två funktioner: frågelogik och resultat. För frågor använder du sökmetoden . Den här metoden tar söktext (frågesträngen) och andra alternativ.
Klassen SearchResults representerar resultatet.
I Program.cs skapar du en WriteDocuments
metod som skriver ut sökresultat till konsolen.
// 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();
}
Skapa en RunQueries
metod för att köra frågor och returnera resultat. Resultatet är Hotellobjekt. Det här exemplet visar metodsignaturen och den första frågan. Den här frågan visar parametern Välj som gör att du kan skapa resultatet med hjälp av valda fält från dokumentet.
// 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);
I den andra frågan söker du efter en term, lägger till ett filter som väljer dokument där Omdöme är större än 4 och sorterar sedan efter Klassificering i fallande ordning. Filter är ett booleskt uttryck som utvärderas över IsFilterable-fält i ett index. Filtrera frågor antingen inkludera eller exkludera värden. Därför finns det ingen relevanspoäng associerad med en filterfråga.
// 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);
Den tredje frågan visar searchFields
, som används för att begränsa en fulltextsökningsåtgärd till specifika fält.
// 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);
Den fjärde frågan visar facets
, som kan användas för att strukturera en fasetterad navigeringsstruktur.
// 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);
I den femte frågan returnerar du ett specifikt dokument. Ett dokumentuppslag är ett typiskt svar på OnClick
händelsen i en resultatuppsättning.
// 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);
Den sista frågan visar syntaxen för automatisk komplettering, som simulerar en partiell användarinmatning av sa som matchar två möjliga matchningar i de sourceFields som är associerade med den förslagsanvändare som du definierade i indexet.
// Query 6
Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
var autoresponse = srchclient.Autocomplete("sa", "sg");
WriteDocuments(autoresponse);
Lägg till RunQueries
i 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();
Föregående frågor visar flera sätt att matcha termer i en fråga: fulltextsökning, filter och automatisk komplettering.
Fulltextsökning och -filter utförs med metoden SearchClient.Search . En sökfråga kan skickas i strängensearchText
, medan ett filteruttryck kan skickas i filteregenskapen för klassen SearchOptions. Om du vill filtrera utan att söka skickar du "*"
bara efter parametern searchText
för sökmetoden . Om du vill söka utan filtrering lämnar du Filter
egenskapen oetig eller skickar inte någon SearchOptions
instans alls.
Köra programmet
Tryck på F5 för att återskapa appen och köra programmet i sin helhet.
Utdata innehåller meddelanden från Console.WriteLine, med tillägg av frågeinformation och resultat.
Använd en Jupyter-anteckningsbok och biblioteket azure-search-documents i Azure SDK för Python för att skapa, läsa in och fråga ett sökindex.
Du kan också ladda ned och köra en färdig notebook-fil.
Konfigurera din miljö
Använd Visual Studio Code med Python-tillägget eller motsvarande IDE med Python 3.10 eller senare.
Vi rekommenderar en virtuell miljö för den här snabbstarten:
Starta Visual Studio Code.
Öppna kommandopaletten (Ctrl+Skift+P).
Sök efter Python: Skapa miljö.
Välj Venv.
Välj en Python-tolk. Välj version 3.10 eller senare.
Det kan ta en minut att konfigurera. Om du stöter på problem kan du läsa Python-miljöer i VS Code.
Installera paket och ange variabler
Installera paket, inklusive azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet
! pip install azure-identity --quiet
! pip install python-dotenv --quiet
Ange slutpunkten och API-nyckeln för din tjänst:
search_endpoint: str = "PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE"
search_api_key: str = "PUT-YOUR-SEARCH-SERVICE-ADMIN-API-KEY-HERE"
index_name: str = "hotels-quickstart"
Skapa ett index
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')
Skapa en nyttolast för dokument
Använd en indexåtgärd för åtgärdstypen, till exempel uppladdning eller sammanslagning och uppladdning. Dokument kommer från Exemplet HotelsData på 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"
}
}
]
Ladda upp dokument
# 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)
Kör din första fråga
Använd sökmetoden för klassen search.client.
Det här exemplet kör en tom sökning (search=*
), som returnerar en orankad lista (sökpoäng = 1,0) godtyckliga dokument. Eftersom det inte finns några kriterier inkluderas alla dokument i resultatet.
# Run an empty query (returns selected fields, all documents)
results = search_client.search(query_type='simple',
search_text="*" ,
select='HotelName,Description',
include_total_count=True)
print ('Total Documents Matching Query:', results.get_count())
for result in results:
print(result["@search.score"])
print(result["HotelName"])
print(f"Description: {result['Description']}")
Köra en termfråga
Nästa fråga lägger till hela termer i sökuttrycket ("wifi"). Den här frågan anger att resultaten endast innehåller de fälten i -instruktionen select
. Om du begränsar fälten som kommer tillbaka minimeras mängden data som skickas tillbaka över tråden och minskar sökfördröjningen.
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']}")
Lägg till ett filter
Lägg till ett filteruttryck som endast returnerar de hotell med ett omdöme som är större än fyra, sorterat i fallande ordning.
# 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"]))
Lägg till fältomfång
Lägg till search_fields
i omfånget för frågekörning till specifika fält.
# 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"]))
Lägg till fasetter
Fasetter genereras för positiva matchningar som finns i sökresultaten. Det finns inga noll matchningar. Om sökresultaten inte innehåller termen wifi visas inte wifi i den fasetterade navigeringsstrukturen.
# Return facets
results = search_client.search(search_text="*", facets=["Category"])
facets = results.get_facets()
for facet in facets["Category"]:
print(" {}".format(facet))
Slå upp ett dokument
Returnera ett dokument baserat på dess nyckel. Den här åtgärden är användbar om du vill visa detaljerad information när en användare väljer ett objekt i ett sökresultat.
# 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"]))
Lägg till automatisk komplettering
Automatisk komplettering kan ge potentiella matchningar när användaren skriver i sökrutan.
Autocomplete använder en suggester (sg
) för att veta vilka fält som innehåller potentiella matchningar för förslagsbegäranden. I den här snabbstarten är Tags
fälten , Address/City
, Address/Country
.
Om du vill simulera automatisk komplettering skickar du bokstäverna sa som en partiell sträng. Metoden för automatisk komplettering av SearchClient skickar tillbaka potentiella termmatchningar.
# 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'])
Skapa ett Java-konsolprogram med hjälp av biblioteket Azure.Search.Documents för att skapa, läsa in och köra frågor mot ett sökindex.
Du kan också ladda ned källkoden för att börja med ett färdigt projekt eller följa dessa steg för att skapa din egen.
Konfigurera din miljö
Använd följande verktyg för att skapa den här snabbstarten.
Skapa projektet
Starta Visual Studio Code.
Öppna kommandopaletten med hjälp av Ctrl+Skift+P. Sök efter Skapa Java-projekt.
Välj Maven.
Välj maven-archetype-quickstart.
Välj den senaste versionen, för närvarande 1.4.
Ange azure.search.sample som grupp-ID.
Ange azuresearchquickstart som artefakt-ID.
Välj den mapp som projektet ska skapas i.
Slutför projektskapandet i den integrerade terminalen. Tryck på Retur för att acceptera standardvärdet för "1.0-SNAPSHOT" och skriv sedan "y" för att bekräfta egenskaperna för projektet.
Öppna mappen som du skapade projektet i.
Ange Maven-beroenden
Öppna filen pom.xml och lägg till följande beroenden.
<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>
Ändra Java-versionen för kompilatorn till 11.
<maven.compiler.source>1.11</maven.compiler.source>
<maven.compiler.target>1.11</maven.compiler.target>
Skapa en sökklient
App
Öppna klassen under src, main, java, azure, search, sample. Lägg till följande importdirektiv.
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;
I följande exempel finns platshållare för ett söktjänstnamn, administratörs-API-nyckel som ger behörighet att skapa och ta bort samt indexnamn. Ersätt giltiga värden för alla tre platshållarna. Skapa två klienter: SearchIndexClient skapar indexet och SearchClient läser in och frågar ett befintligt index. Båda behöver tjänstslutpunkten och en administratörs-API-nyckel för autentisering med behörighet att skapa och ta bort.
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();
}
Skapa ett index
Den här snabbstarten skapar ett Hotell-index som du läser in med hotelldata och kör frågor mot. I det här steget definierar du fälten i indexet. Varje fältdefinition innehåller ett namn, en datatyp och attribut som avgör hur fältet används.
I det här exemplet används synkrona metoder i biblioteket azure-search-documents för enkelhet och läsbarhet. För produktionsscenarier bör du dock använda asynkrona metoder för att hålla appen skalbar och dynamisk. Du kan till exempel använda SearchAsyncClient i stället för SearchClient.
Lägg till en tom klassdefinition i projektet: Hotel.java
Kopiera följande kod till Hotel.java
för att definiera strukturen för ett hotelldokument. Attribut i fältet avgör hur det används i ett program. Till exempel måste IsFilterable-anteckningen tilldelas till varje fält som stöder ett filteruttryck
// 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 "";
}
}
}
I azure.search.documents-klientbiblioteket kan du använda SearchableField och SimpleField för att effektivisera fältdefinitioner.
SimpleField
kan vara vilken datatyp som helst, är alltid inte sökbar (den ignoreras för fulltextsökningsfrågor) och kan hämtas (den är inte dold). Andra attribut är inaktiverade som standard, men kan aktiveras. Du kan använda simplefield för dokument-ID:er eller fält som endast används i filter, fasetter eller bedömningsprofiler. I så fall måste du tillämpa eventuella attribut som är nödvändiga för scenariot, till exempel IsKey = true för ett dokument-ID.
SearchableField
måste vara en sträng och är alltid sökbar och hämtningsbar. Andra attribut är inaktiverade som standard, men kan aktiveras. Eftersom den här fälttypen är sökbar stöder den synonymer och det fullständiga komplementet av analysverktygsegenskaper.
Oavsett om du använder det grundläggande SearchField
API:et eller någon av hjälpmodellerna måste du uttryckligen aktivera attribut för filter, fasetter och sortering. Till exempel isFilterable
, isSortable
, och isFacetable
måste uttryckligen tillskrivas, som du ser i föregående exempel.
Lägg till en andra tom klassdefinition i projektet: Address.java
. Kopiera följande kod till klassen.
// 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;
}
I App.java
skapar du ett SearchIndex
objekt i main
metoden och anropar createOrUpdateIndex
sedan metoden för att skapa indexet i söktjänsten. Indexet innehåller även en SearchSuggester
för att aktivera automatisk komplettering på de angivna fälten.
// Create Search Index for Hotel model
searchIndexClient.createOrUpdateIndex(
new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
.setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));
Läsa in dokument
Azure AI Search söker efter innehåll som lagras i tjänsten. I det här steget läser du in JSON-dokument som överensstämmer med det hotellindex som du nyss skapade.
I Azure AI Search är sökdokument datastrukturer som både är indata för indexering och utdata från frågor. Som hämtats från en extern datakälla kan dokumentindata vara rader i en databas, blobar i Blob Storage eller JSON-dokument på disk. I det här exemplet tar vi en genväg och bäddar in JSON-dokument för fyra hotell i själva koden.
När du laddar upp dokument måste du använda ett IndexDocumentsBatch-objekt . Ett IndexDocumentsBatch
objekt innehåller en samling IndexActions, som var och en innehåller ett dokument och en egenskap som talar om för Azure AI Search vilken åtgärd som ska utföras (ladda upp, slå samman, ta bort och mergeOrUpload).
I App.java
skapar du dokument och indexåtgärder och skickar dem sedan till IndexDocumentsBatch
. Följande dokument överensstämmer med indexet hotels-quickstart enligt definitionen i hotellklassen.
// 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");
}
}
När du har initierat IndexDocumentsBatch
objektet kan du skicka det till indexet genom att anropa indexDocuments för objektet SearchClient
.
Lägg till följande rader i Main()
. Inläsning av dokument görs med hjälp av SearchClient
.
// Upload sample hotel documents to the Search Index
uploadDocuments(searchClient);
Eftersom det här är en konsolapp som kör alla kommandon sekventiellt lägger du till en väntetid på 2 sekunder mellan indexering och frågor.
// 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)
{
}
Fördröjningen på 2 sekunder kompenserar för indexering, vilket är asynkront, så att alla dokument kan indexeras innan frågorna körs. Kodning i en fördröjning är vanligtvis bara nödvändigt i demonstrationer, tester och exempelprogram.
Sök i ett index
Du kan få frågeresultat så snart det första dokumentet indexeras, men den faktiska testningen av indexet bör vänta tills alla dokument har indexerats.
Det här avsnittet lägger till två funktioner: frågelogik och resultat. För frågor använder du sökmetoden. Den här metoden tar söktext (frågesträngen) och andra alternativ.
I App.java
skapar du en WriteDocuments
metod som skriver ut sökresultat till konsolen.
// 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();
}
Skapa en RunQueries
metod för att köra frågor och returnera resultat. Resultatet är Hotel
objekt. Det här exemplet visar metodsignaturen och den första frågan. Den här frågan visar parametern Select
som gör att du kan skapa resultatet med hjälp av valda fält från dokumentet.
// 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));
}
I den andra frågan söker du efter en term, lägger till ett filter som väljer dokument där Omdöme är större än 4 och sorterar sedan efter Klassificering i fallande ordning. Filter är ett booleskt uttryck som utvärderas över isFilterable
fält i ett index. Filtrera frågor antingen inkludera eller exkludera värden. Därför finns det ingen relevanspoäng associerad med en filterfråga.
// 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));
Den tredje frågan visar searchFields
, som används för att begränsa en fulltextsökningsåtgärd till specifika fält.
// 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));
Den fjärde frågan visar facets
, som kan användas för att strukturera en fasetterad navigeringsstruktur.
// 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));
I den femte frågan returnerar du ett specifikt dokument.
// 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();
Den sista frågan visar syntaxen för automatisk komplettering, vilket simulerar en partiell användarinmatning av s som matchar två möjliga matchningar i den sourceFields
associerade med den förslagsanvändare som du definierade i indexet.
// Query 6
System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");
WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));
Lägg till RunQueries
i 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");
Föregående frågor visar flera sätt att matcha termer i en fråga: fulltextsökning, filter och automatisk komplettering.
Fulltextsökning och -filter utförs med metoden SearchClient.search . En sökfråga kan skickas i strängen searchText
, medan ett filteruttryck kan skickas i filter
egenskapen för klassen SearchOptions . Om du vill filtrera utan att söka skickar du bara "*" för parametern searchText
för search
metoden. Om du vill söka utan filtrering lämnar du filter
egenskapen oetig eller skickar inte någon SearchOptions
instans alls.
Köra programmet
Tryck på F5 för att återskapa appen och köra programmet i sin helhet.
Utdata innehåller meddelanden från System.out.println
, med tillägg av frågeinformation och resultat.
Skapa ett Node.js program med hjälp av biblioteket @azure/search-documents för att skapa, läsa in och fråga ett sökindex.
Du kan också ladda ned källkoden för att börja med ett färdigt projekt eller följa dessa steg för att skapa din egen.
Konfigurera din miljö
Vi använde följande verktyg för att skapa den här snabbstarten.
Skapa projektet
Starta Visual Studio Code.
Öppna kommandopaletten med hjälp av Ctrl+Skift+P och öppna den integrerade terminalen.
Skapa en utvecklingskatalog med namnet snabbstart:
mkdir quickstart
cd quickstart
Initiera ett tomt projekt med npm genom att köra följande kommando. Om du vill initiera projektet helt trycker du på Retur flera gånger för att acceptera standardvärdena, förutom licensen, som du bör ange till MIT.
npm init
Installera @azure/search-documents
, JavaScript/TypeScript SDK för Azure AI Search.
npm install @azure/search-documents
Installera dotenv
, som används för att importera miljövariabler som söktjänstens namn och API-nyckel.
npm install dotenv
Gå till snabbstartskatalogen och bekräfta sedan att du har konfigurerat projektet och dess beroenden genom att kontrollera att filen package.json ser ut ungefär som följande json:
{
"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"
}
}
Skapa en fil .env för att lagra söktjänstparametrarna:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
Ersätt värdet YOUR-SEARCH-SERVICE-URL
med namnet på söktjänstens slutpunkts-URL. Ersätt <YOUR-SEARCH-ADMIN-API-KEY>
med administratörsnyckeln som du registrerade tidigare.
Skapa index.js fil
Sedan skapar vi en index.js fil, som är huvudfilen som är värd för vår kod.
Längst upp i den här filen importerar @azure/search-documents
vi biblioteket:
const { SearchIndexClient, SearchClient, AzureKeyCredential, odata } = require("@azure/search-documents");
Sedan måste vi kräva dotenv
att paketet läser in parametrarna från .env-filen på följande sätt:
// 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 || "";
Med våra import- och miljövariabler på plats är vi redo att definiera huvudfunktionen.
De flesta av funktionerna i SDK:et är asynkrona, så vi gör vår huvudfunktion async
. Vi inkluderar även en main().catch()
under huvudfunktionen för att fånga och logga eventuella fel som påträffas:
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);
});
Med det på plats är vi redo att skapa ett index.
Skapa index
Skapa en fil hotels_quickstart_index.json. Den här filen definierar hur Azure AI Search fungerar med de dokument som du läser in i nästa steg. Varje fält identifieras av en name
och har en angiven type
. Varje fält har också en serie indexattribut som anger om Azure AI Search kan söka, filtrera, sortera och fasettera på fältet. De flesta av fälten är enkla datatyper, men vissa, som AddressType
är komplexa typer som gör att du kan skapa omfattande datastrukturer i ditt index. Du kan läsa mer om datatyper som stöds och indexattribut som beskrivs i Skapa index (REST).
Lägg till följande innehåll för att hotels_quickstart_index.json eller ladda ned filen.
{
"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"
]
}
]
}
Med vår indexdefinition på plats vill vi importera hotels_quickstart_index.json överst i index.js så att huvudfunktionen kan komma åt indexdefinitionen.
const indexDefinition = require('./hotels_quickstart_index.json');
I huvudfunktionen skapar vi sedan en SearchIndexClient
, som används för att skapa och hantera index för Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Sedan vill vi ta bort indexet om det redan finns. Den här åtgärden är en vanlig metod för test-/demokod.
Det gör vi genom att definiera en enkel funktion som försöker ta bort indexet.
async function deleteIndexIfExists(indexClient, indexName) {
try {
await indexClient.deleteIndex(indexName);
console.log('Deleting index...');
} catch {
console.log('Index does not exist yet.');
}
}
För att köra funktionen extraherar vi indexnamnet från indexdefinitionen och skickar indexName
med indexClient
till deleteIndexIfExists()
funktionen.
const indexName = indexDefinition["name"];
console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);
Efter det är vi redo att skapa indexet med createIndex()
-metoden.
console.log('Creating index...');
let index = await indexClient.createIndex(indexDefinition);
console.log(`Index named ${index.name} has been created.`);
Kör exemplet
Nu är du redo att köra exemplet. Använd ett terminalfönster för att köra följande kommando:
node index.js
Om du har laddat ned källkoden och inte har installerat de nödvändiga paketen ännu kör du npm install
först.
Du bör se en serie meddelanden som beskriver de åtgärder som vidtas av programmet.
Öppna översikten över söktjänsten i Azure Portal. Välj fliken Index . Du bör se något som liknar följande exempel:
I nästa steg lägger du till data för indexering.
Läsa in dokument
I Azure AI Search är dokument datastrukturer som både är indata för indexering och utdata från frågor. Du kan skicka sådana data till indexet eller använda en indexerare. I det här fallet skickar vi programmatiskt dokumenten till indexet.
Dokumentindata kan vara rader i en databas, blobar i Blob Storage eller, som i det här exemplet, JSON-dokument på disk. Du kan antingen ladda ned hotels.json eller skapa en egen hotels.json fil med följande innehåll:
{
"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"
}
}
]
}
På samma sätt som vi gjorde med indexDefinition
måste vi också importera hotels.json
överst i index.js så att data kan nås i vår huvudfunktion.
const hotelData = require('./hotels.json');
För att indexera data i sökindexet måste vi nu skapa en SearchClient
. SearchIndexClient
Används för att skapa och hantera ett index, SearchClient
men används för att ladda upp dokument och köra frågor mot indexet.
Det finns två sätt att skapa en SearchClient
. Det första alternativet är att skapa en SearchClient
från grunden:
const searchClient = new SearchClient(endpoint, indexName, new AzureKeyCredential(apiKey));
Du kan också använda getSearchClient()
metoden SearchIndexClient
för för att skapa SearchClient
:
const searchClient = indexClient.getSearchClient(indexName);
Nu när klienten har definierats laddar du upp dokumenten till sökindexet. I det här fallet använder mergeOrUploadDocuments()
vi metoden som laddar upp dokumenten eller sammanfogar dem med ett befintligt dokument om det redan finns ett dokument med samma nyckel.
console.log('Uploading documents...');
let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Kör programmet igen med node index.js
. Du bör se en något annorlunda uppsättning meddelanden än de du såg i steg 1. Den här gången finns indexet och du bör se ett meddelande om att ta bort det innan appen skapar det nya indexet och publicerar data till det.
Innan vi kör frågorna i nästa steg definierar du en funktion så att programmet väntar en sekund. Detta görs bara i test-/demosyfte för att säkerställa att indexeringen är klar och att dokumenten är tillgängliga i indexet för våra frågor.
function sleep(ms) {
var d = new Date();
var d2 = null;
do {
d2 = new Date();
} while (d2 - d < ms);
}
Om du vill att programmet ska vänta en sekund anropar du sleep
funktionen som nedan:
sleep(1000);
Sök i ett index
När ett index har skapats och dokument har laddats upp är du redo att skicka frågor till indexet. I det här avsnittet skickar vi fem olika frågor till sökindexet för att demonstrera olika frågefunktioner som är tillgängliga för dig.
Frågorna skrivs i en sendQueries()
funktion som vi anropar i huvudfunktionen enligt följande:
await sendQueries(searchClient);
Frågor skickas med metoden search()
searchClient
. Den första parametern är söktexten och den andra parametern anger sökalternativ.
Den första frågan söker efter *
, vilket motsvarar att söka efter allt och väljer tre av fälten i indexet. Det är en bra idé att bara select
använda de fält du behöver eftersom onödiga data kan ge svarstid till dina frågor.
För searchOptions
den här frågan har includeTotalCount
också angetts till true
, som returnerar antalet matchande resultat som hittades.
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 återstående frågorna som beskrivs nedan bör också läggas till i sendQueries()
funktionen. De är separerade här för läsbarhet.
I nästa fråga anger vi söktermen "wifi"
och inkluderar även ett filter för att endast returnera resultat där tillståndet är lika med 'FL'
. Resultaten beställs också av hotellets Rating
.
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)}`);
}
Därefter begränsas sökningen till ett enda sökbart fält med hjälp av parametern searchFields
. Den här metoden är ett bra alternativ för att göra frågan mer effektiv om du vet att du bara är intresserad av matchningar i vissa fält.
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();
Ett annat vanligt alternativ att ta med i en fråga är facets
. Med fasetter kan du skapa filter i användargränssnittet för att göra det enkelt för användarna att veta vilka värden de kan filtrera ned till.
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)}`);
}
Den sista frågan använder getDocument()
metoden för searchClient
. På så sätt kan du effektivt hämta ett dokument med dess nyckel.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument(key='3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Kör exemplet
Kör programmet med hjälp node index.js
av . Förutom föregående steg skickas frågorna och resultaten skrivs till konsolen.
Skapa ett Node.js program med hjälp av biblioteket @azure/search-documents för att skapa, läsa in och fråga ett sökindex.
Du kan också ladda ned källkoden för att börja med ett färdigt projekt eller följa dessa steg för att skapa din egen.
Konfigurera din miljö
Vi använde följande verktyg för att skapa den här snabbstarten.
Skapa projektet
Starta Visual Studio Code.
Öppna kommandopaletten med hjälp av Ctrl+Skift+P och öppna den integrerade terminalen.
Skapa en utvecklingskatalog med namnet snabbstart:
mkdir quickstart
cd quickstart
Initiera ett tomt projekt med npm genom att köra följande kommando. Om du vill initiera projektet helt trycker du på Retur flera gånger för att acceptera standardvärdena, förutom licensen, som du bör ange till MIT.
npm init
Installera @azure/search-documents
, JavaScript/TypeScript SDK för Azure AI Search.
npm install @azure/search-documents
Installera dotenv
, som används för att importera miljövariabler som söktjänstens namn och API-nyckel.
npm install dotenv
Gå till snabbstartskatalogen och bekräfta sedan att du har konfigurerat projektet och dess beroenden genom att kontrollera att filen package.json ser ut ungefär som följande json:
{
"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"
}
}
Skapa en fil .env för att lagra söktjänstparametrarna:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
Ersätt värdet YOUR-SEARCH-SERVICE-URL
med namnet på söktjänstens slutpunkts-URL. Ersätt <YOUR-SEARCH-ADMIN-API-KEY>
med administratörsnyckeln som du registrerade tidigare.
Skapa index.ts fil
Sedan skapar vi en index.ts fil, som är huvudfilen som är värd för vår kod.
Längst upp i den här filen importerar @azure/search-documents
vi biblioteket:
import {
AzureKeyCredential,
ComplexField,
odata,
SearchClient,
SearchFieldArray,
SearchIndex,
SearchIndexClient,
SearchSuggester,
SimpleField
} from "@azure/search-documents";
Sedan måste vi kräva dotenv
att paketet läser in parametrarna från .env-filen på följande sätt:
// 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 || "";
Med våra import- och miljövariabler på plats är vi redo att definiera huvudfunktionen.
De flesta av funktionerna i SDK:et är asynkrona, så vi gör vår huvudfunktion async
. Vi inkluderar även en main().catch()
under huvudfunktionen för att fånga och logga eventuella fel som påträffas:
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);
});
Med det på plats är vi redo att skapa ett index.
Skapa index
Skapa en fil hotels_quickstart_index.json. Den här filen definierar hur Azure AI Search fungerar med de dokument som du läser in i nästa steg. Varje fält identifieras av en name
och har en angiven type
. Varje fält har också en serie indexattribut som anger om Azure AI Search kan söka, filtrera, sortera och fasettera på fältet. De flesta av fälten är enkla datatyper, men vissa, som AddressType
är komplexa typer som gör att du kan skapa omfattande datastrukturer i ditt index. Du kan läsa mer om datatyper som stöds och indexattribut som beskrivs i Skapa index (REST).
Lägg till följande innehåll för att hotels_quickstart_index.json eller ladda ned filen.
{
"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"
]
}
]
}
Med vår indexdefinition på plats vill vi importera hotels_quickstart_index.json överst i index.ts så att huvudfunktionen kan komma åt indexdefinitionen.
// 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;
I huvudfunktionen skapar vi sedan en SearchIndexClient
, som används för att skapa och hantera index för Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Sedan vill vi ta bort indexet om det redan finns. Den här åtgärden är en vanlig metod för test-/demokod.
Det gör vi genom att definiera en enkel funktion som försöker ta bort indexet.
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.');
}
}
För att köra funktionen extraherar vi indexnamnet från indexdefinitionen och skickar indexName
med indexClient
till deleteIndexIfExists()
funktionen.
// 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);
Efter det är vi redo att skapa indexet med createIndex()
-metoden.
console.log('Creating index...');
let index = await indexClient.createIndex(hotelIndexDefinition);
console.log(`Index named ${index.name} has been created.`);
Kör exemplet
Nu är du redo att skapa och köra exemplet. Använd ett terminalfönster för att köra följande kommandon för att skapa källan med tsc
och kör sedan källan med node
:
tsc
node index.ts
Om du har laddat ned källkoden och inte har installerat de nödvändiga paketen ännu kör du npm install
först.
Du bör se en serie meddelanden som beskriver de åtgärder som vidtas av programmet.
Öppna översikten över söktjänsten i Azure Portal. Välj fliken Index . Du bör se något som liknar följande exempel:
I nästa steg lägger du till data för indexering.
Läsa in dokument
I Azure AI Search är dokument datastrukturer som både är indata för indexering och utdata från frågor. Du kan skicka sådana data till indexet eller använda en indexerare. I det här fallet skickar vi programmatiskt dokumenten till indexet.
Dokumentindata kan vara rader i en databas, blobar i Blob Storage eller, som i det här exemplet, JSON-dokument på disk. Du kan antingen ladda ned hotels.json eller skapa en egen hotels.json fil med följande innehåll:
{
"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"
}
}
]
}
På samma sätt som vi gjorde med indexDefinition måste vi också importera hotels.json
överst i index.ts så att data kan nås i vår huvudfunktion.
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"];
För att indexera data i sökindexet måste vi nu skapa en SearchClient
. SearchIndexClient
Används för att skapa och hantera ett index, SearchClient
men används för att ladda upp dokument och köra frågor mot indexet.
Det finns två sätt att skapa en SearchClient
. Det första alternativet är att skapa en SearchClient
från grunden:
const searchClient = new SearchClient<Hotel>(endpoint, indexName, new AzureKeyCredential(apiKey));
Du kan också använda getSearchClient()
metoden SearchIndexClient
för för att skapa SearchClient
:
const searchClient = indexClient.getSearchClient<Hotel>(indexName);
Nu när klienten har definierats laddar du upp dokumenten till sökindexet. I det här fallet använder mergeOrUploadDocuments()
vi metoden som laddar upp dokumenten eller sammanfogar dem med ett befintligt dokument om det redan finns ett dokument med samma nyckel. Kontrollera sedan att åtgärden lyckades eftersom åtminstone det första dokumentet finns.
console.log("Uploading documents...");
const indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotels);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Kör programmet igen med tsc && node index.ts
. Du bör se en något annorlunda uppsättning meddelanden än de du såg i steg 1. Den här gången finns indexet och du bör se ett meddelande om att ta bort det innan appen skapar det nya indexet och publicerar data till det.
Innan vi kör frågorna i nästa steg definierar du en funktion så att programmet väntar en sekund. Detta görs bara i test-/demosyfte för att säkerställa att indexeringen är klar och att dokumenten är tillgängliga i indexet för våra frågor.
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Om du vill att programmet ska vänta en sekund anropar du sleep
funktionen:
sleep(1000);
Sök i ett index
När ett index har skapats och dokument har laddats upp är du redo att skicka frågor till indexet. I det här avsnittet skickar vi fem olika frågor till sökindexet för att demonstrera olika frågefunktioner som är tillgängliga för dig.
Frågorna skrivs i en sendQueries()
funktion som vi anropar i huvudfunktionen enligt följande:
await sendQueries(searchClient);
Frågor skickas med metoden search()
searchClient
. Den första parametern är söktexten och den andra parametern anger sökalternativ.
Den första frågan söker efter *
, vilket motsvarar att söka efter allt och väljer tre av fälten i indexet. Det är en bra idé att bara select
använda de fält du behöver eftersom onödiga data kan ge svarstid till dina frågor.
För searchOptions
den här frågan har includeTotalCount
också angetts till true
, vilket returnerar antalet matchande resultat som hittades.
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 återstående frågorna som beskrivs nedan bör också läggas till i sendQueries()
funktionen. De är separerade här för läsbarhet.
I nästa fråga anger vi söktermen "wifi"
och inkluderar även ett filter för att endast returnera resultat där tillståndet är lika med 'FL'
. Resultaten beställs också av hotellets Rating
.
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)}`);
}
Därefter begränsas sökningen till ett enda sökbart fält med hjälp av parametern searchFields
. Den här metoden är ett bra alternativ för att göra frågan mer effektiv om du vet att du bara är intresserad av matchningar i vissa fält.
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)}`);
}
Ett annat vanligt alternativ att ta med i en fråga är facets
. Med fasetter kan du tillhandahålla självriktad detaljvisning från resultatet i användargränssnittet. Fasetteringsresultatet kan omvandlas till kryssrutor i resultatfönstret.
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)}`);
}
Den sista frågan använder getDocument()
metoden för searchClient
. På så sätt kan du effektivt hämta ett dokument med dess nyckel.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument('3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Kör exemplet igen
Skapa och kör programmet med tsc && node index.ts
. Förutom föregående steg skickas frågorna och resultaten skrivs till konsolen.
När du arbetar i din egen prenumeration kan det dock vara klokt att i slutet av ett projekt kontrollera om du fortfarande behöver de resurser som du skapade. Resurser som fortsätter att köras kostar pengar. Du kan ta bort enstaka resurser eller hela resursgruppen om du vill ta bort alla resurser.
Om du använder en kostnadsfri tjänst ska du komma ihåg att du är begränsad till tre index, indexerare och datakällor. Du kan ta bort enskilda objekt i portalen för att hålla dig under gränsen.
I den här snabbstarten arbetade du med en uppsättning uppgifter för att skapa ett index, läsa in det med dokument och köra frågor. I olika steg tog vi genvägar för att förenkla koden för läsbarhet och förståelse. Nu när du är bekant med de grundläggande begreppen kan du prova en självstudiekurs som anropar API:erna för Azure AI Search i en webbapp.