Tutorial: Mengoptimalkan pengindeksan dengan API push

Pencarian Azure AI mendukung dua pendekatan dasar untuk mengimpor data ke dalam indeks pencarian: mendorong data Anda ke dalam indeks secara terprogram, atau mengarahkan pengindeks Azure AI Search di sumber data yang didukung untuk menarik data.

Tutorial ini menjelaskan cara mengindeks data secara efisien menggunakan model pendorongan dengan membuat batch permintaan dan menggunakan strategi coba lagi backoff eksponensial. Anda dapat mengunduh dan menjalankan aplikasi sampel. Artikel ini menjelaskan aspek utama aplikasi dan faktor apa yang perlu dipertimbangkan saat mengindeks data.

Tutorial ini menggunakan C# dan pustaka Azure.Search.Documents dari Azure SDK untuk .NET untuk melakukan tugas berikut:

  • Buat indeks
  • Uji berbagai ukuran batch untuk menentukan ukuran yang paling efisien
  • Indeks batch secara asinkron
  • Gunakan beberapa utas untuk meningkatkan kecepatan pengindeksan
  • Gunakan strategi percobaan ulang backoff eksponensial untuk mencoba kembali dokumen yang gagal

Jika Anda tidak memiliki langganan Azure, buat akun gratis sebelum Anda memulai.

Prasyarat

Layanan dan alat berikut diperlukan untuk tutorial ini.

Mengunduh file

Kode sumber untuk tutorial ini berada di folder optimize-data-indexing/v11 di repositori GitHub Azure-Samples/azure-search-dotnet-samples .

Pertimbangan kunci

Faktor-faktor yang memengaruhi kecepatan pengindeksan tercantum berikutnya. Anda dapat mempelajari selengkapnya di Mengindeks himpunan data besar.

  • Tingkat layanan dan jumlah partisi/replika - Menambahkan partisi atau meningkatkan tingkat Anda meningkatkan kecepatan pengindeksan.
  • Kompleksitas skema indeks - Menambahkan properti bidang dan bidang menurunkan kecepatan pengindeksan. Indeks yang lebih kecil lebih cepat untuk diindeks.
  • Ukuran batch - Ukuran batch optimal bervariasi berdasarkan skema indeks dan himpunan data Anda.
  • Jumlah utas/pekerja - Satu utas tidak akan memanfaatkan kecepatan pengindeksan sepenuhnya.
  • Strategi coba lagi - Strategi coba lagi backoff eksponensial adalah praktik terbaik untuk pengindeksan optimal.
  • Kecepatan transfer data jaringan - Kecepatan transfer data dapat menjadi faktor pembatas. Indeks data dari dalam lingkungan Azure Anda untuk meningkatkan kecepatan transfer data.

1 - Membuat azure AI layanan Pencarian

Untuk menyelesaikan tutorial ini, Anda memerlukan layanan Pencarian Azure AI, yang dapat Anda buat di portal. Sebaiknya gunakan tingkat yang sama dengan yang Anda berencana untuk digunakan dalam produksi sehingga Anda dapat menguji dan mengoptimalkan kecepatan pengindeksan secara akurat.

Tutorial ini menggunakan autentikasi berbasis kunci. Salin kunci API admin untuk ditempelkan ke file appsettings.json .

  1. Masuk ke portal Azure, dan di halaman Gambaran Umum layanan pencarian Anda, dapatkan URL. Contoh titik akhir mungkin terlihat sepertihttps://mydemo.search.windows.net.

  2. Di Pengaturan>Kunci, dapatkan kunci admin untuk mendapatkan hak penuh atas layanan. Ada dua kunci admin yang dapat dipertukarkan, kunci disediakan untuk kelangsungan bisnis jika Anda perlu menimpa salah satunya. Anda dapat menggunakan kunci utama atau sekunder pada permintaan untuk menambahkan, memodifikasi, dan menghapus objek.

    Get an HTTP endpoint and access key

2 - Menyiapkan lingkungan Anda

  1. Mulai Visual Studio dan buka OptimizeDataIndexing.sln.
  2. Di Penjelajah Solusi, buka appsettings.json untuk memberikan informasi koneksi.
{
  "SearchServiceUri": "https://{service-name}.search.windows.net",
  "SearchServiceAdminApiKey": "",
  "SearchIndexName": "optimize-indexing"
}

