ES NEST - 如何使用几何(geo_point 或 geo_shape)创建索引和批量索引动态对象?
ES NEST - How to Create an index and Bulk index dynamic objects with geometry (geo_point or geo_shape)?
我有一个数据集,我不知道或不知道其类型,也不知道属性的数量或类型。
执行时,我为该数据集获取了一个 DatasetSchema,其中包含属性的名称、类型和一些标志。
对于几何属性,我将它们的 GeoJson 表示存储为字符串,并且我有一些标志(isGeoShape、isGeoPoint)告诉 ES 属性 类型。
如果需要将这些 GeoJson 解析为实际的 Geometry 对象,我也会使用 NetTopologySuite,但我宁愿不进行这种额外的解析,而是使用 GeoJson 字符串。
class DatasetSchema {
List<DatasetField> Fields;
}
class DatasetField {
string Name;
Type DataType;
bool isGeoShape;
bool isGeoPoint;
}
问题:
如何使用具有这些几何属性的 NEST 高级客户端创建具有未知/动态映射模式的 ES 索引?
如何使用具有这些几何属性的批量或 BulkAll API 使用 NEST 高级客户端批量索引这些文档?
我看到 and here 可以使用 BulkDescriptor 完成批量索引:
dynamic obj = new System.Dynamic.ExpandoObject();
// ….
var descriptor = new BulkDescriptor();
foreach (var doc in values)
{
descriptor.Index<object>(i => i
.Index("abc")
.Id((Id)doc.Id)
.Document((object)doc));
}
client.Bulk(descriptor);
不过,我很好奇应该如何处理几何类型?
非常感谢!
欢迎任何想法或建议!
Dynamic templates 将非常适合您的用例,此功能为您提供了一种很好的方式来控制 elasticsearch 如何映射您的动态数据模式。
您可以利用 match 参数并根据字段名称控制字段类型。如果 DatasetField
的实例将 IsGeoPoint
设置为 true
,我们可以在 elasticsearch 字段名称前加上 GeoPoint 并配置动态模板为以 GeoPoint[=23] 为前缀的名称创建 goe_point
字段=]
{
"mappings": {
"dynamic_templates": [{
"geo_shape": {
"match": "GeoShape*",
"mapping": {
"type": "geo_shape"
}
}
}, {
"geo_point": {
"match": "GeoPoint*",
"mapping": {
"type": "geo_point"
}
}
}
]
}
}
这是一个示例 C# 应用程序,展示了它的实际效果
class Program
{
static async Task Main(string[] args)
{
string indexName = "my_index";
var connectionSettings = new ConnectionSettings(new Uri("http://localhost:9200"));
connectionSettings.DefaultIndex(indexName);
var elasticClient = new ElasticClient(connectionSettings);
await elasticClient.Indices.DeleteAsync(indexName);
//create index mapping with two dynamic templates,
//based on field suffix elasticsearch will map field to specific type
var indexResponse = await elasticClient.Indices.CreateAsync(indexName, d => d
.Map(map => map
.DynamicTemplates(dt => dt
.DynamicTemplate("geo_shape", gs => gs.Match("GeoShape*").Mapping(m => m.GeoShape(s => s)))
.DynamicTemplate("geo_point", gs => gs.Match("GeoPoint*").Mapping(m => m.GeoPoint(p => p)))
)));
//some same data matching your schema
var data = new List<DatasetField>
{
new () { Name = "Field1", IsGeoPoint = true },
new () { Name = "Field2", IsGeoShape = true },
};
var document = new EsDocument();
foreach (var datasetField in data)
{
//if the field is of type geo shape, prefix field name with GeoShape,
//geo_shape dynamic template will match field name and will create geo_point type for it
if (datasetField.IsGeoShape)
{
document.Add($"GeoShape{datasetField.Name}", new PointGeoShape(new GeoCoordinate(0, 0)));
}
//if the field is of type geo point, prefix field name with GeoPoint,
//geo_point dynamic template will match field name and will create geo_shape type for it
if (datasetField.IsGeoPoint)
{
document.Add($"GeoPoint{datasetField.Name}", new GeoLocation(0, 0));
}
}
var response = await elasticClient.IndexDocumentAsync(document);
}
//this class is just an alias to dictionary
class EsDocument : Dictionary<string,object>{}
class DatasetField
{
public string Name { get; set; }
public bool IsGeoShape { get; set; }
public bool IsGeoPoint { get; set; }
}
}
这将产生以下 elasticsearch 映射
{
"my_index": {
"mappings": {
"dynamic_templates": [{
"geo_shape": {
"match": "GeoShape*",
"mapping": {
"type": "geo_shape"
}
}
}, {
"geo_point": {
"match": "GeoPoint*",
"mapping": {
"type": "geo_point"
}
}
}
],
"properties": {
"GeoPointField1": {
"type": "geo_point"
},
"GeoShapeField2": {
"type": "geo_shape"
}
}
}
}
}
对于批量索引文档,最简单的方法是使用IndexManyAsync
扩展方法
await elasticClient.IndexManyAsync(new List<EsDocument>());
另请查看 this blog post 详细描述了索引多个文档。检查“多个文档”部分。
更新:将新的动态模板添加到具有现有动态模板的映射中
var map = (await elasticClient.Indices.GetMappingAsync<EsDocument>()).Indices["your_index_name"];
var dynamicTemplates = map.Mappings.DynamicTemplates;
//add new
dynamicTemplates.Add(new KeyValuePair<string, IDynamicTemplate>());
await elasticClient.Indices.PutMappingAsync(new PutMappingRequest("your_index_name") { DynamicTemplates = dynamicTemplates });
我有一个数据集,我不知道或不知道其类型,也不知道属性的数量或类型。
执行时,我为该数据集获取了一个 DatasetSchema,其中包含属性的名称、类型和一些标志。
对于几何属性,我将它们的 GeoJson 表示存储为字符串,并且我有一些标志(isGeoShape、isGeoPoint)告诉 ES 属性 类型。
如果需要将这些 GeoJson 解析为实际的 Geometry 对象,我也会使用 NetTopologySuite,但我宁愿不进行这种额外的解析,而是使用 GeoJson 字符串。
class DatasetSchema {
List<DatasetField> Fields;
}
class DatasetField {
string Name;
Type DataType;
bool isGeoShape;
bool isGeoPoint;
}
问题:
如何使用具有这些几何属性的 NEST 高级客户端创建具有未知/动态映射模式的 ES 索引?
如何使用具有这些几何属性的批量或 BulkAll API 使用 NEST 高级客户端批量索引这些文档?
我看到
dynamic obj = new System.Dynamic.ExpandoObject();
// ….
var descriptor = new BulkDescriptor();
foreach (var doc in values)
{
descriptor.Index<object>(i => i
.Index("abc")
.Id((Id)doc.Id)
.Document((object)doc));
}
client.Bulk(descriptor);
不过,我很好奇应该如何处理几何类型?
非常感谢! 欢迎任何想法或建议!
Dynamic templates 将非常适合您的用例,此功能为您提供了一种很好的方式来控制 elasticsearch 如何映射您的动态数据模式。
您可以利用 match 参数并根据字段名称控制字段类型。如果 DatasetField
的实例将 IsGeoPoint
设置为 true
,我们可以在 elasticsearch 字段名称前加上 GeoPoint 并配置动态模板为以 GeoPoint[=23] 为前缀的名称创建 goe_point
字段=]
{
"mappings": {
"dynamic_templates": [{
"geo_shape": {
"match": "GeoShape*",
"mapping": {
"type": "geo_shape"
}
}
}, {
"geo_point": {
"match": "GeoPoint*",
"mapping": {
"type": "geo_point"
}
}
}
]
}
}
这是一个示例 C# 应用程序,展示了它的实际效果
class Program
{
static async Task Main(string[] args)
{
string indexName = "my_index";
var connectionSettings = new ConnectionSettings(new Uri("http://localhost:9200"));
connectionSettings.DefaultIndex(indexName);
var elasticClient = new ElasticClient(connectionSettings);
await elasticClient.Indices.DeleteAsync(indexName);
//create index mapping with two dynamic templates,
//based on field suffix elasticsearch will map field to specific type
var indexResponse = await elasticClient.Indices.CreateAsync(indexName, d => d
.Map(map => map
.DynamicTemplates(dt => dt
.DynamicTemplate("geo_shape", gs => gs.Match("GeoShape*").Mapping(m => m.GeoShape(s => s)))
.DynamicTemplate("geo_point", gs => gs.Match("GeoPoint*").Mapping(m => m.GeoPoint(p => p)))
)));
//some same data matching your schema
var data = new List<DatasetField>
{
new () { Name = "Field1", IsGeoPoint = true },
new () { Name = "Field2", IsGeoShape = true },
};
var document = new EsDocument();
foreach (var datasetField in data)
{
//if the field is of type geo shape, prefix field name with GeoShape,
//geo_shape dynamic template will match field name and will create geo_point type for it
if (datasetField.IsGeoShape)
{
document.Add($"GeoShape{datasetField.Name}", new PointGeoShape(new GeoCoordinate(0, 0)));
}
//if the field is of type geo point, prefix field name with GeoPoint,
//geo_point dynamic template will match field name and will create geo_shape type for it
if (datasetField.IsGeoPoint)
{
document.Add($"GeoPoint{datasetField.Name}", new GeoLocation(0, 0));
}
}
var response = await elasticClient.IndexDocumentAsync(document);
}
//this class is just an alias to dictionary
class EsDocument : Dictionary<string,object>{}
class DatasetField
{
public string Name { get; set; }
public bool IsGeoShape { get; set; }
public bool IsGeoPoint { get; set; }
}
}
这将产生以下 elasticsearch 映射
{
"my_index": {
"mappings": {
"dynamic_templates": [{
"geo_shape": {
"match": "GeoShape*",
"mapping": {
"type": "geo_shape"
}
}
}, {
"geo_point": {
"match": "GeoPoint*",
"mapping": {
"type": "geo_point"
}
}
}
],
"properties": {
"GeoPointField1": {
"type": "geo_point"
},
"GeoShapeField2": {
"type": "geo_shape"
}
}
}
}
}
对于批量索引文档,最简单的方法是使用IndexManyAsync
扩展方法
await elasticClient.IndexManyAsync(new List<EsDocument>());
另请查看 this blog post 详细描述了索引多个文档。检查“多个文档”部分。
更新:将新的动态模板添加到具有现有动态模板的映射中
var map = (await elasticClient.Indices.GetMappingAsync<EsDocument>()).Indices["your_index_name"];
var dynamicTemplates = map.Mappings.DynamicTemplates;
//add new
dynamicTemplates.Add(new KeyValuePair<string, IDynamicTemplate>());
await elasticClient.Indices.PutMappingAsync(new PutMappingRequest("your_index_name") { DynamicTemplates = dynamicTemplates });