Zvolte programovací jazyk pro další krok. Klientské knihovny Azure.Search.Documents jsou k dispozici v sadách Azure SDK pro .NET, Python, Javu a JavaScript.
Vytvořte konzolovou aplikaci pomocí klientské knihovny Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání. Případně si můžete zdrojový kód stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.
Nastavení prostředí
Spusťte Visual Studio a vytvořte nový projekt pro konzolovou aplikaci.
V nástrojích>NuGet Správce balíčků vyberte Spravovat balíčky NuGet pro řešení....
Vyberte Procházet.
Vyhledejte balíček Azure.Search.Documents a vyberte verzi 11.0 nebo novější.
Výběrem možnosti Nainstalovat vpravo přidejte sestavení do projektu a řešení.
Vytvoření vyhledávacího klienta
V Program.cs změňte obor názvů na AzureSearch.SDK.Quickstart.v11
a přidejte následující using
direktivy.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
Vytvořte dva klienty: SearchIndexClient vytvoří index a SearchClient načte a dotazuje existující index. Oba potřebují koncový bod služby a klíč rozhraní API pro správu pro ověřování s právy k vytvoření nebo odstranění.
Vzhledem k tomu, že kód sestaví identifikátor URI za vás, zadejte pouze název vyhledávací služby ve vlastnosti serviceName.
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);
. . .
}
Vytvoření indexu
V tomto rychlém startu vytvoříte index hotelů, na který načtete data hotelů a spustíte dotazy. V tomto kroku definujte pole v indexu. Každá definice pole obsahuje název, datový typ a atributy, které určují způsob použití pole.
V tomto příkladu se pro jednoduchost a čitelnost používají synchronní metody knihovny Azure.Search.Documents. V produkčních scénářích byste ale měli použít asynchronní metody, které umožňují udržovat aplikaci škálovatelnou a responzivní. Místo CreateIndex byste například použili CreateIndexAsync.
Přidání prázdné definice třídy do projektu: Hotel.cs
Zkopírujte následující kód do Hotel.cs a definujte strukturu hotelového dokumentu. Atributy v poli určují, jak se používá v aplikaci. Atribut musí být například IsFilterable
přiřazen ke každému poli, které podporuje výraz filtru.
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; }
}
}
V klientské knihovně Azure.Search.Documents můžete k zjednodušení definic polí použít SearchableField a SimpleField . Oba jsou deriváty vyhledávacího pole a můžou potenciálně zjednodušit váš kód:
SimpleField
může být libovolný datový typ, je vždy nehledatelný (je ignorován pro dotazy fulltextového vyhledávání) a je načítaný (není skrytý). Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Můžete použít SimpleField
pro ID dokumentu nebo pole použitá pouze v filtrech, omezujících vlastností nebo v bodovacích profilech. Pokud ano, nezapomeňte použít všechny atributy, které jsou nezbytné pro daný scénář, například IsKey = true
pro ID dokumentu. Další informace najdete v tématu SimpleFieldAttribute.cs ve zdrojovém kódu.
SearchableField
musí být řetězec a je vždy prohledávatelný a načístelný. Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Vzhledem k tomu, že tento typ pole je prohledávatelný, podporuje synonyma a úplný doplněk vlastností analyzátoru. Další informace najdete v SearchableFieldAttribute.cs ve zdrojovém kódu.
Bez ohledu na to, jestli používáte základní SearchField
rozhraní API nebo jeden z pomocných modelů, musíte explicitně povolit atributy filtru, omezující vlastnosti a řazení. Například IsFilterable, IsSortable a IsFacetable musí být explicitně přiřazeny, jak je znázorněno v ukázce výše.
Přidejte do projektu druhou definici prázdné třídy: Address.cs. Zkopírujte do třídy následující kód.
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; }
}
}
Vytvořte dvě další třídy: Hotel.Methods.cs a Address.Methods.cs pro přepsání ToString(). Tyto třídy slouží k vykreslení výsledků hledání ve výstupu konzoly. Obsah těchto tříd není v tomto článku k dispozici, ale kód můžete zkopírovat ze souborů na GitHubu.
V Program.cs vytvořte SearchIndex objekt a potom volání CreateIndex metoda vyjádřit index ve vyhledávací službě. Index obsahuje také SearchSuggester , který povolí automatické dokončování v zadaných polích.
// 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);
}
Nahrání dokumentů
Azure AI Search vyhledá obsah uložený ve službě. V tomto kroku načtete dokumenty JSON, které odpovídají právě vytvořenému indexu hotelu.
Ve službě Azure AI Search jsou vyhledávací dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Jak je získáno z externího zdroje dat, vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo dokumenty JSON na disku. V tomto příkladu přebíráme zástupce a vkládáme dokumenty JSON pro čtyři hotely v samotném kódu.
Při nahrávání dokumentů musíte použít objekt IndexDocumentsBatch . Objekt IndexDocumentsBatch
obsahuje kolekci akcí, z nichž každý obsahuje dokument a vlastnost, která službě Azure AI Search říká, jakou akci provést (nahrání, sloučení, odstranění a mergeOrUpload).
V Program.cs vytvořte pole dokumentů a akcí indexu a pak předejte pole do IndexDocumentsBatch
. Následující dokumenty odpovídají indexu rychlého startu hotelů, jak je definováno hotelovou třídou.
// 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 = "Secret Point Motel",
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 = "Twin Dome Motel",
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 = "Triple 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 Cliff Hotel",
Description = "Sublime Cliff 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 Cliff is part of a lovingly restored 1800 palace.",
DescriptionFr = "Le sublime Cliff 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 Cliff 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}");
}
}
Jakmile inicializujete IndexDocumentsBatch objekt, můžete jej odeslat do indexu voláním IndexDocuments na objekt SearchClient .
Přidejte do main() následující řádky. Načítání dokumentů se provádí pomocí SearchClient, ale operace také vyžaduje oprávnění správce služby, která je obvykle přidružená k SearchIndexClient. Jedním ze způsobů, jak nastavit tuto operaci, je získat SearchClient prostřednictvím SearchIndexClient (v tomto příkladu adminClient).
SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
// Load documents
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(ingesterClient);
Vzhledem k tomu, že se jedná o konzolovou aplikaci, která spouští všechny příkazy postupně, přidejte 2sekundovou dobu čekání mezi indexováním a dotazy.
// 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);
Dvousekundové zpoždění kompenzuje indexování, což je asynchronní, aby se všechny dokumenty mohly indexovat před spuštěním dotazů. Kódování ve zpoždění je obvykle nezbytné pouze v ukázkách, testech a ukázkových aplikacích.
Prohledání indexu
Výsledky dotazu můžete získat hned po indexování prvního dokumentu, ale skutečné testování indexu by mělo počkat na indexování všech dokumentů.
Tato část přidává dvě funkce: logiku dotazu a výsledky. Pro dotazy použijte metodu Search . Tato metoda přebírá hledaný text (řetězec dotazu) a další možnosti.
SearchResults třída představuje výsledky.
V Program.cs vytvořte metodu WriteDocuments , která vytiskne výsledky hledání do konzoly.
// 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();
}
Vytvořte metodu RunQueries pro spouštění dotazů a vracení výsledků. Výsledky jsou objekty Hotelu. Tato ukázka ukazuje podpis metody a první dotaz. Tento dotaz ukazuje parametr Select, který umožňuje vytvořit výsledek pomocí vybraných polí z dokumentu.
// 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);
Ve druhém dotazu vyhledejte termín, přidejte filtr, který vybere dokumenty, ve kterých je hodnocení větší než 4, a potom řadit podle hodnocení v sestupném pořadí. Filtr je logický výraz, který se vyhodnocuje přes pole IsFilterable v indexu. Dotazy filtrování zahrnují nebo vylučují hodnoty. Proto neexistuje žádné skóre relevance přidružené k dotazu filtru.
// 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);
Třetí dotaz ukazuje pole searchFields, která slouží k určení rozsahu operace fulltextového vyhledávání na konkrétní pole.
// 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);
Čtvrtý dotaz ukazuje omezující vlastnosti, které lze použít ke strukturování fasetové navigační struktury.
// 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);
V pátém dotazu vraťte konkrétní dokument. Vyhledání dokumentu je typická odpověď na událost OnClick v sadě výsledků.
// 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);
Poslední dotaz zobrazí syntaxi automatického dokončování, která simuluje částečný vstup uživatele sa, který se přeloží na dvě možné shody ve zdrojových polích přidružených k sugestivnímu modulu, který jste definovali v indexu.
// Query 6
Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
var autoresponse = srchclient.Autocomplete("sa", "sg");
WriteDocuments(autoresponse);
Přidání RunQueries do 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();
Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.
Fulltextové vyhledávání a filtry se provádějí pomocí metody SearchClient.Search . Vyhledávací dotaz lze předat v řetězcisearchText
, zatímco výraz filtru lze předat ve vlastnosti Filter třídy SearchOptions. Pokud chcete filtrovat bez hledání, stačí předat "*"
searchText
parametr metody Search . Pokud chcete hledat bez filtrování, nechejte Filter
vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions
instanci.
Spuštění programu
Stisknutím klávesy F5 znovu sestavíte aplikaci a spustíte program v plném rozsahu.
Výstup obsahuje zprávy z Console.WriteLine s přidáním informací o dotazu a výsledků.
K vytvoření, načtení a dotazování indexu vyhledávání použijte poznámkový blok Jupyter a knihovnu azure-search-documents v sadě Azure SDK pro Python.
Případně si stáhněte a spusťte hotový poznámkový blok.
Nastavení prostředí
Použijte Visual Studio Code s rozšířením Pythonu nebo ekvivalentním integrovaným vývojovém prostředím (IDE) s Pythonem 3.10 nebo novějším.
Pro účely tohoto rychlého startu doporučujeme virtuální prostředí:
Spusťte Visual Studio Code.
Otevřete paletu příkazů (Ctrl+Shift+P).
Vyhledejte Python: Vytvoření prostředí.
Vyberte Venv.
Vyberte interpret Pythonu. Zvolte 3.10 nebo novější.
Nastavení může trvat minutu. Pokud narazíte na problémy, prohlédni si prostředí Pythonu ve VS Code.
Instalace balíčků a nastavení proměnných
Nainstalujte balíčky, včetně azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet
! pip install azure-identity --quiet
! pip install python-dotenv --quiet
Zadejte koncové body a klíče rozhraní API:
search_endpoint: str = "PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE"
search_api_key: str = "PUT-YOUR-SEARCH-SERVICE-ADMIN-API-KEY-HERE"
index_name: str = "hotels-quickstart"
Vytvoření indexu
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')
Vytvoření datové části dokumentů
Pro typ operace použijte akci indexu (nahrání, sloučení a nahrání atd.). Dokumenty pocházejí z HotelsData na GitHubu.
# Create a documents payload
documents = [
{
"@search.action": "upload",
"HotelId": "1",
"HotelName": "Secret Point Motel",
"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": "Twin Dome Motel",
"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": "Triple 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 Cliff Hotel",
"Description": "Sublime Cliff 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 Cliff is part of a lovingly restored 1800 palace.",
"Description_fr": "Le sublime Cliff 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 Cliff 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"
}
}
]
Nahrát dokumenty
# 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)
Spuštění prvního dotazu
Použijte metodu vyhledávání třídy search.client.
Tento příklad spustí prázdné hledání (search=*
), které vrátí neřaděný seznam (skóre hledání = 1,0) libovolných dokumentů. Vzhledem k tomu, že neexistují žádná kritéria, jsou ve výsledcích zahrnuty všechny dokumenty.
# 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']}")
Spuštění dotazu na termín
Další dotaz přidá do vyhledávacího výrazu celé termíny ("wifi"). Tento dotaz určuje, že výsledky obsahují pouze tato pole v select
příkazu. Omezení polí, která se vrátí, minimalizuje množství dat odesílaných zpět přes drát a snižuje latenci vyhledávání.
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']}")
Přidat filtr
Přidejte výraz filtru, který vrací pouze ty hotely s hodnocením větším než čtyři, seřazené sestupně.
# 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"]))
Nastavení rozsahu pro přidání pole
Přidejte search_fields
do oboru provádění dotazu na konkrétní pole.
# 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"]))
Přidání omezujících vlastností
Omezující vlastnosti se generují pro kladné shody nalezené ve výsledcích hledání. Neexistují žádné nulové shody. Pokud výsledky hledání neobsahují termín "wifi"
, "wifi"
nezobrazí se ve fasetové navigační struktuře.
# Return facets
results = search_client.search(search_text="*", facets=["Category"])
facets = results.get_facets()
for facet in facets["Category"]:
print(" {}".format(facet))
Vyhledání dokumentu
Vrátí dokument na základě jeho klíče. Tato operace je užitečná, pokud chcete poskytnout podrobnou analýzu, když uživatel vybere položku ve výsledku hledání.
# 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"]))
Přidání automatického dokončování
Automatické dokončování může poskytovat potenciální shody, protože uživatel zadá do vyhledávacího pole.
Automatické dokončování používá modul pro návrhy (sg
) ke zjištění, která pole obsahují potenciální shody pro žádosti s návrhy. V tomto rychlém startu jsou Tags
tato pole , Address/City
, Address/Country
.
Pokud chcete simulovat automatické dokončování, předejte písmena "sa" jako částečný řetězec. Metoda automatického dokončování SearchClient odesílá zpět potenciální shody termínů.
# 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'])
Vytvořte konzolovou aplikaci Java pomocí knihovny Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání. Případně si můžete zdrojový kód stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.
Nastavení prostředí
K vytvoření tohoto rychlého startu jsme použili následující nástroje.
Vytvoření projektu
Spusťte Visual Studio Code.
Otevřete paletu příkazů Ctrl+Shift+P. Vyhledejte vytvořit projekt Java.
Vyberte Maven.
Vyberte maven-archetype-quickstart.
Vyberte nejnovější verzi, aktuálně 1.4.
Jako ID skupiny zadejte azure.search.sample .
Jako ID artefaktu zadejte azuresearchquickstart .
Vyberte složku, ve které chcete projekt vytvořit.
Dokončete vytváření projektu v integrovaném terminálu. Stisknutím klávesy Enter potvrďte výchozí hodnotu 1.0-SNAPSHOT a zadáním y potvrďte vlastnosti projektu.
Otevřete složku, ve které jste projekt vytvořili.
Určení závislostí Mavenu
Otevřete soubor pom.xml a přidejte následující závislosti.
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-search-documents</artifactId>
<version>11.5.2</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core</artifactId>
<version>1.34.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
Změna verze Java kompilátoru na 11
<maven.compiler.source>1.11</maven.compiler.source>
<maven.compiler.target>1.11</maven.compiler.target>
Vytvoření vyhledávacího klienta
App
Otevřete třídu v části src, main, java, azure, search, sample. Přidejte následující direktivy importu.
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;
Následující příklad obsahuje zástupné symboly pro název vyhledávací služby, klíč rozhraní API správce, který uděluje oprávnění k vytvoření a odstranění a název indexu. Nahraďte platné hodnoty pro všechny tři zástupné symboly. Vytvořte dva klienty: SearchIndexClient vytvoří index a SearchClient načte a dotazuje existující index. Oba potřebují koncový bod služby a klíč rozhraní API pro správu pro ověřování s oprávněními k vytvoření a odstranění.
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();
}
Vytvoření indexu
V tomto rychlém startu vytvoříte index hotelů, na který načtete data hotelů a spustíte dotazy. V tomto kroku definujte pole v indexu. Každá definice pole obsahuje název, datový typ a atributy, které určují způsob použití pole.
V tomto příkladu se pro jednoduchost a čitelnost používají synchronní metody knihovny azure-search-documents. V produkčních scénářích byste ale měli použít asynchronní metody, které umožňují udržovat aplikaci škálovatelnou a responzivní. Například místo SearchClient byste použili SearchAsyncClient .
Přidání prázdné definice třídy do projektu: Hotel.java
Zkopírujte následující kód do Hotel.java a definujte strukturu hotelového dokumentu. Atributy v poli určují, jak se používá v aplikaci. Například anotaci IsFilterable musí být přiřazena ke každému poli, které podporuje výraz filtru.
// 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 "";
}
}
}
V klientské knihovně Azure.Search.Documents můžete k zjednodušení definic polí použít SearchableField a SimpleField .
SimpleField
může být libovolný datový typ, je vždy nehledatelný (je ignorován pro dotazy fulltextového vyhledávání) a je načítaný (není skrytý). Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Pro ID dokumentu nebo pole použitá pouze v filtrech, fazetách nebo v bodovacích profilech můžete použít SimpleField. Pokud ano, nezapomeňte použít všechny atributy, které jsou nezbytné pro scénář, například IsKey = true pro ID dokumentu.
SearchableField
musí být řetězec a je vždy prohledávatelný a načístelný. Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Vzhledem k tomu, že tento typ pole je prohledávatelný, podporuje synonyma a úplný doplněk vlastností analyzátoru.
Bez ohledu na to, jestli používáte základní SearchField
rozhraní API nebo jeden z pomocných modelů, musíte explicitně povolit atributy filtru, omezující vlastnosti a řazení. Například isFilterable
, isSortable
a isFacetable
musí být explicitně přiřazen, jak je znázorněno v ukázce výše.
Přidejte do projektu druhou definici prázdné třídy: Address.cs. Zkopírujte do třídy následující kód.
// 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;
}
V App.java vytvořte SearchIndex
objekt v hlavní metodě a potom zavolejte metodu createOrUpdateIndex
, která vytvoří index ve vyhledávací službě. Index obsahuje SearchSuggester
také povolení automatického dokončování u zadaných polí.
// Create Search Index for Hotel model
searchIndexClient.createOrUpdateIndex(
new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
.setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));
Načtení dokumentů
Azure AI Search vyhledá obsah uložený ve službě. V tomto kroku načtete dokumenty JSON, které odpovídají právě vytvořenému indexu hotelu.
Ve službě Azure AI Search jsou vyhledávací dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Jak je získáno z externího zdroje dat, vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo dokumenty JSON na disku. V tomto příkladu přebíráme zástupce a vkládáme dokumenty JSON pro čtyři hotely v samotném kódu.
Při nahrávání dokumentů musíte použít objekt IndexDocumentsBatch . Objekt IndexDocumentsBatch
obsahuje kolekci IndexActions, z nichž každý obsahuje dokument a vlastnost, která službě Azure AI Search říká, jakou akci provést (nahrání, sloučení, odstranění a mergeOrUpload).
V App.java vytvořte dokumenty a akce indexu a pak je IndexDocumentsBatch
předejte . Následující dokumenty odpovídají indexu rychlého startu hotelů, jak je definováno hotelovou třídou.
// 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 = "Secret Point Motel";
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 = "Twin Dome Motel";
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 = "Triple 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 Cliff Hotel";
hotel.description = "Sublime Cliff 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 Cliff is part of a lovingly restored 1800 palace.";
hotel.descriptionFr = "Le sublime Cliff 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 Cliff 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");
}
}
Jakmile objekt inicializujete IndexDocumentsBatch
, můžete ho odeslat do indexu voláním indexDocuments ve vašem SearchClient
objektu.
Přidejte následující řádky do Main()
. Načítání dokumentů se provádí pomocí SearchClient
.
// Upload sample hotel documents to the Search Index
uploadDocuments(searchClient);
Vzhledem k tomu, že se jedná o konzolovou aplikaci, která spouští všechny příkazy postupně, přidejte 2sekundovou dobu čekání mezi indexováním a dotazy.
// 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)
{
}
Dvousekundové zpoždění kompenzuje indexování, což je asynchronní, aby se všechny dokumenty mohly indexovat před spuštěním dotazů. Kódování ve zpoždění je obvykle nezbytné pouze v ukázkách, testech a ukázkových aplikacích.
Prohledání indexu
Výsledky dotazu můžete získat hned po indexování prvního dokumentu, ale skutečné testování indexu by mělo počkat na indexování všech dokumentů.
Tato část přidává dvě funkce: logiku dotazu a výsledky. Pro dotazy použijte metodu Search. Tato metoda přebírá hledaný text (řetězec dotazu) a další možnosti.
V App.java vytvořte metodu WriteDocuments, která vypíše výsledky hledání do konzoly.
// 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();
}
Vytvořte metodu RunQueries
pro spouštění dotazů a vracení výsledků. Výsledky jsou Hotel
objekty. Tato ukázka ukazuje podpis metody a první dotaz. Tento dotaz ukazuje Select
parametr, který umožňuje vytvořit výsledek pomocí vybraných polí z dokumentu.
// 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));
}
Ve druhém dotazu vyhledejte termín, přidejte filtr, který vybere dokumenty, ve kterých je hodnocení větší než 4, a potom řadit podle hodnocení v sestupném pořadí. Filtr je logický výraz, který se vyhodnocuje přes isFilterable
pole v indexu. Dotazy filtrování zahrnují nebo vylučují hodnoty. Proto neexistuje žádné skóre relevance přidružené k dotazu filtru.
// 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));
Třetí dotaz ukazuje searchFields
, který slouží k určení rozsahu operace fulltextového vyhledávání na konkrétní pole.
// 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));
Čtvrtý dotaz ukazuje omezující vlastnosti, které lze použít ke strukturování fasetové navigační struktury.
// 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));
V pátém dotazu vraťte konkrétní 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();
Poslední dotaz zobrazí syntaxi automatického dokončování, která simuluje částečný vstup uživatele "s", který se přeloží na dvě možné shody v sourceFields
přidruženém s návrhu, který jste definovali v indexu.
// Query 6
System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");
WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));
Přidání RunQueries do 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");
Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.
Fulltextové vyhledávání a filtry se provádějí pomocí metody SearchClient.search . Vyhledávací dotaz lze předat v searchText
řetězci, zatímco výraz filtru lze předat ve filter
vlastnosti SearchOptions třídy. Pokud chcete filtrovat bez hledání, stačí předat searchText
parametr search
metody "*". Pokud chcete hledat bez filtrování, nechejte filter
vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions
instanci.
Spuštění programu
Stisknutím klávesy F5 znovu sestavíte aplikaci a spustíte program v plném rozsahu.
Výstup obsahuje zprávy ze souboru System.out.println s přidáním informací o dotazu a výsledků.
Vytvořte Node.js aplikaci pomocí knihovny @azure/search-documents k vytvoření, načtení a dotazování indexu vyhledávání. Případně si můžete zdrojový kód stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.
Nastavení prostředí
K vytvoření tohoto rychlého startu jsme použili následující nástroje.
Vytvoření projektu
Spusťte Visual Studio Code.
Otevřete paletu příkazů Ctrl+Shift+P a otevřete integrovaný terminál.
Vytvořte vývojový adresář a pojmenujte ho quickstart
:
mkdir quickstart
cd quickstart
Inicializace prázdného projektu pomocí npm spuštěním následujícího příkazu. Pokud chcete projekt plně inicializovat, stiskněte několikrát klávesu Enter a přijměte výchozí hodnoty s výjimkou licence, kterou byste měli nastavit na MIT.
npm init
Nainstalujte @azure/search-documents
sadu JavaScript/TypeScript SDK pro Azure AI Search.
npm install @azure/search-documents
Nainstalujte dotenv
, která se používá k importu proměnných prostředí, jako je název vyhledávací služby a klíč rozhraní API.
npm install dotenv
Ověřte, že jste projekty a její závislosti nakonfigurovali tak, že zkontrolujete, že váš soubor package.json vypadá podobně jako v následujícím kódu 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"
}
}
Vytvořte soubor .env pro uložení parametrů vyhledávací služby:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
<search-service-name>
Nahraďte hodnotu názvem vyhledávací služby. Nahraďte <search-admin-key>
hodnotou klíče, kterou jste si poznamenali dříve.
Vytvoření souboru index.js
Dále vytvoříme soubor index.js , což je hlavní soubor, který bude hostovat náš kód.
V horní části tohoto souboru naimportujeme knihovnu @azure/search-documents
:
const { SearchIndexClient, SearchClient, AzureKeyCredential, odata } = require("@azure/search-documents");
Dále musíme vyžadovat dotenv
, aby balíček četl v parametrech ze souboru .env následujícím způsobem:
// 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 || "";
S našimi importy a proměnnými prostředí jsme připraveni definovat hlavní funkci.
Většina funkcí v sadě SDK je asynchronní, takže vytvoříme naši hlavní funkci async
. Zahrneme main().catch()
také pod hlavní funkci, která zachytí a zapíše všechny zjištěné chyby:
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);
});
S tím jsme připraveni vytvořit index.
Vytvoření indexu
Vytvořte soubor hotels_quickstart_index.json. Tento soubor definuje, jak Azure AI Search funguje s dokumenty, které načtete v dalším kroku. Každé pole bude identifikováno name
a bude mít zadané type
. Každé pole má také řadu atributů indexu, které určují, jestli může Azure AI Search prohledávat, filtrovat, řadit a omezující vlastnosti pole. Většina polí je jednoduchých datových typů, ale některé, jako AddressType
jsou složité typy, které umožňují vytvářet bohaté datové struktury v indexu. Další informace opodporovaných
Přidejte následující obsah, který hotels_quickstart_index.json nebo soubor stáhnete.
{
"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"
]
}
]
}
S naší definicí indexu chceme importovat hotels_quickstart_index.json v horní části index.js , aby hlavní funkce přistupovala k definici indexu.
const indexDefinition = require('./hotels_quickstart_index.json');
V rámci hlavní funkce pak vytvoříme , SearchIndexClient
která se použije k vytváření a správě indexů pro Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Dále chceme odstranit index, pokud už existuje. Tato operace je běžným postupem pro testovací nebo ukázkový kód.
Provedeme to tak, že definujeme jednoduchou funkci, která se pokusí odstranit index.
async function deleteIndexIfExists(indexClient, indexName) {
try {
await indexClient.deleteIndex(indexName);
console.log('Deleting index...');
} catch {
console.log('Index does not exist yet.');
}
}
Ke spuštění funkce extrahujeme název indexu z definice indexu indexClient
deleteIndexIfExists()
a předáme indexName
funkci spolu s funkcí.
const indexName = indexDefinition["name"];
console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);
Potom jsme připraveni vytvořit index pomocí createIndex()
metody.
console.log('Creating index...');
let index = await indexClient.createIndex(indexDefinition);
console.log(`Index named ${index.name} has been created.`);
Spuštění ukázky
V tuto chvíli jste připraveni spustit ukázku. Spuštěním následujícího příkazu použijte okno terminálu:
node index.js
Pokud jste si stáhli zdrojový kód a ještě jste nenainstalovali požadované balíčky, spusťte npm install
nejprve.
Měla by se zobrazit řada zpráv popisujících akce prováděné programem.
Na webu Azure Portal otevřete přehled vaší vyhledávací služby. Vyberte kartu Indexy. Měli byste vidět něco jako v následujícím příkladu:
V dalším kroku přidáte data do indexu.
Nahrání dokumentů
Ve službě Azure AI Search jsou dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Tato data můžete odeslat do indexu nebo použít indexer. V tomto případě naprogramujeme dokumenty do indexu.
Vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo jako v této ukázce dokumenty JSON na disku. Můžete si stáhnout hotels.json nebo vytvořit vlastní soubor hotels.json s následujícím obsahem:
{
"value": [
{
"HotelId": "1",
"HotelName": "Secret Point Motel",
"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": "Twin Dome Motel",
"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": "Triple 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 Cliff Hotel",
"Description": "Sublime Cliff 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 Cliff is part of a lovingly restored 1800 palace.",
"Description_fr": "Le sublime Cliff 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 Cliff 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"
}
}
]
}
Podobně jako u indexDefinition je potřeba importovat hotels.json
také v horní části index.js , aby k datům bylo možné přistupovat v hlavní funkci.
const hotelData = require('./hotels.json');
Abychom mohli data indexovat do vyhledávacího indexu, musíme teď vytvořit .SearchClient
SearchIndexClient
Zatímco se používá k vytvoření a správě indexu, SearchClient
slouží k nahrání dokumentů a dotazování indexu.
Existují dva způsoby, jak vytvořit SearchClient
. První možností je vytvořit úplně SearchClient
od začátku:
const searchClient = new SearchClient(endpoint, indexName, new AzureKeyCredential(apiKey));
Alternativně můžete použít getSearchClient()
metodu SearchIndexClient
vytvoření SearchClient
:
const searchClient = indexClient.getSearchClient(indexName);
Teď, když je klient definovaný, nahrajte dokumenty do indexu vyhledávání. V tomto případě použijeme metodu mergeOrUploadDocuments()
, která nahraje dokumenty nebo je sloučí s existujícím dokumentem, pokud už existuje dokument se stejným klíčem.
console.log('Uploading documents...');
let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Spusťte program znovu pomocí node index.js
příkazu . Měli byste vidět trochu odlišnou sadu zpráv od zpráv, které jste viděli v kroku 1. Tentokrát existuje index a měla by se zobrazit zpráva o jejím odstranění, než aplikace vytvoří nový index a publikuje do něj data.
Než spustíme dotazy v dalším kroku, definujte funkci, která má program čekat na jednu sekundu. To se provádí jenom pro účely testování/ukázky, aby se zajistilo dokončení indexování a dostupnost dokumentů v indexu pro naše dotazy.
function sleep(ms) {
var d = new Date();
var d2 = null;
do {
d2 = new Date();
} while (d2 - d < ms);
}
Pokud chcete, aby program čekal na jednu sekundu, zavolejte funkci, jak je znázorněno sleep
níže:
sleep(1000);
Prohledání indexu
Když jste vytvořili index a nahráli jste dokumenty, můžete do indexu odesílat dotazy. V této části pošleme do indexu vyhledávání pět různých dotazů, abychom vám ukázali různé části funkcí dotazů, které jsou vám k dispozici.
Dotazy jsou napsané ve sendQueries()
funkci, kterou budeme volat v hlavní funkci následujícím způsobem:
await sendQueries(searchClient);
Dotazy se odesílají pomocí search()
metody searchClient
. Prvním parametrem je hledaný text a druhý parametr určuje možnosti hledání.
První dotaz vyhledá *
, což je ekvivalent pro hledání všeho a vybere tři pole v indexu. Osvědčeným postupem je pouze select
pole, která potřebujete, protože stažení nepotřebných dat může do dotazů přidat latenci.
U searchOptions
tohoto dotazu je includeTotalCount
také nastavena hodnota true
, která vrátí počet nalezených odpovídajících výsledků.
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
}
Zbývající níže uvedené dotazy by se také měly přidat do sendQueries()
funkce. Jsou zde odděleny pro čitelnost.
V dalším dotazu určíme hledaný termín "wifi"
a zahrneme také filtr, který vrátí pouze výsledky, ve kterých je stav roven 'FL'
. Výsledky jsou také objednány hotelovým hotelem 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ále je hledání omezeno na jedno prohledávatelné pole pomocí parametru searchFields
. Tento přístup je skvělou možností, jak zefektivnit dotaz, pokud víte, že vás zajímají jenom shody v určitých polích.
console.log('Query #3 - Limit searchFields:');
searchOptions = {
select: ["HotelId", "HotelName", "Rating"],
searchFields: ["HotelName"]
};
searchResults = await searchClient.search("sublime cliff", searchOptions);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
console.log();
Další běžnou možností zahrnutí do dotazu je facets
. Omezující vlastnosti umožňují vytvářet filtry v uživatelském rozhraní, aby uživatelé snadno věděli, na jaké hodnoty můžou filtrovat.
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)}`);
}
Poslední dotaz používá getDocument()
metodu searchClient
. Díky tomu můžete dokument efektivně načíst podle jeho klíče.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument(key='3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Spuštění ukázky
Spusťte program pomocí node index.js
příkazu . Kromě předchozích kroků se teď budou dotazy odesílat a výsledky zapsané do konzoly.
Vytvořte Node.js aplikaci pomocí knihovny @azure/search-documents k vytvoření, načtení a dotazování indexu vyhledávání. Případně si můžete zdrojový kód stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.
Nastavení prostředí
K vytvoření tohoto rychlého startu jsme použili následující nástroje.
Vytvoření projektu
Spusťte Visual Studio Code.
Otevřete paletu příkazů Ctrl+Shift+P a otevřete integrovaný terminál.
Vytvořte vývojový adresář a pojmenujte ho quickstart
:
mkdir quickstart
cd quickstart
Inicializace prázdného projektu pomocí npm spuštěním následujícího příkazu. Pokud chcete projekt plně inicializovat, stiskněte několikrát klávesu Enter a přijměte výchozí hodnoty s výjimkou licence, kterou byste měli nastavit na MIT.
npm init
Nainstalujte @azure/search-documents
sadu JavaScript/TypeScript SDK pro Azure AI Search.
npm install @azure/search-documents
Nainstalujte dotenv
, která se používá k importu proměnných prostředí, jako je název vyhledávací služby a klíč rozhraní API.
npm install dotenv
Ověřte, že jste projekty a její závislosti nakonfigurovali tak, že zkontrolujete, že váš soubor package.json vypadá podobně jako v následujícím kódu 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"
}
}
Vytvořte soubor .env pro uložení parametrů vyhledávací služby:
SEARCH_API_KEY=<YOUR-SEARCH-ADMIN-API-KEY>
SEARCH_API_ENDPOINT=<YOUR-SEARCH-SERVICE-URL>
<search-service-name>
Nahraďte hodnotu názvem vyhledávací služby. Nahraďte <search-admin-key>
hodnotou klíče, kterou jste si poznamenali dříve.
Vytvoření souboru index.ts
Dále vytvoříme soubor index.ts , což je hlavní soubor, který bude hostovat náš kód.
V horní části tohoto souboru naimportujeme knihovnu @azure/search-documents
:
import {
AzureKeyCredential,
ComplexField,
odata,
SearchClient,
SearchFieldArray,
SearchIndex,
SearchIndexClient,
SearchSuggester,
SimpleField
} from "@azure/search-documents";
Dále musíme vyžadovat dotenv
, aby balíček četl v parametrech ze souboru .env následujícím způsobem:
// 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 || "";
S našimi importy a proměnnými prostředí jsme připraveni definovat hlavní funkci.
Většina funkcí v sadě SDK je asynchronní, takže vytvoříme naši hlavní funkci async
. Zahrneme main().catch()
také pod hlavní funkci, která zachytí a zapíše všechny zjištěné chyby:
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);
});
S tím jsme připraveni vytvořit index.
Vytvoření indexu
Vytvořte soubor hotels_quickstart_index.json. Tento soubor definuje, jak Azure AI Search funguje s dokumenty, které načtete v dalším kroku. Každé pole bude identifikováno name
a bude mít zadané type
. Každé pole má také řadu atributů indexu, které určují, jestli může Azure AI Search prohledávat, filtrovat, řadit a omezující vlastnosti pole. Většina polí je jednoduchých datových typů, ale některé, jako AddressType
jsou složité typy, které umožňují vytvářet bohaté datové struktury v indexu. Další informace opodporovaných
Přidejte následující obsah, který hotels_quickstart_index.json nebo soubor stáhnete.
{
"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"
]
}
]
}
S definicí indexu chceme importovat hotels_quickstart_index.json v horní části index.ts , aby hlavní funkce přistupovala k definici indexu.
// 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;
V rámci hlavní funkce pak vytvoříme , SearchIndexClient
která se použije k vytváření a správě indexů pro Azure AI Search.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Dále chceme odstranit index, pokud už existuje. Tato operace je běžným postupem pro testovací nebo ukázkový kód.
Provedeme to tak, že definujeme jednoduchou funkci, která se pokusí odstranit index.
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.');
}
}
Ke spuštění funkce extrahujeme název indexu z definice indexu indexClient
deleteIndexIfExists()
a předáme indexName
funkci spolu s funkcí.
// 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);
Potom jsme připraveni vytvořit index pomocí createIndex()
metody.
console.log('Creating index...');
let index = await indexClient.createIndex(hotelIndexDefinition);
console.log(`Index named ${index.name} has been created.`);
Spuštění ukázky
V tuto chvíli jste připraveni sestavit a spustit ukázku. Pomocí okna terminálu spusťte následující příkazy pro sestavení zdroje a tsc
potom spusťte zdroj s node
:
tsc
node index.js
Pokud jste si stáhli zdrojový kód a ještě jste nenainstalovali požadované balíčky, spusťte npm install
nejprve.
Měla by se zobrazit řada zpráv popisujících akce prováděné programem.
Na webu Azure Portal otevřete přehled vaší vyhledávací služby. Vyberte kartu Indexy. Měli byste vidět něco jako v následujícím příkladu:
V dalším kroku přidáte data do indexu.
Nahrání dokumentů
Ve službě Azure AI Search jsou dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Tato data můžete odeslat do indexu nebo použít indexer. V tomto případě naprogramujeme dokumenty do indexu.
Vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo jako v této ukázce dokumenty JSON na disku. Můžete si stáhnout hotels.json nebo vytvořit vlastní soubor hotels.json s následujícím obsahem:
{
"value": [
{
"HotelId": "1",
"HotelName": "Secret Point Motel",
"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": "Twin Dome Motel",
"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": "Triple 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 Cliff Hotel",
"Description": "Sublime Cliff 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 Cliff is part of a lovingly restored 1800 palace.",
"Description_fr": "Le sublime Cliff 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 Cliff 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"
}
}
]
}
Podobně jako u indexDefinition je potřeba importovat hotels.json
také do horní části index.ts , aby k datům bylo možné přistupovat v hlavní funkci.
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"];
Abychom mohli data indexovat do vyhledávacího indexu, musíme teď vytvořit .SearchClient
SearchIndexClient
Zatímco se používá k vytvoření a správě indexu, SearchClient
slouží k nahrání dokumentů a dotazování indexu.
Existují dva způsoby, jak vytvořit SearchClient
. První možností je vytvořit úplně SearchClient
od začátku:
const searchClient = new SearchClient<Hotel>(endpoint, indexName, new AzureKeyCredential(apiKey));
Alternativně můžete použít getSearchClient()
metodu SearchIndexClient
vytvoření SearchClient
:
const searchClient = indexClient.getSearchClient<Hotel>(indexName);
Teď, když je klient definovaný, nahrajte dokumenty do indexu vyhledávání. V tomto případě použijeme metodu mergeOrUploadDocuments()
, která nahraje dokumenty nebo je sloučí s existujícím dokumentem, pokud už existuje dokument se stejným klíčem. Pak zkontrolujte, jestli operace proběhla úspěšně, protože existuje alespoň první dokument.
console.log("Uploading documents...");
const indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotels);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Spusťte program znovu pomocí tsc && node index.js
příkazu . Měli byste vidět trochu odlišnou sadu zpráv od zpráv, které jste viděli v kroku 1. Tentokrát existuje index a měla by se zobrazit zpráva o jejím odstranění, než aplikace vytvoří nový index a publikuje do něj data.
Než spustíme dotazy v dalším kroku, definujte funkci, která má program čekat na jednu sekundu. To se provádí jenom pro účely testování/ukázky, aby se zajistilo dokončení indexování a dostupnost dokumentů v indexu pro naše dotazy.
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Pokud chcete, aby program čekal na jednu sekundu, zavolejte funkci, jak je znázorněno sleep
níže:
sleep(1000);
Prohledání indexu
Když jste vytvořili index a nahráli jste dokumenty, můžete do indexu odesílat dotazy. V této části pošleme do indexu vyhledávání pět různých dotazů, abychom vám ukázali různé části funkcí dotazů, které jsou vám k dispozici.
Dotazy jsou napsané ve sendQueries()
funkci, kterou budeme volat v hlavní funkci následujícím způsobem:
await sendQueries(searchClient);
Dotazy se odesílají pomocí search()
metody searchClient
. Prvním parametrem je hledaný text a druhý parametr určuje možnosti hledání.
První dotaz vyhledá *
, což je ekvivalent pro hledání všeho a vybere tři pole v indexu. Osvědčeným postupem je pouze select
pole, která potřebujete, protože stažení nepotřebných dat může do dotazů přidat latenci.
U searchOptions
tohoto dotazu je includeTotalCount
také nastavena hodnota true
, která vrátí počet nalezených odpovídajících výsledků.
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
}
Zbývající níže uvedené dotazy by se také měly přidat do sendQueries()
funkce. Jsou zde odděleny pro čitelnost.
V dalším dotazu určíme hledaný termín "wifi"
a zahrneme také filtr, který vrátí pouze výsledky, ve kterých je stav roven 'FL'
. Výsledky jsou také objednány hotelovým hotelem 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ále je hledání omezeno na jedno prohledávatelné pole pomocí parametru searchFields
. Tento přístup je skvělou možností, jak zefektivnit dotaz, pokud víte, že vás zajímají jenom shody v určitých polích.
console.log('Query #3 - limit searchFields:');
const searchOptions3 = {
select: selectFields,
searchFields: ["HotelName"] as const
};
searchResults = await searchClient.search("sublime cliff", searchOptions3);
for await (const result of searchResults.results) {
console.log(`${JSON.stringify(result.document)}`);
}
Další běžnou možností zahrnutí do dotazu je facets
. Fasety umožňují poskytovat samoobslužné přechody k podrobnostem z výsledků v uživatelském rozhraní. Výsledky omezujících vlastností se dají v podokně výsledků převést na zaškrtávací políčka.
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)}`);
}
Poslední dotaz používá getDocument()
metodu searchClient
. Díky tomu můžete dokument efektivně načíst podle jeho klíče.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument('3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Opětovné spuštění ukázky
Sestavte a spusťte program pomocí tsc && node index.ts
příkazu . Kromě předchozích kroků se teď budou dotazy odesílat a výsledky zapsané do konzoly.
Pokud pracujete s vlastním předplatným, je vhodné vždy na konci projektu zkontrolovat, jestli budete vytvořené prostředky ještě potřebovat. Prostředky, které necháte spuštěné, vás stojí peníze. Prostředky můžete odstraňovat jednotlivě nebo můžete odstranit skupinu prostředků, a odstranit tak celou sadu prostředků najednou.
Pokud používáte bezplatnou službu, mějte na paměti, že jste omezeni na tři indexy, indexery a zdroje dat. Jednotlivé položky na portálu můžete odstranit, abyste zůstali pod limitem.
V tomto rychlém startu jste prošli sadou úloh, kterými jste vytvořili index, načetli ho s dokumenty a spustili dotazy. V různých fázích jsme vzali zástupce, abychom zjednodušili kód pro čitelnost a porozumění. Teď, když znáte základní koncepty, vyzkoušejte kurz, který volá rozhraní API služby Azure AI Search ve webové aplikaci.