3 - Jelajahi kode

Setelah Anda memperbarui appsettings.json, program sampel di OptimizeDataIndexing.sln seharusnya siap untuk dibangun dan dijalankan.

Kode ini berasal dari bagian C# dari Mulai Cepat: Pencarian teks lengkap menggunakan Azure SDK. Anda dapat menemukan informasi lebih detail tentang dasar-dasar bekerja dengan .NET SDK di artikel tersebut.

Aplikasi konsol C#/.NET sederhana ini melakukan tugas-tugas berikut:

  • Membuat indeks baru berdasarkan struktur data kelas Hotel C# (yang juga mereferensikan kelas Alamat).
  • Menguji berbagai ukuran batch untuk menentukan ukuran yang paling efisien
  • Mengindeks data secara asinkron
    • Menggunakan beberapa utas untuk meningkatkan kecepatan pengindeksan
    • Menggunakan strategi percobaan ulang backoff eksponensial untuk mencoba kembali item yang gagal

Sebelum menjalankan program, luangkan waktu satu menit untuk mempelajari kode dan definisi indeks untuk sampel ini. Kode yang relevan ada di beberapa file:

  • Hotel.cs dan Address.cs berisi skema yang mendefinisikan indeks
  • DataGenerator.cs berisi kelas sederhana untuk memudahkan membuat data hotel dalam jumlah besar
  • ExponentialBackoff.cs berisi kode untuk mengoptimalkan proses pengindeksan seperti yang dijelaskan dalam artikel ini
  • Program.cs berisi fungsi yang membuat dan menghapus indeks Azure AI Search, mengindeks batch data, dan menguji ukuran batch yang berbeda

Membuat indeks

Program sampel ini menggunakan Azure SDK untuk .NET untuk menentukan dan membuat indeks Azure AI Search. Ini memanfaatkan kelas FieldBuilder untuk menghasilkan struktur indeks dari kelas model data C#.

Model data ditentukan oleh kelas Hotel, yang juga berisi referensi ke kelas Alamat. FieldBuilder menelusuri detail beberapa definisi kelas untuk menghasilkan struktur data yang kompleks untuk indeks. Tag metadata digunakan untuk menentukan atribut setiap bidang, seperti apakah tag dapat dicari atau dapat diurutkan.

Cuplikan berikut dari file Hotel.cs menunjukkan bagaimana satu bidang dan referensi ke kelas model data lain dapat ditentukan.

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

Dalam file Program.cs, indeks ditentukan dengan nama dan koleksi bidang yang dihasilkan oleh metode FieldBuilder.Build(typeof(Hotel)), lalu dibuat sebagai berikut:

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

Menghasilkan data

Kelas sederhana diimplementasikan dalam file DataGenerator.cs untuk menghasilkan data untuk pengujian. Satu-satunya tujuan kelas ini adalah untuk memudahkan menghasilkan sejumlah besar dokumen dengan ID unik untuk pengindeksan.

Untuk mendapatkan daftar 100.000 hotel dengan ID unik, jalankan baris kode berikut:

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

Ada dua ukuran hotel yang tersedia untuk pengujian dalam sampel ini: kecil dan besar.

Skema indeks Anda memiliki efek pada kecepatan pengindeksan. Untuk alasan ini, masuk akal untuk mengonversi kelas ini untuk menghasilkan data yang paling sesuai dengan skema indeks yang Anda maksudkan setelah Anda menjalankan tutorial ini.

4 - Menguji ukuran batch

Azure AI Search mendukung API berikut untuk memuat satu atau beberapa dokumen ke dalam indeks:

Mengindeks dokumen dalam batch akan secara signifikan meningkatkan performa pengindeksan. Batch ini dapat mencapai 1000 dokumen, atau hingga sekitar 16 MB per batch.

Menentukan ukuran batch optimal untuk data Anda adalah komponen kunci untuk mengoptimalkan kecepatan pengindeksan. Dua faktor utama yang memengaruhi ukuran batch yang optimal adalah:

  • Skema indeks Anda
  • Ukuran data Anda

