Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Служба "Поиск ИИ Azure" поддерживает два основных метода импорта данных в индекс поиска: отправку данных в индекс программным способом или извлечение данных путем указания индексатора на поддерживаемый источник данных.
В этом руководстве объясняется, как эффективно индексировать данные с помощью модели push, пакетируя запросы и применяя стратегию экспоненциальной повторной попытки. Вы можете скачать и запустить пример приложения. В этом руководстве также описываются ключевые аспекты приложения и факторы, которые следует учитывать при индексировании данных.
В этом руководстве вы используете C# и библиотеку Azure.Search.Documents из пакета SDK Azure для .NET:
- Создание индекса
- Попробуйте разные размеры пакетов, чтобы выбрать наиболее эффективный вариант.
- Реализуйте асинхронное индексирование пакетов.
- Используйте несколько потоков для увеличения скорости индексирования.
- Используйте стратегию повторных попыток с экспоненциальной задержкой для повторной обработки неудавшихся документов.
Предварительные условия
- Учетная запись Azure с активной подпиской. Создайте учетную запись бесплатно .
- Визуальная студия.
Загрузка файлов
Исходный код для этого руководства находится в папке optimize-data-indexing/v11 в репозитории GitHub azure-samples/azure-search-dotnet-scale GitHub.
Основные рекомендации
Следующие факторы влияют на скорость индексирования. Дополнительные сведения см. в разделе "Индексирование больших наборов данных".
- Ценовая категория и количество секций или реплик: добавление секций или обновление уровня увеличивает скорость индексирования.
- Сложность схемы индекса: добавление полей и свойств полей снижает скорость индексирования. Меньшие индексы быстрее индексируются.
- Размер пакета: оптимальный размер пакета зависит от схемы индекса и набора данных.
- Количество потоков/работников: один поток не в полной мере использует преимущества скорости индексирования.
- Стратегия повторных попыток: экспоненциальное увеличение интервалов между попытками является наилучшей практикой для оптимального индексирования.
- Скорость передачи данных в сети: скорость передачи данных может быть ограничивающим фактором. Чтобы увеличить скорость передачи данных, индексируйте данные из среды Azure.
Создание службы поиска
В этом руководстве требуется служба поиска ИИ Azure, которую можно создать на портале Azure. Вы также можете найти существующую службу в текущей подписке. Чтобы точно протестировать и оптимизировать скорость индексирования, рекомендуется использовать ту же ценовую категорию, что и в рабочей среде.
Получение ключа администратора и URL-адреса для поиска искусственного интеллекта Azure
В этом руководстве используется проверка подлинности на основе ключей. Скопируйте ключ API администратора для вставки в appsettings.json файл.
Войдите на портал Azure и выберите службу поиска.
В левой области выберите "Обзор " и скопируйте конечную точку. Он должен быть в следующем формате:
https://my-service.search.windows.netВ левой панели выберите Параметры> и Ключи, затем скопируйте администраторский ключ для полного доступа к службе. Существуют два взаимозаменяемых ключа администратора, предназначенных для обеспечения непрерывности бизнес-процессов на случай, если вам потребуется сменить один из них. Вы можете использовать либо один из ключей для запросов чтобы добавлять, изменять или удалять объекты.
Настройка среды
OptimizeDataIndexing.slnОткройте файл в Visual Studio.В обозревателе решений измените
appsettings.jsonфайл с данными о подключении, собранными на предыдущем шаге.{ "SearchServiceUri": "https://{service-name}.search.windows.net", "SearchServiceAdminApiKey": "", "SearchIndexName": "optimize-indexing" }
Изучение кода
После обновления appsettings.jsonпример программы OptimizeDataIndexing.sln должен быть готов к сборке и запуску.
Этот код является производным от раздела краткого руководства по C#: полнотекстовый поиск, который содержит подробные сведения об основах работы с пакетом SDK для .NET.
Это простое консольное приложение для C#/.NET выполняет следующие задачи:
- Создает новый индекс на основе структуры данных класса C#
Hotel(который также ссылается наAddressкласс) - выполняет тесты с разными размерами пакетов, чтобы выбрать наиболее эффективный вариант;
- Индексирует данные асинхронно
- использует несколько потоков для увеличения скорости индексирования;
- применяет стратегию повторов с экспоненциальной задержкой, чтобы обрабатывать неудачные попытки.
Прежде чем запустить программу, изучите код и определения индекса для этого примера. Соответствующий код находится в нескольких файлах:
-
Hotel.csиAddress.csсодержит схему, определяющую индекс. -
DataGenerator.csсодержит простой класс, чтобы упростить создание больших объемов данных отеля -
ExponentialBackoff.csсодержит код для оптимизации процесса индексирования, как описано в этой статье -
Program.csсодержит функции, которые создают и удаляют индекс поиска ИИ Azure, индексирует пакеты данных и проверяет различные размеры пакетов.
Создание индекса
В этом примере программы для .NET используется пакет SDK Azure для .NET для определения и создания индекса поиска ИИ Azure. Он использует преимущества FieldBuilder класса для создания структуры индекса из класса модели данных C#.
Модель данных определяется классом Hotel , который также содержит ссылки на Address класс.
FieldBuilder проходит через несколько определений классов для генерации сложной структуры данных для индекса. Теги метаданных применяются для определения атрибутов каждого поля, например сведений о поддержке поиска или сортировки.
Следующие фрагменты из Hotel.cs файла указывают одно поле и ссылку на другой класс модели данных.
. . .
[SearchableField(IsSortable = true)]
public string HotelName { get; set; }
. . .
public Address Address { get; set; }
. . .
Program.cs В файле индекс определяется с именем и коллекцией полей, созданной методом FieldBuilder.Build(typeof(Hotel)), и затем он создается следующим образом:
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);
}
Сформировать данные
Простой класс реализуется в DataGenerator.cs файле для создания данных для тестирования. Цель этого класса — упростить создание большого количества документов с уникальным идентификатором для индексирования.
Чтобы получить список из 100 000 отелей с уникальными идентификаторами, выполните следующий код:
long numDocuments = 100000;
DataGenerator dg = new DataGenerator();
List<Hotel> hotels = dg.GetHotels(numDocuments, "large");
В этом примере доступны два размера гостиниц для тестирования: small (маленькие) и large (большие).
Схема индекса влияет на скорость индексирования. После завершения работы с этим руководством рекомендуется преобразовать этот класс для создания данных, которые лучше всего соответствуют предполагаемой схеме индекса.
Тестовые размеры пакетов
Чтобы загрузить один или несколько документов в индекс, служба "Поиск ИИ Azure" поддерживает следующие API:
Индексирование документов в пакетах значительно повышает производительность индексирования. Эти пакеты могут составлять до 1000 документов или около 16 МБ на пакет.
Определение оптимального размера пакета для данных является ключевой задачей при оптимизации скорости индексирования. Существует два основных фактора, которые влияют на оптимальный размер пакета:
- схема вашего индекса
- размер ваших данных.
Так как оптимальный размер пакета зависит от индекса и данных, лучше всего протестировать различные размеры пакетов, чтобы определить, какие результаты приводят к самым быстрым скоростям индексирования для вашего сценария.
В следующем примере функции показан простой подход к выполнению тестирования с пакетами разных размеров.
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();
}
Обычно не все документы имеют одинаковый размер, как в нашем примере, поэтому нам нужно оценивать размер данных, отправляемых в службу поиска. Это можно сделать с помощью следующей функции, которая сначала преобразует объект в JSON, а затем определяет его размер в байтах. Этот метод позволяет определить наиболее эффективные размеры пакетов с точки зрения скорости индексирования (МБ/с).
// 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;
}
Для функции требуется SearchClient плюс количество попыток, которые вы хотите протестировать для каждого размера пакета. Так как для каждого пакета может быть вариативность времени индексации, попробуйте каждый пакет три раза по умолчанию, чтобы сделать результаты более статистически значимыми.
await TestBatchSizesAsync(searchClient, numTries: 3);
При запуске функции вы увидите выходные данные в консоли, как показано в следующем примере:
Определите наиболее эффективный размер пакета и используйте этот размер пакета в следующем шаге этого руководства. Вы можете увидеть плато в мегабайтах в секунду при различных размерах пакетов.
Индексирование данных
Теперь, когда вы определили размер пакета, который вы планируете использовать, следующий шаг — начать индексировать данные. Для эффективного индексирования данных в этом примере выполняются следующие действия:
- Использование нескольких потоков и рабочих ролей
- Реализует стратегию повторных попыток с экспоненциальным увеличением интервала задержки.
Раскомментируйте строки 41–49, а затем повторно запустите программу. В этом запуске программа создает и отправляет пакеты документов, до 100 000, если код выполняется без изменения параметров.
Использование нескольких потоков и рабочих ролей
Чтобы воспользоваться преимуществами скорости индексирования в Azure AI Search, используйте несколько потоков для одновременной отправки пакетных запросов на индексирование в эту службу.
Некоторые ключевые аспекты могут повлиять на оптимальное количество потоков. Вы можете изменить этот пример и протестировать с разным количеством потоков, чтобы определить оптимальное количество потоков для вашего сценария. Однако, если у вас работает несколько потоков параллельно, вы сможете воспользоваться большинством прироста эффективности.
По мере увеличения запросов, поступающих в службу поиска, могут возникнуть коды состояния HTTP, указывающие, что запрос не полностью выполнен. При индексировании часто используются следующие два кода состояния HTTP:
- Служба 503 недоступна. Эта ошибка означает, что система находится под тяжелой нагрузкой, и ваш запрос не может обрабатываться в настоящее время.
- 207 Multi-Status: эта ошибка означает, что некоторые документы были обработаны успешно, но по крайней мере один произошел сбой.
Реализация стратегии повторов с экспоненциальной задержкой
Если произойдет сбой, следует повторить запросы с помощью экспоненциальной стратегии повторных попыток.
SDK для .NET Azure AI Search автоматически повторяет 503 и другие ошибочные запросы, но вам следует реализовать собственную логику для повторного выполнения запросов 207. Средства с открытым исходным кодом, такие как Polly , могут быть полезны в стратегии повторных попыток.
В этом примере мы реализуем собственную стратегию повторов с экспоненциальной задержкой. Сначала мы определяем некоторые переменные, включая maxRetryAttempts инициал delay для неудачного запроса.
// 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;
Результаты операции индексирования хранятся в переменной IndexDocumentResult result. Эта переменная позволяет проверить, потерпели ли документы в пакете сбой, как в следующем примере. Если произошел частичный сбой, создается новый пакет на основе идентификатора неудачных документов.
RequestFailedException Исключения также должны быть пойманы, так как они указывают на то, что запрос полностью провалился, и его следует повторить.
// 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);
Отсюда оставьте экспоненциальный код обратной передачи в функцию, чтобы ее можно было легко вызвать.
Кроме того, создается еще одна функция для управления активными потоками. Для простоты мы не приводим здесь эту функцию, но вы можете найти ее в файле ExponentialBackoff.cs. Вы можете вызвать функцию с помощью следующей команды, где hotels есть данные, которые мы хотим отправить, 1000 — это размер пакета и 8 количество параллельных потоков.
await ExponentialBackoff.IndexData(indexClient, hotels, 1000, 8);
При запуске функции вы увидите выходные данные, аналогичные следующему примеру:
При сбое пакета документов выводится сообщение об ошибке, указывающее на сбой, и пакет подвергается повторной попытке.
[Batch starting at doc 6000 had partial failure]
[Retrying 560 failed documents]
После завершения работы функции можно убедиться, что все документы были добавлены в индекс.
Изучение индекса
После завершения работы программы можно изучить заполненный индекс поиска программным способом или с помощью обозревателя поиска на портале Azure.
Программно
Есть два основных метода проверки количества документов в индексе: API Count Documents и API Get Index Statistics. Оба пути требуют времени для обработки, поэтому не следует беспокоиться, если количество возвращенных документов изначально ниже, чем ожидалось.
Количество документов
Операция count Documents извлекает количество документов в индексе поиска.
long indexDocCount = await searchClient.GetDocumentCountAsync();
Получение статистики индексов
Операция Get Index Statistics возвращает количество документов в текущем индексе, а также сведения об использовании хранилища. Статистика индексов обновляется дольше, чем количество документов.
var indexStats = await indexClient.GetIndexStatisticsAsync(indexName);
Портал Azure
На портале Azure на панели слева найдите индекс optimize-indexing в списке Indexes.
Количество документов и размер хранилища основаны на API получения статистики индекса, их обновление может занять несколько минут.
Сброс и повторный запуск
На ранних экспериментальных этапах разработки наиболее практичный подход к итерации проектирования заключается в удалении объектов из службы поиска Azure AI и позволении вашему коду перестроить их. Имена ресурсов уникальны. Удаление объекта позволяет воссоздать его с использованием того же имени.
Пример кода для этого руководства проверяет имеющиеся индексы и удаляет их, чтобы вы могли повторно выполнить этот код.
Вы также можете использовать портал Azure для удаления индексов.
Очистка ресурсов
Если вы работаете в своей подписке, после завершения проекта целесообразно удалить ресурсы, которые вам больше не потребуются. Ресурсы, которые остаются включенными, могут обойтись вам в деньги. Вы можете удалить ресурсы по отдельности либо удалить всю группу ресурсов.
Ресурсы и управление ими можно найти в портал Azure, используя ссылку "Все ресурсы" или "Группы ресурсов" в области навигации слева.
Следующий шаг
Дополнительные сведения об индексировании больших объемов данных см. в следующем руководстве.