ES NEST如何创建含geo类型的动态映射索引并批量索引动态对象
解答
1. 动态创建带几何属性的ES索引
你可以直接基于运行时获取的DatasetSchema手动构造索引映射,不需要依赖ES自动类型推断,也不需要提前定义固定POCO类:
- 遍历Schema中的所有字段,普通字段按.NET类型对应到ES的标准数据类型
- 标记为
isGeoPoint的字段明确指定为geo_point类型,标记为isGeoShape的字段明确指定为geo_shape类型
示例代码如下:
// 已定义变量:ES客户端实例 client、目标索引名 indexName、数据集Schema实例 datasetSchema var createIndexResult = await client.Indices.CreateAsync(indexName, c => c .Map(m => m .Properties(p => { foreach (var field in datasetSchema.Fields) { if (field.isGeoPoint) { p.GeoPoint(g => g.Name(field.Name)); } else if (field.isGeoShape) { p.GeoShape(g => g.Name(field.Name)); } else { // 普通字段按类型映射,示例可按需扩展 if (field.DataType == typeof(string)) { p.Text(t => t.Name(field.Name) .Keyword(k => k.Name($"{field.Name}.keyword").IgnoreAbove(256))); } else if (field.DataType == typeof(int) || field.DataType == typeof(long)) { p.Number(n => n.Name(field.Name).Type(NumberType.Long)); } else if (field.DataType == typeof(DateTime)) { p.Date(d => d.Name(field.Name)); } } } return p; }) ) );
2. 批量索引带几何属性的文档
你完全可以不用解析为NetTopologySuite的Geometry对象,只要做一步简单处理即可:
- 构造文档时,不要直接把GeoJson字符串赋值给几何字段,需要先把GeoJson字符串反序列化为动态对象/字典结构,避免ES将其识别为普通字符串
- 后续直接用
Bulk或者BulkAllAPI传入构造好的动态文档即可,NEST会自动将几何结构序列化为ES可识别的格式
示例代码如下:
using System.Dynamic; using System.Text.Json; // 构造待索引的动态文档集合,rawDataset为你的原始数据集 List<object> indexDocs = new List<object>(); foreach (var rawItem in rawDataset) { IDictionary<string, object> doc = new ExpandoObject(); foreach (var field in datasetSchema.Fields) { var rawValue = rawItem.GetFieldValue(field.Name); if (field.isGeoPoint || field.isGeoShape) { // GeoJson字符串反序列化为对象,避免直接传字符串 var geoStructure = JsonSerializer.Deserialize<object>(rawValue.ToString()); doc[field.Name] = geoStructure; } else { doc[field.Name] = rawValue; } } // 可按需指定文档Id,比如doc["Id"] = rawItem.Id indexDocs.Add(doc); } // 小数据量用Bulk即可 var bulkResult = await client.BulkAsync(b => b .Index(indexName) .IndexMany(indexDocs) ); // 大数据量推荐用BulkAll,自带重试、限流、进度回调能力 var bulkAllObserver = client.BulkAll<object>(indexDocs, b => b .Index(indexName) .Size(1000) // 每批索引的文档数,可按需调整 .BackOffRetries(3) .BackOffTime(TimeSpan.FromSeconds(10)) ); // 阻塞等待所有数据索引完成,也可以用异步回调方式处理 bulkAllObserver.Wait(TimeSpan.FromMinutes(30), batch => { // 每批索引完成的回调,可用于记录进度 });
注意事项
如果你的GeoJson格式完全符合ES的geo_point/geo_shape规范,以上方案不需要引入任何额外依赖,性能比转换为Geometry对象更高。如果碰到格式兼容问题,再考虑用NetTopologySuite做格式转换即可。
内容的提问来源于stack exchange,提问作者Florin Vârdol
相关产品推荐
相关产品推荐

