/// <summary> /// This will rebuild an entire index alias behind the scenes with no downtime. It creates a new index /// and populates it then uses Elasticsearch's hot-swapping technique to bring it online. /// </summary> public async static Task RebuildIndexWithHotSwapAsync( this IElasticLowLevelClient client, string alias, JObject indexMapping, Func <Task <IEnumerable <BulkIndexingDoc> > > reader, CancellationToken ctx = default(CancellationToken)) { var deletableIndices = JArray.Parse((await client.CatAliasesAsync <StringResponse>(alias, new CatAliasesRequestParameters { Format = "json" }, ctx)).Body) .Select(x => new { alias = x.Value <string>("alias"), index = x.Value <string>("index") }) .ToList(); var index = GenerateUniqueIndexNameForAlias(alias); await client.IndicesCreateAsync <StringResponse>(index, PostData.String(indexMapping?.ToString()), ctx : ctx); while (!ctx.IsCancellationRequested) { // TODO: If an exception is thrown, delete the half-created index var docs = await reader(); if (ctx.IsCancellationRequested || !docs.Any()) { break; } var body = docs.SelectMany(doc => doc.ToLines().Select(x => x.ToString(Formatting.None))); var bulkResponse = await client.BulkAsync <StringResponse>(index, PostData.MultiJson(body)); ThrowOnPartialBulkSuccess(bulkResponse); } if (ctx.IsCancellationRequested) { return; } var actions = deletableIndices.Select(idx => (object)new { remove = new { idx.index, idx.alias } }).ToList(); actions.Add(new { add = new { index, alias } }); // This is the hot-swap. The actions in the list are performed atomically await client.IndicesUpdateAliasesForAllAsync <StringResponse>(PostData.String(JObject.FromObject(new { actions }).ToString()), ctx : ctx); if (deletableIndices.Any()) { await client.IndicesDeleteAsync <StringResponse>(string.Join(",", deletableIndices.Select(x => x.index)), ctx : ctx); } }
public static async Task <string> ReIndex <T>(List <T> data) where T : Entity, ISearcheable, new() { var targetType = typeof(T).Name.ToLower(); await _lowlevelClient.IndicesDeleteAsync <StringResponse>(targetType); foreach (var post in data) { var indexObject = post.GetIndexObject(); await _lowlevelClient.IndexAsync <StringResponse>(targetType, targetType, indexObject.Id, PostData.Serializable(indexObject)); } return($"{data.Count} reindexed"); }