Öğretici: Gönderme API’siyle dizin oluşturmayı iyileştirme

Azure AI Search, verileri arama dizinine aktarmak için iki temel yaklaşımı destekler: verilerinizi program aracılığıyla dizine gönderme veya desteklenen bir veri kaynağına Azure AI Search dizin oluşturucusunun verileri çekmesini sağlama.

Bu öğreticide, istekleri toplu işleyerek ve üstel geri alma yeniden deneme stratejisi kullanarak gönderim modelini kullanarak verilerin nasıl verimli bir şekilde dizine alındığı açıklanmaktadır. Örnek uygulamayı indirip çalıştırabilirsiniz. Bu makalede, uygulamanın önemli yönleri ve verilerin dizinini oluştururken dikkate alınması gereken faktörler açıklanmaktadır.

Bu öğreticide aşağıdaki görevleri gerçekleştirmek için .NET için Azure SDK'sından C# ve Azure.Search.Documents kitaplığı kullanılır:

  • Dizin oluşturma
  • En verimli boyutu belirlemek için çeşitli toplu iş boyutlarını test etme
  • Toplu işleri zaman uyumsuz olarak dizine ekleme
  • Dizin oluşturma hızlarını artırmak için birden çok iş parçacığı kullanma
  • Başarısız belgeleri yeniden denemek için üstel geri alma yeniden deneme stratejisi kullanma

Azure aboneliğiniz yoksa başlamadan önce ücretsiz bir hesap oluşturun.

Önkoşullar

Bu öğretici için aşağıdaki hizmetler ve araçlar gereklidir.

Dosyaları indirme

Bu öğreticinin kaynak kodu Azure-Samples/azure-search-dotnet-samples GitHub deposundaki optimize-data-indexing/v11 klasöründedir.

Dikkat edilmesi gereken temel konular

Dizin oluşturma hızlarını etkileyen faktörler aşağıda listelenmiştir. Büyük veri kümelerini dizinle bölümünden daha fazla bilgi edinebilirsiniz.

  • Hizmet katmanı ve bölüm/çoğaltma sayısı - Bölüm ekleme veya katmanınızı yükseltme dizin oluşturma hızlarını artırır.
  • Dizin şeması karmaşıklığı - Alan ve alan özellikleri eklemek dizin oluşturma hızlarını düşürür. Daha küçük dizinleri dizine almak daha hızlıdır.
  • Toplu iş boyutu - En uygun toplu iş boyutu, dizin şemanıza ve veri kümenize göre değişir.
  • İş parçacığı/çalışan sayısı - Tek bir iş parçacığı dizin oluşturma hızlarından tam olarak yararlanamaz.
  • Yeniden deneme stratejisi - Üstel geri alma yeniden deneme stratejisi, en iyi dizin oluşturma için en iyi yöntemdir.
  • Ağ veri aktarım hızları - Veri aktarım hızları sınırlayıcı bir faktör olabilir. Veri aktarım hızlarını artırmak için Azure ortamınızdan verileri dizine alın.

1 - Azure AI Arama hizmeti oluşturma

Bu öğreticiyi tamamlamak için portalda oluşturabileceğiniz bir Azure AI Arama hizmeti gerekir. Dizin oluşturma hızlarını doğru bir şekilde test edebilmeniz ve iyileştirebilmeniz için üretimde kullanmayı planladığınız katmanı kullanmanızı öneririz.

Bu öğreticide anahtar tabanlı kimlik doğrulaması kullanılır. appsettings.json dosyasına yapıştırmak için bir yönetici API anahtarı kopyalayın.

  1. Azure portalında oturum açın ve arama hizmetine Genel Bakış sayfanızda URL'yi alın. Örnek uç nokta https://mydemo.search.windows.net şeklinde görünebilir.

  2. Ayarlar> Keys'te, hizmet üzerinde tam haklar için bir yönetici anahtarı alın. Bir tane yuvarlamanız gerektiğinde iş sürekliliği için sağlanan iki değiştirilebilir yönetici anahtarı vardır. Nesneleri ekleme, değiştirme ve silme isteklerinde birincil veya ikincil anahtarı kullanabilirsiniz.

    Get an HTTP endpoint and access key

2 - Ortamınızı ayarlama

  1. Visual Studio'yu başlatın ve OptimizeDataIndexing.sln açın.
  2. Çözüm Gezgini'da, bağlantı bilgilerini sağlamak için appsettings.json açın.
{
  "SearchServiceUri": "https://{service-name}.search.windows.net",
  "SearchServiceAdminApiKey": "",
  "SearchIndexName": "optimize-indexing"
}

