如何用Elasticsearch NEST C#客户端批量条件更新嵌套时间序列列表
基于NEST批量部分更新Elasticsearch嵌套列表的实现方法
问题背景
需要使用Elasticsearch .NET高级客户端NEST,批量对指定ID的文档进行嵌套列表的部分更新:仅修改history列表中匹配特定日期的quantity值,未匹配的日期数据保持不变;如果指定日期在原列表中不存在,则新增该条记录。已知全文档批量索引和全嵌套列表替换的实现方式,但不清楚嵌套列表的部分更新方法。
原文档示例
[ { "id": 1, "description": "market 1", "salesprice": 10.9, "cost": 7.95957, "history": [ { "historydate": "2020-01-01", "quantity": 1 }, { "historydate": "2020-02-01", "quantity": 2 }, { "historydate": "2020-04-01", "quantity": 5 } ] }, { "id": 2, "description": "market 2", "salesprice": 12, "cost": 12, "history": [ { "historydate": "2020-01-01", "quantity": 1 }, { "historydate": "2020-02-01", "quantity": 2 }, { "historydate": "2020-03-01", "quantity": 6 } ] } ]
更新需求
- ID为1的文档:更新
2020-02-01的quantity为9,新增2020-03-01的记录(quantity=11) - ID为2的文档:更新
2020-02-01的quantity为20,更新2020-03-01的quantity为15
实现方案
核心思路是利用Elasticsearch的**脚本更新(Script Update)**结合NEST的批量请求(Bulk API),通过脚本遍历嵌套数组,完成匹配更新与新增逻辑。
1. 定义C#实体类
对应文档结构定义实体:
public class MarketDocument { public int Id { get; set; } public string Description { get; set; } public decimal SalesPrice { get; set; } public decimal Cost { get; set; } public List<HistoryItem> History { get; set; } } public class HistoryItem { public DateTime HistoryDate { get; set; } public int Quantity { get; set; } }
2. 批量更新代码实现
构建批量更新请求,为每个指定ID的文档编写对应的更新脚本:
// 假设已初始化ElasticClient实例 var client = new ElasticClient(settings); // 准备待更新数据集:Key为文档ID,Value为需要更新/新增的HistoryItem列表 var updateTasks = new Dictionary<int, List<HistoryItem>> { { 1, new List<HistoryItem> { new HistoryItem { HistoryDate = new DateTime(2020, 2, 1), Quantity = 9 }, new HistoryItem { HistoryDate = new DateTime(2020, 3, 1), Quantity = 11 } } }, { 2, new List<HistoryItem> { new HistoryItem { HistoryDate = new DateTime(2020, 2, 1), Quantity = 20 }, new HistoryItem { HistoryDate = new DateTime(2020, 3, 1), Quantity = 15 } } } }; // 构建批量请求 var bulkRequest = new BulkRequest(); bulkRequest.Operations = new List<IBulkOperation>(); foreach (var task in updateTasks) { var docId = task.Key; var historyUpdates = task.Value; // 编写Painless脚本:遍历history数组,匹配日期则更新,未匹配则新增 var script = new InlineScript(@" def updates = params.updates; for (update in updates) { def found = false; for (item in ctx._source.history) { if (item.historydate == update.historydate) { item.quantity = update.quantity; found = true; break; } } if (!found) { ctx._source.history.add(update); } } ") { Params = new Dictionary<string, object> { { "updates", historyUpdates.Select(h => new { historydate = h.HistoryDate.ToString("yyyy-MM-dd"), quantity = h.Quantity }) } } }; // 添加更新操作到批量请求 bulkRequest.Operations.Add(new UpdateOperation<MarketDocument, object>(docId) { Script = script }); } // 执行批量更新 var response = client.Bulk(bulkRequest); // 检查执行结果 if (response.IsValid) { Console.WriteLine("批量更新成功"); } else { Console.WriteLine($"批量更新失败: {response.ServerError?.Error?.Reason}"); }
关键说明
- 脚本逻辑:
- 遍历传入的更新参数
updates,对每个待更新的日期,先检查原history数组中是否存在匹配项 - 存在则直接修改
quantity值;不存在则调用add方法新增该记录
- 遍历传入的更新参数
- 日期格式:脚本中统一使用
yyyy-MM-dd格式匹配,确保与文档中存储的日期字符串格式一致 - 批量请求:通过NEST的
BulkRequest将多个更新操作打包执行,提升效率 - 映射适配:如果
history字段在Elasticsearch中设置为nested类型,脚本逻辑依然适用,无需额外修改
内容的提问来源于stack exchange,提问作者user1887852
相关产品推荐
相关产品推荐

