问题描述
总结
我想使用来自 GeoJson 文件或字符串的 C#、GeoShape 和 ElasticSearch 在 Nest 中正确索引(摄取)地理数据(Geometry、GeometryCollection)为 NetTopologySuite (NTS)表示。
我正在使用以下堆栈: 弹性搜索 7.10.1 巢 7.10.1 网络拓扑套件 2.1.0 NetTopologySuite.IO.GeoJSON 2.0.4
在 my GitHub GIST 中,您可以找到两个示例文件(postal-area.geojson 和 geojson 文件作为场景 #7 的示例)以及下面提供的代码,以及我迄今为止尝试过的代码。
我的尝试
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using Bogus.DataSets;
using Elasticsearch.Net;
using ElasticSearch;
using GeoAPI.Geometries;
using Microsoft.Extensions.Configuration;
using nest;
using nest.JsonNetSerializer;
using NetTopologySuite.Features;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NetTopologySuite.IO;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO.Converters;
using Newtonsoft.Json.Converters;
using Coordinate = NetTopologySuite.Geometries.Coordinate;
using GeometryCollection = NetTopologySuite.Geometries.GeometryCollection;
private static void Main()
{
try {
var defaultIndex = "my_shapes";
string cloudId = "cloudId";
string username = "username";
string password = "password";
var credentials = new BasicAuthenticationCredentials(username,password);
//var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200"));
var pool = new CloudConnectionPool(cloudId,credentials);
var settings = new ConnectionSettings(pool,(c,s) =>
new JsonNetSerializer(c,s,contractJsonConverters: new JsonConverter[]
{
new AttributesTableConverter(),new CoordinateConverter(),new EnvelopeConverter(),new FeatureConverter(),new FeatureCollectionConverter(),new GeometryConverter(),new GeometryArrayConverter(),new StringEnumConverter()
}))
.DefaultIndex(defaultIndex)
.disableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails => {
if (callDetails.RequestBodyInBytes != null) {
var json = JObject.Parse(Encoding.UTF8.GetString(callDetails.RequestBodyInBytes));
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{json.ToString(Newtonsoft.Json.Formatting.Indented)}");
}
else {
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null) {
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-',30)}\n");
}
else {
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-',30)}\n");
}
});
var client = new Elasticclient(settings);
var createIndexResponse = client.Indices.Create(defaultIndex,c => c
.Map<MyDocument>(m => m
.Properties(p => p
.GeoShape(g => g
.Name(n => n.Geometry)
)
)
)
);
if (!createIndexResponse.IsValid) {
throw new Exception($"Error creating index: {createIndexResponse.Debuginformation}");
}
IndexResponse indexResponse;
MyDocument document;
Geometry geometrypolygon;
FeatureCollection featureCollection;
//Working Scenario #1: Geometry from mock polygon -------------------works!!!!!!!!!!!
var polygon = new polygon(new LinearRing(new [] {
new Coordinate(0,0),new Coordinate(0,4),new Coordinate(4,0)
}));
document = new MyDocument(1,polygon);
indexResponse = client.IndexDocument(document);
//End of Scenario #1 -------------------
//Working Scenario #2: Geometry from FeatureCollection from real GeoJson file ------------------- works
var geojsonFileName = @"..\..\..\_GeoDataFiles\GeoJSONs\PostalArea.geojson";
var jsonData = File.ReadAllText(geojsonFileName);
featureCollection = new GeoJsonReader().Read<FeatureCollection>(jsonData);
if (featureCollection == null) return;
var geometry = featureCollection[0].Geometry;
document = new MyDocument(1,geometry);
indexResponse = client.IndexDocument(document);
//End of Scenario #2-------------------
//NOT Working Scenario #3: Geometry deserialized (with GeoJsonSerializer) from mock GeoJson string -------------------
//excluded coordinates arrays for clarity
var geoJsonpolygonStr1 = "{\"type\":\"polygon\",\"coordinates\":[ ... ]}";
var serializer = new NetTopologySuite.IO.GeoJsonSerializer();
using(var stringReader = new StringReader(geoJsonpolygonStr1))
using (var jsonReader = new JsonTextReader(stringReader))
{
/*Error:
{"Could not create an instance of type NetTopologySuite.Geometries.Geometry.
Type is an interface or abstract class and cannot be instantiated.
Path 'type',line 2,position 8."}*/
geometrypolygon = serializer.Deserialize<Geometry>(jsonReader);
}
document = new MyDocument(1,geometrypolygon);
indexResponse = client.IndexDocument(document);
//End of Scenario #3 -------------------
//NOT Working Scenario #4: Geometry deserialized (with JsonConvert) from mock GeoJson string -------------------
//excluded coordinates arrays for clarity
var geoJsonpolygonStr2 = "{\"type\":\"polygon\",\"coordinates\":[ ... ]}";
/*Error:
{"Could not create an instance of type NetTopologySuite.Geometries.Geometry.
Type is an interface or abstract class and cannot be instantiated.
Path 'type',position 8."}*/
geometrypolygon = JsonConvert.DeserializeObject<Geometry>(geoJsonpolygonStr2);
document = new MyDocument(1,geometrypolygon);
indexResponse = client.IndexDocument(document);
//End of Scenario #4 -------------------
//NOT Working Scenario #5: GeometryCollection deserialized (with JsonConvert) from mock GeoJson string -------------------
var geoCollectionMock =
@"{""type"": ""geometrycollection"",""geometries"": ["
+ geoJsonpolygonStr1 +
","
+ geoJsonpolygonStr2 +
@"]
}";
/*Error:
{"Could not create an instance of type NetTopologySuite.Geometries.Geometry.
Type is an interface or abstract class and cannot be instantiated.
Path 'type',position 8."}*/
geometrypolygon = JsonConvert.DeserializeObject<Geometry>(geoCollectionMock);
document = new MyDocument(1,geometrypolygon);
indexResponse = client.IndexDocument(document);
//End of Scenario #5 -------------------
//Weired Scenario #6: GeometryCollection built from multiple Geometry objects from FeatureCollection from real GeoJson file -------------------
//Data ingested into ElasticSearch Index,BUT,polygons from GeometryCollection can't be seen on Kibana Maps as other simple polygons can be seen
var geoCollectionObj = new NetTopologySuite.Geometries.GeometryCollection(new[]
{
featureCollection[0].Geometry,featureCollection[1].Geometry,featureCollection[2].Geometry
});
document = new MyDocument(1,geoCollectionObj);
indexResponse = client.IndexDocument(document);
//End of Scenario #6 -------------------
//Not working Scenario #7: Geometry from FeatureCollection from real GeoJson file - invalid Geometry -------------------
var isValid = featureCollection[0].Geometry.IsValid;//= false
/*Error:
"type" : "mapper_parsing_exception","reason" : "Failed to parse field [geometry] of type [geo_shape]","caused_by" : {
"type" : "invalid_shape_exception","reason" : "Self-intersection at or near point [-3.173,57.545]"
}*/
document = new MyDocument(99,featureCollection[99].Geometry);
indexResponse = client.IndexDocument(document);
//End of Scenario #7 -------------------
if (!indexResponse.IsValid) {
throw new Exception($"Error indexinf document: {indexResponse.Debuginformation}");
}
}
catch (Exception ex)
{
Console.WriteLine($"General error: {ex}");
}
}
public class MyDocument {
public MyDocument(int id,Geometry geometry) {
Id = id;
Geometry = geometry;
}
public int Id { get; set; }
public Geometry Geometry { get; set; }
}
这是来自 my GitHub GIST 的 GeoJson 文件,用作场景 #7 的示例。貌似有效,其他平台显示(GitHub mapBox地图预览、QGIS、geojson.io)
问题
- 关于不工作的场景(#3、#4、#5)如何将 GeoJson 字符串反序列化为 Geometry 对象?
- 关于场景 #6,为什么 GeometryCollection 数据在 Kibana Map 上不像简单的几何(多边形)那样可见?
- 2.1.不知道它是否相关,但是在 Kibana 地图上拖动和缩放时,我在浏览器 JS 控制台中收到此错误:
message: "Input data given to 'cfe5e9a5-de63-4beb-85b2-4b67ad455ae9' is not a valid GeoJSON object."_ proto _: Object overrideMethod @ react_devtools_backend.js:2430 Ut.fire @ maps.chunk.1.js:31```
- 2.1.不知道它是否相关,但是在 Kibana 地图上拖动和缩放时,我在浏览器 JS 控制台中收到此错误:
- 将 ElasticSearch geoshape 作为多个单独的 Geometry 对象(单个文档中的多边形)而不是一个 GeometryCollection(单个文档中的多边形)摄取有什么区别和优缺点?
- 关于场景 #7,为什么有些几何图形似乎无效?
免责声明/其他说明
代码是从RussCam的GIST复制和改编的。
可在此 StackOverflow Chat room 中找到有关此主题的初步讨论。
当前代码可能对正在尝试此操作并从 RussCam 的旧 example 和 article 开始的其他人有用。
代码是从我的源文件中提取的,所以如果你发现一些错别字,请多多包涵。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)