3 - Kodu keşfetme

appsettings.json güncelleştirdikten sonra, OptimizeDataIndexing.sln'daki örnek program derlemeye ve çalıştırmaya hazır olmalıdır.

Bu kod, Hızlı Başlangıç: Azure SDK'larını kullanarak tam metin araması bölümünün C# bölümünden türetilmiştir. Bu makalede .NET SDK ile çalışmanın temelleri hakkında daha ayrıntılı bilgi bulabilirsiniz.

Bu basit C#/.NET konsol uygulaması aşağıdaki görevleri gerçekleştirir:

  • C# Hotel sınıfının (Address sınıfına da başvurur) veri yapısını temel alan yeni bir dizin oluşturur.
  • En verimli boyutu belirlemek için çeşitli toplu iş boyutlarını test eder
  • Verileri zaman uyumsuz olarak dizinler
    • Dizin oluşturma hızlarını artırmak için birden çok iş parçacığı kullanma
    • Başarısız öğeleri yeniden denemek için üstel geri alma yeniden deneme stratejisi kullanma

Programı çalıştırmadan önce kodu ve bu örneğin dizin tanımlarını incelemek için bir dakika bekleyin. İlgili kod birkaç dosyadadır:

  • Hotel.cs ve Address.cs dizini tanımlayan şemayı içerir
  • DataGenerator.cs, büyük miktarlarda otel verilerini oluşturmayı kolaylaştıran basit bir sınıf içerir
  • ExponentialBackoff.cs, bu makalede açıklandığı gibi dizin oluşturma işlemini iyileştirmeye yönelik kod içerir
  • Program.cs, Azure AI Search dizinini oluşturup silip silebilen, veri toplu işlemlerini dizinleyen ve farklı toplu iş boyutlarını test eden işlevler içerir

Dizin oluşturma

Bu örnek program, bir Azure AI Search dizini tanımlamak ve oluşturmak için .NET için Azure SDK'sını kullanır. C# veri modeli sınıfından FieldBuilder dizin yapısı oluşturmak için sınıfından yararlanır.

Veri modeli, Address sınıfına başvurular da içeren Hotel sınıfı tarafından tanımlanır. FieldBuilder, dizin için karmaşık bir veri yapısı oluşturmak üzere birden çok sınıf tanımında detaya iner. Meta veri etiketleri, her alanın aranabilir veya sıralanabilir olması gibi öznitelikleri tanımlamak için kullanılır.

Hotel.cs dosyasındaki aşağıdaki kod parçacıkları, tek bir alanın ve başka bir veri modeli sınıfına başvurunun nasıl belirtilebileceğini gösterir.

. . .
[SearchableField(IsSortable = true)]
public string HotelName { get; set; }
. . .
public Address Address { get; set; }
. . .

Program.cs dosyasında dizin, yöntemi tarafından FieldBuilder.Build(typeof(Hotel)) oluşturulan bir ad ve alan koleksiyonuyla tanımlanır ve aşağıdaki gibi oluşturulur:

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);
}

Veri oluşturma

Test için veri oluşturmak üzere DataGenerator.cs dosyasında basit bir sınıf uygulanır. Bu sınıfın tek amacı, dizin oluşturma için benzersiz bir kimlikle çok sayıda belge oluşturmayı kolaylaştırmaktır.

Benzersiz kimliklere sahip 100.000 otelin listesini almak için aşağıdaki kod satırlarını çalıştırın:

long numDocuments = 100000;
DataGenerator dg = new DataGenerator();
List<Hotel> hotels = dg.GetHotels(numDocuments, "large");

Bu örnekte test için kullanılabilecek iki otel boyutu vardır: küçük ve büyük.

Dizininizin şemasının dizin oluşturma hızları üzerinde etkisi vardır. Bu nedenle, bu öğreticiyi çalıştırdıktan sonra hedeflenen dizin şemanıza en uygun verileri oluşturmak için bu sınıfı dönüştürmek mantıklıdır.

4 - Toplu iş boyutlarını test edin

Azure AI Search, bir dizine tek veya birden çok belge yüklemek için aşağıdaki API'leri destekler:

Belgeleri toplu olarak dizine ekleme, dizin oluşturma performansını önemli ölçüde artırır. Bu toplu işlemler en fazla 1000 belge veya toplu iş başına yaklaşık 16 MB olabilir.

Verileriniz için en uygun toplu iş boyutunu belirlemek, dizin oluşturma hızlarını iyileştirmenin önemli bir bileşenidir. En uygun toplu iş boyutunu etkileyen iki birincil faktör şunlardır:

  • Dizininizin şeması
  • Verilerinizin boyutu

