Oktatóanyag: Indexelés optimalizálása a leküldéses API használatával
Az Azure AI Search két alapvető módszert támogat az adatok keresési indexbe való importálásához: az adatokat programozott módon kell leküldni az indexbe, vagy lekérni az adatokat úgy, hogy egy Azure AI Search-indexelőt egy támogatott adatforrásra mutat.
Ez az oktatóanyag bemutatja, hogyan indexelheti hatékonyan az adatokat a leküldéses modell használatával kérelmek kötegelésével és exponenciális visszalépési újrapróbálkozási stratégia használatával. Letöltheti és futtathatja a mintaalkalmazást. Ez a cikk az alkalmazás főbb szempontjait és az adatok indexelése során figyelembe veendő tényezőket ismerteti.
Ez az oktatóanyag a .NET-hez készült Azure SDK C# és Azure.Search.Documents könyvtárát használja a következő feladatok végrehajtásához:
- Index létrehozása
- Különböző kötegméretek tesztelése a leghatékonyabb méret meghatározásához
- Index kötegek aszinkron módon
- Több szál használata az indexelési sebesség növeléséhez
- Exponenciális backoff újrapróbálkozási stratégia használata a sikertelen dokumentumok újrapróbálkozásához
Előfeltételek
Az oktatóanyaghoz az alábbi szolgáltatásokra és eszközökre van szükség.
Azure-előfizetés. Ha még nincs fiókja, hozzon létre egy ingyenes fiókot.
Visual Studio, bármilyen kiadás. A mintakódot és az utasításokat az ingyenes közösségi kiadásban teszteltük.
Fájlok letöltése
Az oktatóanyag forráskódja az Azure-Samples/azure-search-dotnet-scale GitHub-adattár optimize-data-indexing/v11 mappájában található.
Fő szempontok
Az indexelési sebességet befolyásoló tényezők a következőkben láthatók. További információ: Nagy adathalmazok indexelése.
- Szolgáltatási szint és partíciók/replikák száma: A partíciók hozzáadása vagy a réteg frissítése növeli az indexelési sebességet.
- Indexséma összetettsége: A mezők és mezőtulajdonságok hozzáadása csökkenti az indexelési sebességet. A kisebb indexek gyorsabban indexelnek.
- Kötegméret: Az optimális kötegméret az indexsémától és az adatkészlettől függően változik.
- Szálak/feldolgozók száma: Egyetlen szál nem használja ki teljes mértékben az indexelési sebesség előnyeit.
- Újrapróbálkozási stratégia: Az optimális indexelés ajánlott eljárása az exponenciális visszalépési újrapróbálkozási stratégia.
- Hálózati adatátvitel sebessége: Az adatátvitel sebessége korlátozó tényező lehet. Indexelje az adatokat az Azure-környezetből az adatátviteli sebesség növelése érdekében.
1. lépés: Azure AI-Search szolgáltatás létrehozása
Az oktatóanyag elvégzéséhez szüksége lesz egy Azure AI-Search szolgáltatás, amelyet létrehozhat az Azure Portalon, vagy megkereshet egy meglévő szolgáltatást az aktuális előfizetése alatt. Javasoljuk, hogy ugyanazt a szintet használja, amelyet éles környezetben szeretne használni, hogy pontosan tesztelhesse és optimalizálhassa az indexelési sebességet.
Rendszergazdai kulcs és URL-cím lekérése az Azure AI Search szolgáltatáshoz
Ez az oktatóanyag kulcsalapú hitelesítést használ. Másolja a rendszergazdai API-kulcsot a appsettings.json fájlba való beillesztéshez.
Jelentkezzen be az Azure Portalra. Kérje le a végpont URL-címét a keresési szolgáltatás áttekintési oldaláról. A végpontok például a következőképpen nézhetnek ki:
https://mydemo.search.windows.net
.A Beállításkulcsok> területen szerezze be a szolgáltatás teljes jogosultságainak rendszergazdai kulcsát. Két felcserélhető rendszergazdai kulcs áll rendelkezésre az üzletmenet folytonossága érdekében, ha át kell gördítenie egyet. Az elsődleges vagy a másodlagos kulcsot használhatja objektumok hozzáadására, módosítására és törlésére vonatkozó kérelmekhez.
2. lépés: A környezet beállítása
Indítsa el a Visual Studiót, és nyissa meg a OptimizeDataIndexing.sln.
A Megoldáskezelő nyissa meg a appsettings.json a szolgáltatás kapcsolati adatainak megadásához.
{
"SearchServiceUri": "https://{service-name}.search.windows.net",
"SearchServiceAdminApiKey": "",
"SearchIndexName": "optimize-indexing"
}
3. lépés: A kód megismerése
A appsettings.json frissítése után az OptimizeDataIndexing.sln mintaprogramjának készen kell állnia a létrehozásra és a futtatásra.
Ez a kód a rövid útmutató C# szakaszából származik: Teljes szöveges keresés az Azure SDK-k használatával. Ebben a cikkben részletesebb információkat talál a .NET SDK használatának alapjairól.
Ez az egyszerű C#/.NET-konzolalkalmazás a következő feladatokat hajtja végre:
- Új indexet hoz létre a C#
Hotel
osztály adatstruktúrája alapján (amely azAddress
osztályra is hivatkozik) - Különböző kötegméretek tesztelése a leghatékonyabb méret meghatározásához
- Az adatokat aszinkron módon indexeli
- Több szál használata az indexelési sebesség növeléséhez
- Exponenciális backoff újrapróbálkozási stratégia használata a sikertelen elemek újrapróbálkozásához
A program futtatása előtt szánjon egy percet a minta kódjának és indexdefinícióinak tanulmányozására. A megfelelő kód több fájlban található:
- Hotel.cs és Address.cs az indexet meghatározó sémát tartalmazzák
- DataGenerator.cs egy egyszerű osztályt tartalmaz, amely megkönnyíti a nagy mennyiségű szállodai adat létrehozását
- ExponentialBackoff.cs tartalmaz kódot az indexelési folyamat optimalizálásához a jelen cikkben leírtak szerint
- Program.cs olyan függvényeket tartalmaz, amelyek létrehozzák és törlik az Azure AI Search-indexet, indexelik az adatkötegeket, és különböző kötegméreteket tesztelnek
Az index létrehozása
Ez a mintaprogram az Azure SDK for .NET használatával definiál és hoz létre egy Azure AI Search-indexet. Az osztály előnyeit kihasználva FieldBuilder
indexstruktúrát hozhat létre egy C#-adatmodell-osztályból.
Az adatmodellt az Hotel
osztály határozza meg, amely az Address
osztályra mutató hivatkozásokat is tartalmaz. A FieldBuilder több osztálydefiníción keresztül részletezi az index összetett adatstruktúráját. A metaadatcímkék az egyes mezők attribútumainak meghatározására szolgálnak, például azt, hogy kereshető vagy rendezhető-e.
A Hotel.cs fájl alábbi kódrészletei bemutatják, hogyan adható meg egyetlen mező és egy másik adatmodell-osztályra mutató hivatkozás.
. . .
[SearchableField(IsSortable = true)]
public string HotelName { get; set; }
. . .
public Address Address { get; set; }
. . .
A Program.cs fájlban az index a metódus által létrehozott névvel és mezőgyűjteménysel van definiálva, majd a FieldBuilder.Build(typeof(Hotel))
következőképpen jön létre:
private static async Task CreateIndexAsync(string indexName, SearchIndexClient indexClient)
{
// Create a new search index structure that matches the properties of the Hotel class.
// The Address class is referenced from the Hotel class. The FieldBuilder
// will enumerate these to create a complex data structure for the index.
FieldBuilder builder = new FieldBuilder();
var definition = new SearchIndex(indexName, builder.Build(typeof(Hotel)));
await indexClient.CreateIndexAsync(definition);
}
Adatok generálása
A DataGenerator.cs fájlban egy egyszerű osztályt implementál a teszteléshez szükséges adatok létrehozásához. Ennek az osztálynak az egyetlen célja, hogy megkönnyítse nagyszámú, egyedi azonosítóval rendelkező dokumentum létrehozásának megkönnyítését az indexeléshez.
100 000 egyedi azonosítóval rendelkező szálloda listájának lekéréséhez futtassa a következő kódsorokat:
long numDocuments = 100000;
DataGenerator dg = new DataGenerator();
List<Hotel> hotels = dg.GetHotels(numDocuments, "large");
Ebben a mintában két méretben lehet tesztelni a szállodákat: kicsi és nagy.
Az index sémája hatással van az indexelési sebességre. Ezért érdemes átalakítani ezt az osztályt úgy, hogy az oktatóanyag futtatása után a legjobban megfelelő adatokat hozzon létre a kívánt indexsémának megfelelően.
4. lépés: Kötegméretek tesztelése
Az Azure AI Search a következő API-kat támogatja egy vagy több dokumentum indexbe való betöltéséhez:
A dokumentumok kötegekben való indexelése jelentősen javítja az indexelési teljesítményt. Ezek a kötegek legfeljebb 1000 dokumentumból, kötegenként akár 16 MB-ból is lehetnek.
Az indexelési sebesség optimalizálásának kulcsfontosságú összetevője az adatok optimális kötegméretének meghatározása. Az optimális kötegméretet befolyásoló két elsődleges tényező:
- Az index sémája
- Az adatok mérete
Mivel az optimális kötegméret az indextől és az adatoktól függ, a legjobb módszer a különböző kötegméretek tesztelése, hogy megállapítsa, mi okozza a forgatókönyv leggyorsabb indexelési sebességét.
Az alábbi függvény egy egyszerű módszert mutat be a kötegméretek tesztelésére.
public static async Task TestBatchSizesAsync(SearchClient searchClient, int min = 100, int max = 1000, int step = 100, int numTries = 3)
{
DataGenerator dg = new DataGenerator();
Console.WriteLine("Batch Size \t Size in MB \t MB / Doc \t Time (ms) \t MB / Second");
for (int numDocs = min; numDocs <= max; numDocs += step)
{
List<TimeSpan> durations = new List<TimeSpan>();
double sizeInMb = 0.0;
for (int x = 0; x < numTries; x++)
{
List<Hotel> hotels = dg.GetHotels(numDocs, "large");
DateTime startTime = DateTime.Now;
await UploadDocumentsAsync(searchClient, hotels).ConfigureAwait(false);
DateTime endTime = DateTime.Now;
durations.Add(endTime - startTime);
sizeInMb = EstimateObjectSize(hotels);
}
var avgDuration = durations.Average(timeSpan => timeSpan.TotalMilliseconds);
var avgDurationInSeconds = avgDuration / 1000;
var mbPerSecond = sizeInMb / avgDurationInSeconds;
Console.WriteLine("{0} \t\t {1} \t\t {2} \t\t {3} \t {4}", numDocs, Math.Round(sizeInMb, 3), Math.Round(sizeInMb / numDocs, 3), Math.Round(avgDuration, 3), Math.Round(mbPerSecond, 3));
// Pausing 2 seconds to let the search service catch its breath
Thread.Sleep(2000);
}
Console.WriteLine();
}
Mivel nem minden dokumentum mérete azonos (bár ebben a mintában szerepelnek), megbecsüljük a keresési szolgáltatásnak küldött adatok méretét. Ezt a következő függvénnyel teheti meg, amely először json-ra konvertálja az objektumot, majd bájtokban határozza meg a méretét. Ez a technika lehetővé teszi, hogy megállapítsuk, mely kötegméretek a leghatékonyabbak MB/s indexelési sebesség szempontjából.
// Returns size of object in MB
public static double EstimateObjectSize(object data)
{
// converting object to byte[] to determine the size of the data
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
byte[] Array;
// converting data to json for more accurate sizing
var json = JsonSerializer.Serialize(data);
bf.Serialize(ms, json);
Array = ms.ToArray();
// converting from bytes to megabytes
double sizeInMb = (double)Array.Length / 1000000;
return sizeInMb;
}
A függvényhez meg kell adni az SearchClient
egyes kötegméretekhez tesztelni kívánt próbálkozások számát. Mivel az egyes kötegek indexelési idejének variabilitása lehet, alapértelmezés szerint háromszor próbálkozzon az egyes kötegekkel, hogy az eredmények statisztikailag szignifikánsabbak legyenek.
await TestBatchSizesAsync(searchClient, numTries: 3);
A függvény futtatásakor a konzolon az alábbi példához hasonló kimenetnek kell megjelennie:
Azonosítsa a leghatékonyabb kötegméretet, majd használja ezt a kötegméretet az oktatóanyag következő lépésében. Előfordulhat, hogy a plató MB/s-ban különböző kötegméretekben jelenik meg.
5. lépés: Az adatok indexelése
Most, hogy azonosította a használni kívánt kötegméretet, a következő lépés az adatok indexelésének megkezdése. Az adatok hatékony indexeléséhez ez a minta:
- több szálat/feldolgozót használ
- exponenciális backoff újrapróbálkozási stratégiát implementál
Bontsa ki a 41–49. sorokat, majd futtassa újra a programot. Ebben a futtatásban a minta legfeljebb 100 000 dokumentumköteget hoz létre és küld el, ha a paraméterek módosítása nélkül futtatja a kódot.
Több szál/feldolgozó használata
Az Azure AI Search indexelési sebességének teljes kihasználásához használjon több szálat a kötegindexelési kérések egyidejű elküldéséhez a szolgáltatásnak.
A korábban említett főbb szempontok közül több is befolyásolhatja a szálak optimális számát. Ezt a mintát módosíthatja, és különböző szálszámokkal tesztelheti a forgatókönyv optimális szálszámának meghatározásához. Mindaddig azonban, amíg több szál fut egyszerre, képesnek kell lennie arra, hogy kihasználja a hatékonyságnövekedés nagy részét.
A keresési szolgáltatásra irányuló kérések felfuttatása során HTTP-állapotkódok jelenhetnek meg, amelyek azt jelzik, hogy a kérés nem sikerült teljes mértékben. Az indexelés során két gyakori HTTP-állapotkód:
- 503 Szolgáltatás nem érhető el: Ez a hiba azt jelenti, hogy a rendszer nagy terhelés alatt áll, és a kérés jelenleg nem dolgozható fel.
- 207 Többállapotú: Ez a hiba azt jelenti, hogy egyes dokumentumok sikeresek voltak, de legalább egy sikertelen volt.
Exponenciális backoff újrapróbálkozási stratégia implementálása
Ha hiba történik, a kéréseket exponenciális visszalépési újrapróbálkozási stratégiával kell újrapróbálkoznia.
Az Azure AI Search .NET SDK-jában automatikusan újrapróbálkoznak az 503s és más sikertelen kérések, de a 207-ek újrapróbálkozásához saját logikát kell implementálnia. A nyílt forráskódú eszközök, például a Polly hasznosak lehetnek az újrapróbálkozás stratégiájában.
Ebben a mintában saját exponenciális backoff újrapróbálkozási stratégiát valósítunk meg. Először definiálunk néhány változót, köztük egy maxRetryAttempts
sikertelen kérés kezdeti delay
értékét:
// Create batch of documents for indexing
var batch = IndexDocumentsBatch.Upload(hotels);
// Create an object to hold the result
IndexDocumentsResult result = null;
// Define parameters for exponential backoff
int attempts = 0;
TimeSpan delay = delay = TimeSpan.FromSeconds(2);
int maxRetryAttempts = 5;
Az indexelési művelet eredményeit a változó IndexDocumentResult result
tárolja. Ez a változó azért fontos, mert lehetővé teszi annak ellenőrzését, hogy a kötegben lévő dokumentumok sikertelenek-e, ahogy az alábbi példában is látható. Részleges hiba esetén egy új köteg jön létre a sikertelen dokumentumok azonosítója alapján.
RequestFailedException
kivételeket is ki kell fogni, mivel azt jelzik, hogy a kérés teljesen meghiúsult, és újra kell próbálkozni.
// Implement exponential backoff
do
{
try
{
attempts++;
result = await searchClient.IndexDocumentsAsync(batch).ConfigureAwait(false);
var failedDocuments = result.Results.Where(r => r.Succeeded != true).ToList();
// handle partial failure
if (failedDocuments.Count > 0)
{
if (attempts == maxRetryAttempts)
{
Console.WriteLine("[MAX RETRIES HIT] - Giving up on the batch starting at {0}", id);
break;
}
else
{
Console.WriteLine("[Batch starting at doc {0} had partial failure]", id);
Console.WriteLine("[Retrying {0} failed documents] \n", failedDocuments.Count);
// creating a batch of failed documents to retry
var failedDocumentKeys = failedDocuments.Select(doc => doc.Key).ToList();
hotels = hotels.Where(h => failedDocumentKeys.Contains(h.HotelId)).ToList();
batch = IndexDocumentsBatch.Upload(hotels);
Task.Delay(delay).Wait();
delay = delay * 2;
continue;
}
}
return result;
}
catch (RequestFailedException ex)
{
Console.WriteLine("[Batch starting at doc {0} failed]", id);
Console.WriteLine("[Retrying entire batch] \n");
if (attempts == maxRetryAttempts)
{
Console.WriteLine("[MAX RETRIES HIT] - Giving up on the batch starting at {0}", id);
break;
}
Task.Delay(delay).Wait();
delay = delay * 2;
}
} while (true);
Innen csomagolja be az exponenciális visszalépési kódot egy függvénybe, hogy könnyen meghívható legyen.
Ezután létrejön egy másik függvény az aktív szálak kezeléséhez. Az egyszerűség kedvéért ez a függvény nem szerepel itt, de megtalálható a ExponentialBackoff.cs. A függvény a következő paranccsal hívható meg, ahol hotels
a feltölteni kívánt adatok, 1000
a köteg mérete és 8
az egyidejű szálak száma:
await ExponentialBackoff.IndexData(indexClient, hotels, 1000, 8);
A függvény futtatásakor egy kimenetnek kell megjelennie:
Ha egy dokumentumköteg meghibásodik, a rendszer a hibát jelző hibát nyomtatja ki, és a köteg újrapróbálkozás alatt áll:
[Batch starting at doc 6000 had partial failure]
[Retrying 560 failed documents]
A függvény futtatása után ellenőrizheti, hogy az összes dokumentum hozzá lett-e adva az indexhez.
6. lépés: Az index felfedezése
A feltöltött keresési indexet azután is felfedezheti, hogy a program programozott módon vagy a Portál Keresőböngészőjének használatával futott.
Programozott módon
Az indexben lévő dokumentumok számának ellenőrzésére két fő lehetőség áll rendelkezésre: a Dokumentumok száma API és az Indexstatisztikák lekérése API. Mindkét elérési úthoz időre van szükség a feldolgozáshoz, ezért ne aggódjon, ha a visszaadott dokumentumok száma kezdetben alacsonyabb a vártnál.
Dokumentumok száma
A Dokumentumok száma művelet lekéri a keresési indexben lévő dokumentumok számát:
long indexDocCount = await searchClient.GetDocumentCountAsync();
Indexstatisztikák lekérése
Az Indexstatisztikák lekérése művelet az aktuális index dokumentumszámát és a tárterület használatát adja vissza. Az indexstatisztikák frissítése hosszabb időt vesz igénybe, mint a dokumentumok száma.
var indexStats = await indexClient.GetIndexStatisticsAsync(indexName);
Azure Portal
Az Azure Portal bal oldali navigációs paneljén keresse meg az optimalizálási indexet az Indexek listában.
A dokumentumszám és a tárterület mérete az Indexstatisztikai API lekérésén alapul, és a frissítés eltarthat néhány percig.
Alaphelyzetbe állítás és ismételt futtatás
A fejlesztés korai kísérleti fázisaiban a tervezési iteráció legpraktikusabb módszere az objektumok törlése az Azure AI Searchből, és a kód újraépítésének engedélyezése. Az erőforrásnevek egyediek. Egy objektum törlése révén újból létrehozhatja azt ugyanazzal a névvel.
Az oktatóanyag mintakódja ellenőrzi a meglévő indexeket, és törli őket, hogy újrafuttassa a kódot.
A portálon indexeket is törölhet.
Az erőforrások eltávolítása
Ha a saját előfizetésében dolgozik, a projekt végén célszerű eltávolítania a már nem szükséges erőforrásokat. A továbbra is futó erőforrások költségekkel járhatnak. Az erőforrásokat törölheti egyesével, vagy az erőforráscsoport törlésével eltávolíthatja a benne lévő összes erőforrást is.
A portálon a bal oldali navigációs panel Minden erőforrás vagy Erőforráscsoport hivatkozásával kereshet és kezelhet erőforrásokat.
Következő lépés
A nagy mennyiségű adatok indexelésével kapcsolatos további információkért próbálja ki az alábbi oktatóanyagot.