Karena ukuran batch yang optimal tergantung pada indeks dan data Anda, pendekatan terbaik adalah menguji ukuran batch yang berbeda untuk menentukan hasil apa dalam kecepatan pengindeksan tercepat untuk skenario Anda.

Fungsi berikut menunjukkan pendekatan sederhana untuk menguji ukuran batch.

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

Karena tidak semua dokumen berukuran sama (meskipun dalam sampel ini), kita memerkirakan ukuran data yang kita kirim ke layanan pencarian. Kita melakukan ini menggunakan fungsi di bawah ini yang pertama kali mengonversi objek ke json, lalu menentukan ukurannya dalam byte. Teknik ini memungkinkan kita untuk menentukan ukuran batch mana yang paling efisien dalam hal kecepatan pengindeksan MB/dtk.

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

Fungsi ini memerlukan plus jumlah percobaan yang SearchClient ingin Anda uji untuk setiap ukuran batch. Karena mungkin ada varianbilitas dalam waktu pengindeksan untuk setiap batch, kami mencoba setiap batch tiga kali secara default untuk membuat hasilnya lebih signifikan secara statistik.

await TestBatchSizesAsync(searchClient, numTries: 3);

Saat menjalankan fungsi, Anda akan melihat output seperti di bawah ini dalam konsol:

Output of test batch size function

Identifikasi ukuran batch mana yang paling efisien, lalu gunakan ukuran batch tersebut di langkah tutorial berikutnya. Anda mungkin melihat dataran tinggi dalam MB/dtk di berbagai ukuran batch.

5 - Data indeks

Sekarang setelah kita mengidentifikasi ukuran batch yang ingin digunakan, langkah selanjutnya adalah mulai mengindeks data. Untuk mengindeks data secara efisien, sampel ini:

  • Menggunakan beberapa utas/pekerja.
  • Menerapkan strategi percobaan ulang backoff eksponensial.

Uncomment baris 41 sampai 49 dan jalankan ulang dan program. Pada proses ini, sampel menghasilkan dan mengirim batch dokumen, hingga 100.000 jika Anda menjalankan kode tanpa mengubah parameter.

Menggunakan beberapa utas/pekerja

Untuk memanfaatkan sepenuhnya kecepatan pengindeksan Azure AI Search, gunakan beberapa utas untuk mengirim permintaan pengindeksan batch secara bersamaan ke layanan.

Beberapa pertimbangan utama yang disebutkan sebelumnya dapat memengaruhi jumlah utas yang optimal. Anda dapat memodifikasi sampel ini, dan menguji dengan jumlah utas yang berbeda untuk menentukan jumlah utas optimal untuk skenario Anda. Namun, selama Anda memiliki beberapa utas yang berjalan bersamaan, Anda harus dapat memanfaatkan sebagian besar keuntungan efisiensi.

Saat Anda meningkatkan permintaan yang mencapai layanan pencarian, Anda mungkin menemukan kode status HTTP yang menunjukkan permintaan tidak sepenuhnya berhasil. Selama pengindeksan, dua kode status HTTP umum adalah:

  • 503 Layanan Tidak Tersedia - Kesalahan ini berarti bahwa sistem berada pada kondisi beban berat, dan permintaan Anda tidak dapat diproses saat ini.
  • 207 Multi-Status - Kesalahan ini berarti bahwa beberapa dokumen berhasil, tetapi minimal satu dokumen gagal.

Menerapkan strategi percobaan ulang backoff eksponensial

Jika terjadi kegagalan, permintaan harus dicoba ulang menggunakan strategi percobaan ulang backoff eksponensial.

.NET SDK Azure AI Search secara otomatis mencoba kembali 503s dan permintaan lain yang gagal tetapi Anda harus menerapkan logika Anda sendiri untuk mencoba kembali 207s. Alat sumber terbuka seperti Polly dapat berguna dalam strategi coba lagi.

Dalam sampel ini, kita menerapkan strategi percobaan ulang backoff eksponensial sendiri. Kita mulai dengan menentukan beberapa variabel termasuk maxRetryAttempts dan awal delay untuk permintaan yang gagal:

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

