空间数据类型转化——geometry转geoJson转geoShape

在SqlServer等结构化的数据库中通常使用geometry 或者是 geoGraphy 。在数据中的类型如下:

 

.NET对其操作 通过使用EF中的DbGeometry类型进行映射,并且包含对其的多种属性和操作。基本可以满足我们通用的需求。

在EF中,该类型的定义如下:

这虽然满足,.net程序,对于空间数据的基本使用和操作。但是由于目前我们使用的数据存储服务器为ElasticSearch。其中定义空间数据包含两种类型,分别是geoShape和geoPoint两种类型。

我们想要实现数据库中空间类型 和 elasticsearch中空间类型的转化显得非常困难。因为两种类型的结构和形式完全不同。

查找多方资料,终于知道ElasticSearch是一种geoJson类型的。因此需要先将geometry转成 geoJson ,geoJson再转成geoShape。

下面是转化的步骤:

1.安装NuGet包 geoJson.net

在需要使用geoJson类型的项目,右键点击“管理NuGet程序包”,搜索geoJson.net,出现的结果中选择geoJson.net 选择安装即可。

最后在已安装的包中查看如下:

需要注意的是,geoJson依赖的newtnsoft.json的版本是7.0以上,所以很有可能和当前项目冲突。可以通过修改配置文件的版本进行解决。

2.geometry 转化成geoJSON

具体转化的代码如下,需要引用geoJson才可使用哦

using System;
using System.Data.Entity.Spatial;
using System.Linq;
using GeoJSON.Net.Geometry;
using Newtonsoft.Json;

namespace Jurassic.Sooil.Model.IOModel
{
    public class GisUtil
    {
        /**
     * 将WKT文本字符串转换为ES中的GeoShape字符串格式
     * @param wkt
     * @return
     * @throws ParseException
     */
        public static string GetEsGeoTextFromWkt(DbGeometry geo)
        {

            string result = null;
            string coordinates = null;
            var type = geo.SpatialTypeName.ToLower();

            if (type.Equals("point"))
            {
                coordinates = GetEsPointText(geo);
            }
            else
            {
                coordinates = GetEsMultiPointText(geo);
            }
            result += "{\"type\" :\"" + type + "\"" + ", \"coordinates\" :" + coordinates + "}";
            return result;
        }

        /**
     * 通过MultiPoint对象拼接中括号表示的字符串
     * @param multiPoint
     * @return
     */
        private static String GetEsMultiPointText(DbGeometry polygon)
        {
            var wkt = polygon.WellKnownValue.WellKnownText;
            var startIndex = wkt.IndexOf('(');
            var endIndex = wkt.LastIndexOf(')');
            var coordinates = wkt.Substring(startIndex, endIndex - startIndex + 1);
            var coods = coordinates.Replace('(', '[').Replace(')', ']').Split(',');
            var result = "";
            foreach (var cood in coods)
            {
               var s= cood.TrimStart().Replace(' ', ',');
                result += string.Format("[" + s + "],");
            }
            result= result.Remove(result.Length - 1);
            return result;
        }

        /**
     * 通过Point对象拼接中括号表示的字符串
     * @param point
     * @return
     */
        public static String GetEsPointText(DbGeometry point)
        {
            return "[" + point.XCoordinate + "," + point.YCoordinate + "]";
        }

        public static dynamic GetGeoJson(DbGeometry geo)
        {
            var geoText = GetEsGeoTextFromWkt(geo);
            var type = geo.SpatialTypeName.ToLower();

            switch (type)
            {
                case "point": return JsonConvert.DeserializeObject<Point>(geoText);
                case "polygon": return JsonConvert.DeserializeObject<Polygon>(geoText);
                case "multipolygon": return JsonConvert.DeserializeObject<MultiPolygon>(geoText);
                case "multilinestring": return JsonConvert.DeserializeObject<MultiLineString>(geoText);
                default: return null;
            }
        }

    }
}

调用的代码如下:

Spatial =GisUtil.GetGeoJson(DbGeometry.FromText("POLYGON ((125.718299865723 45.7559700012207, 125.700149536133 45.761962890625, 125.68383026123 45.7523498535156, 125.672470092773 45.7415008544922, 125.667694091797 45.729377746582, 125.664573669434 45.7161026000977, 125.681015014648 45.7145957946777, 125.71363067627 45.7338333129883, 125.716812133789 45.7426528930664, 125.721588134766 45.7547760009766, 125.718299865723 45.7559700012207))", 4326))


传入参数是一个DBGeometry类型的,然后输出的值是一个geoJson抽象类的一个具体实现类,因此这里返回的是一个动态类型。也可使用GeoJsonObject类型。


3.geoJson转化成geoShape

也就是说如何把转化后的数据导入到ElasticSearch中去。

非常幸运,我们做到这一步,基本就可以直接导入到ElasticSearch中去了,因为geoJson的格式和geoShape的格式是一摸一样的。

下面是bulk代码

        /// <summary>
        /// 修改数据模型模型后,导入ES的数据
        /// </summary>
        /// <param name="docs"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public async Task<string> Index(List<T> docs, string type)
        {
            var serializer = new JsonNetSerializer();
            var bulkJson =
                new BulkBuilder(serializer)
                   .BuildCollection(docs,
                   (builder, doc) => builder.Index(doc)
            );
            return await Bulk(bulkJson, type); 
        }

        /// <summary>
        /// bulk操作,根据指定的索引和类型
        /// </summary>
        /// <param name="bulkJson"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public async Task<string> Bulk(string bulkJson, string type)
        {
            if (bulkJson == null) return "索引文档为空";
            string bulkCommand = new BulkCommand(EsIndex, type);
            var result = await esClient.Post(bulkCommand, bulkJson);
            return result;
        }

4.插入结果查询

在sense中查询,插入的空间数据如下图:

通过以上步骤,就解决了ES中geoShape空间数据导入的难题。不过geometry到geojson的转化还是有些不好,需要人工去解析和转化。期待更好的解决方案!

转载自:https://blog.csdn.net/Shiyaru1314/article/details/51832998

You may also like...