En uygun toplu iş boyutu dizininize ve verilerinize bağlı olduğundan, en iyi yaklaşım farklı toplu iş boyutlarını test ederek senaryonuz için en yüksek dizin oluşturma hızlarına hangi sonuçların verileceğini belirlemektir.

Aşağıdaki işlev, toplu iş boyutlarını test etmeye yönelik basit bir yaklaşımı gösterir.

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();
}

Tüm belgeler aynı boyutta olmadığından (bu örnekte olsalar da), arama hizmetine gönderdiğimiz verilerin boyutunu tahmin ediyoruz. Bunu, önce nesnesini json'a dönüştüren ve ardından bayt cinsinden boyutunu belirleyen aşağıdaki işlevi kullanarak yaparız. Bu teknik, HANGI toplu iş boyutlarının MB/sn dizin oluşturma hızları açısından en verimli olduğunu belirlememizi sağlar.

// 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;
}

İşlev, her toplu iş boyutu için test etmek istediğiniz deneme sayısının artısını SearchClient gerektirir. Her toplu iş için dizin oluşturma sürelerinde değişkenlik olabileceğinden, sonuçları istatistiksel olarak daha önemli hale getirmek için her toplu işlemi varsayılan olarak üç kez deneriz.

await TestBatchSizesAsync(searchClient, numTries: 3);

İşlevi çalıştırdığınızda konsolunuzda aşağıdakine benzer bir çıkış görmeniz gerekir:

Output of test batch size function

Hangi toplu iş boyutunun en verimli olduğunu belirleyin ve öğreticinin sonraki adımında bu toplu iş boyutunu kullanın. Farklı toplu iş boyutlarında MB/sn cinsinden bir plato görebilirsiniz.

5 - Dizin verileri

Kullanmak istediğimiz toplu iş boyutunu belirlediğimize göre, sonraki adım verileri dizine eklemeye başlamaktır. Verileri verimli bir şekilde dizine almak için şu örnek:

  • Birden çok iş parçacığı/çalışan kullanır.
  • Üstel geri alma yeniden deneme stratejisi uygular.

41 ile 49 arasında olan açıklama satırlarını kaldırın ve programı yeniden çalıştırın. Bu çalıştırmada örnek, parametreleri değiştirmeden kodu çalıştırırsanız 100.000'e kadar toplu belge oluşturur ve gönderir.

Birden çok iş parçacığı/çalışan kullanma

Azure AI Search'ün dizin oluşturma hızlarından tam olarak yararlanmak için, toplu dizin oluşturma isteklerini hizmete eşzamanlı olarak göndermek için birden çok iş parçacığı kullanın.

Daha önce bahsedilen önemli noktalardan birkaçı en uygun iş parçacığı sayısını etkileyebilir. Senaryonuz için en uygun iş parçacığı sayısını belirlemek için bu örneği değiştirebilir ve farklı iş parçacığı sayılarıyla test edebilirsiniz. Ancak, eşzamanlı olarak çalışan birkaç iş parçacığınız olduğu sürece, verimlilik kazançlarının çoğundan yararlanabilmeniz gerekir.

Arama hizmetine isabet eden istekleri artırdığınızda, isteğin tam olarak başarılı olmadığını belirten HTTP durum kodlarıyla karşılaşabilirsiniz. Dizin oluşturma sırasında iki yaygın HTTP durum kodu şunlardır:

  • 503 Hizmet Kullanılamıyor - Bu hata, sistemin ağır yük altında olduğu ve isteğinizin şu anda işlenebileceği anlamına gelir.
  • 207 Çoklu Durum - Bu hata bazı belgelerin başarılı olduğu, ancak en az birinin başarısız olduğu anlamına gelir.

Üstel geri alma yeniden deneme stratejisi uygulama

Bir hata oluştuğunda istekler üstel geri alma yeniden deneme stratejisi kullanılarak yeniden denenmelidir.

Azure AI Search'ün .NET SDK'sı 503'leri ve diğer başarısız istekleri otomatik olarak yeniden dener, ancak 207'leri yeniden denemek için kendi mantığınızı uygulamanız gerekir. Polly gibi açık kaynak araçlar bir yeniden deneme stratejisinde yararlı olabilir.

Bu örnekte kendi üstel geri alma yeniden deneme stratejimizi uygulayacağız. İlk olarak başarısız bir isteğin maxRetryAttempts başlangıcı delay ve dahil olmak üzere bazı değişkenler tanımlıyoruz:

// 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;

Dizin oluşturma işleminin sonuçları değişkeninde IndexDocumentResult resultdepolanır. Bu değişken, toplu işteki herhangi bir belgenin aşağıda gösterildiği gibi başarısız olup olmadığını denetlemenize olanak sağladığından önemlidir. Kısmi bir hata varsa, başarısız belgelerin kimliğine göre yeni bir toplu iş oluşturulur.

RequestFailedException özel durumlar da isteğin tamamen başarısız olduğunu ve yeniden denenmesi gerektiğini gösterdiğinden yakalanmalıdır.

// 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);

Buradan, üstel geri alma kodunu kolayca çağrılabilmesi için bir işleve sarmalıyoruz.

Daha sonra etkin iş parçacıklarını yönetmek için başka bir işlev oluşturulur. Kolaylık olması için bu işlev buraya dahil değildir ancak ExponentialBackoff.cs bulunabilir. İşlev aşağıdaki komutla çağrılabilir. hotels Burada karşıya yüklemek istediğimiz veriler, 1000 toplu iş boyutu ve 8 eşzamanlı iş parçacıklarının sayısıdır:

await ExponentialBackoff.IndexData(indexClient, hotels, 1000, 8);

İşlevi çalıştırdığınızda aşağıdakine benzer bir çıkış görmeniz gerekir:

Output of index data function

Bir grup belge başarısız olduğunda, hatanın ve toplu işlemin yeniden denendiğini belirten bir hata yazdırılır:

[Batch starting at doc 6000 had partial failure]
[Retrying 560 failed documents]

İşlevin çalışması tamamlandıktan sonra, tüm belgelerin dizine eklendiğini doğrulayabilirsiniz.

6 - Dizini keşfetme

Program program aracılığıyla çalıştırıldıktan veya portaldaki Arama gezginini kullandıktan sonra doldurulan arama dizinini inceleyebilirsiniz.

Programatically

Dizindeki belge sayısını denetlemek için iki ana seçenek vardır: Belgeleri Say API'si ve Dizin İstatistiklerini Al API'si. Her iki yolun da işlenmesi için zaman gerekir, bu nedenle döndürülen belge sayısı başlangıçta beklediğinizden daha düşükse alarma alınmayın.

Belgeleri Say

Belgeleri Say işlemi, arama dizinindeki belge sayısının sayısını alır:

long indexDocCount = await searchClient.GetDocumentCountAsync();

Dizin İstatistiklerini Alma

Dizin İstatistiklerini Al işlemi geçerli dizin için bir belge sayısı ve depolama kullanımı döndürür. Dizin istatistiklerinin güncelleştirileceği belge sayısı daha uzun sürer.

var indexStats = await indexClient.GetIndexStatisticsAsync(indexName);

Azure portal

Azure portalında, sol gezinti bölmesinden dizin iyileştirme dizinini Dizinler listesinde bulun.

List of Azure AI Search indexes

Belge Sayısı ve Depolama Boyutu, Dizin İstatistiklerini Al API'sini temel alır ve güncelleştirilmek birkaç dakika sürebilir.

Sıfırlama ve yeniden çalıştırma

Geliştirmenin ilk deneysel aşamalarında tasarım yinelemesi için en pratik yaklaşım, nesneleri Azure AI Search'ten silmek ve kodunuzun bunları yeniden oluşturmasına izin vermektir. Kaynak adları benzersizdir. Bir nesneyi sildiğinizde, aynı adı kullanarak nesneyi yeniden oluşturabilirsiniz.

Bu öğreticinin örnek kodu, mevcut dizinleri denetler ve kodunuzu yeniden çalıştırabilmeniz için bunları siler.

Dizinleri silmek için portalı da kullanabilirsiniz.

Kaynakları temizleme

Kendi aboneliğinizde çalışırken, bir projenin sonunda artık ihtiyacınız olmayan kaynakları kaldırmak iyi bir fikirdir. Çalışır durumda bırakılan kaynaklar maliyetlerin artmasına neden olabilir. Kaynakları teker teker silebilir veya tüm kaynak grubunu silerek kaynak kümesinin tamamını kaldırabilirsiniz.

Sol gezinti bölmesindeki Tüm kaynaklar veya Kaynak grupları bağlantısını kullanarak kaynakları portalda bulabilir ve yönetebilirsiniz.

Sonraki adımlar

Büyük miktarlardaki verilerin dizinini oluşturma hakkında daha fazla bilgi edinmek için aşağıdaki öğreticiyi deneyin.