Hasil operasi pengindeksan disimpan dalam variabel IndexDocumentResult result. Variabel ini penting karena memungkinkan Anda untuk memeriksa apakah ada dokumen dalam batch yang gagal seperti yang ditunjukkan di bawah ini. Jika ada kegagalan parsial, batch baru dibuat berdasarkan ID dokumen yang gagal.

Pengecualian RequestFailedException juga harus ditangkap karena menunjukkan permintaan gagal sepenuhnya dan juga harus dicoba ulang.

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

Dari sini, kita membungkus kode backoff eksponensial ke dalam fungsi sehingga dapat dipanggil dengan mudah.

Fungsi lain kemudian dibuat untuk mengelola utas aktif. Untuk kesederhanaan, fungsi itu tidak termasuk di sini tetapi dapat ditemukan di ExponentialBackoff.cs. Fungsi ini dapat dipanggil dengan perintah berikut di mana hotels adalah data yang ingin kita unggah, 1000 adalah ukuran batch, dan 8 merupakan jumlah utas bersamaan:

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

Saat menjalankan fungsi, Anda akan melihat output seperti di bawah ini:

Output of index data function

Ketika batch dokumen gagal, kesalahan yang dicetak menunjukkan kegagalan dan bahwa batch sedang dicoba ulang:

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

Setelah fungsi selesai berjalan, Anda dapat memverifikasi bahwa semua dokumen ditambahkan ke indeks.

6 - Menjelajahi indeks

Anda dapat menjelajahi indeks pencarian yang diisi setelah program berjalan secara terprogram atau menggunakan Penjelajah pencarian di portal.

Secara terprogram

Ada dua opsi utama untuk memeriksa jumlah dokumen dalam indeks: API Hitung Dokumen dan API Dapatkan Statistik Indeks. Kedua jalur memerlukan waktu untuk diproses sehingga jangan khawatir jika jumlah dokumen yang dikembalikan awalnya lebih rendah dari yang Anda harapkan.

Hitung Dokumen

Operasi Hitung Dokumen mengambil hitungan jumlah dokumen dalam indeks pencarian:

long indexDocCount = await searchClient.GetDocumentCountAsync();

Dapatkan Statistik Indeks

Operasi Dapatkan Statistik Indeks mengembalikan jumlah dokumen untuk indeks saat ini, ditambah penggunaan penyimpanan. Statistik indeks akan memerlukan waktu lebih lama dari jumlah dokumen untuk diperbarui.

var indexStats = await indexClient.GetIndexStatisticsAsync(indexName);

Portal Azure

Di portal Azure, dari panel navigasi kiri, dan temukan indeks pengindeksan pengoptimalan di daftar Indeks.

List of Azure AI Search indexes

Jumlah Dokumen dan Ukuran Penyimpanan didasarkan pada Get Index Statistics API dan dapat memakan waktu beberapa menit untuk diperbarui.

Atur ulang dan jalankan ulang

Pada tahap pengembangan eksperimental awal, pendekatan paling praktis untuk iterasi desain adalah menghapus objek dari Azure AI Search dan memungkinkan kode Anda untuk membangunnya kembali. Nama sumber daya unik. Menghapus objek memungkinkan Anda membuatnya kembali menggunakan nama yang sama.

Kode sampel untuk tutorial ini memeriksa indeks yang ada dan menghapusnya sehingga Anda dapat menjalankan ulang kode Anda.

Anda juga dapat menggunakan portal untuk menghapus indeks.

Membersihkan sumber daya

Saat Anda bekerja di langganan Anda sendiri, di akhir proyek, sebaiknya hapus sumber daya yang tidak lagi Anda butuhkan. Sumber daya yang dibiarkan berjalan dapat menghabiskan uang Anda. Anda dapat menghapus sumber daya satu per satu atau menghapus grup sumber daya untuk menghapus seluruh rangkaian sumber daya.

Anda dapat menemukan dan mengelola sumber daya di portal, menggunakan tautan Semua sumber daya atau Grup sumber daya di panel navigasi kiri.

Langkah berikutnya

Untuk mempelajari selengkapnya tentang mengindeks data dalam jumlah besar, coba tutorial berikut.