本文已参与「新人创作礼」活动,一起开启掘金创作之路。
最近在做数据可视化的时候,提到了一种 GeoJSON 格式的数据,在此进行一下梳理。
1 简介
GeoJSON是一种对各种地理数据结构进行编码的格式。GeoJSON对象可以表示几何、特征或者特征集合。GeoJSON支持下面几何类型:点、线、面、多点、多线、多面和几何集合。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。
一个完整的GeoJSON数据结构总是一个(JSON术语里的)对象。在GeoJSON里,对象由名/值对--也称作成员的集合组成。
例:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "value0"
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0],
[103.0, 1.0],
[104.0, 0.0],
[105.0, 1.0]
]
},
"properties": {
"prop0": "value0",
"prop1": 0.0
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
},
"properties": {
"prop0": "value0",
"prop1": {
"this": "that"
}
}
}
]
}
2 GeoJSON 对象
GeoJSON总是由一个单独的对象组成。这个对象(指的是下面的GeoJSON对象)表示几何、特征或者特征集合。
- GeoJSON对象可能有任何数目成员(名/值对)。
- GeoJSON对象必须由一个名字为"type"的成员。这个成员的值是由GeoJSON对象的类型所确定的字符串。
- type成员的值必须是下面之一:"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "GeometryCollection", "Feature", 或者 "FeatureCollection"。
- GeoJSON对象可能有一个可选的"crs"成员,它的值必须是一个坐标参考系统的对象。
- GeoJSON对象可能有一个"bbox"成员,它的值必须是边界框数组。
可以在 geojson.io 查看效果
2.1 几何对象
几何是一种GeoJSON对象,这时type成员的值是下面字符串之一:"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", 或者"GeometryCollection"。
除了“GeometryCollection”外的其他任何类型的GeoJSON几何对象必须由一个名字为"coordinates"的成员。coordinates成员的值总是数组。这个数组里的元素的结构由几何类型来确定。
2.1.1 点 Point
{
"type": "Point",
"coordinates": [100.0, 0.0]
}
2.1.2 多点 MultiPoint
{
"type": "MultiPoint",
"coordinates": [
[100, 0],
[101, 1]
]
}
2.1.3 线 LineString
{
"type": "LineString",
"coordinates": [
[100, 0],
[101, 1]
]
}
2.1.4 多线 MultiLineString
{
"type": "MultiLineString",
"coordinates": [
[ [100.0, 0.0], [101.0, 1.0] ],
[ [102.0, 2.0], [103.0, 3.0] ]
]
}
2.1.5 多边形 Polyon
无孔的
{
"type": "Polygon",
"coordinates": [
[
[ 100, 0 ],
[ 101, 0 ],
[ 101, 1 ],
[ 100, 1 ],
[ 100, 0 ]
]
]
}
有孔的
{
"type": "Polygon",
"coordinates": [
[
[ 100, 0 ],
[ 101, 0 ],
[ 101, 1 ],
[ 100, 1 ],
[ 100, 0 ]
],
[
[ 100.2, 0.2 ],
[ 100.8, 0.2 ],
[ 100.8, 0.8 ],
[ 100.2, 0.8 ],
[ 100.2, 0.2 ]
]
]
}
2.1.6 复合多边形 MultiPolyon
不相交的多边形
{
"type": "MultiPolygon",
"coordinates": [
[
[
[109.2041015625, 30.088107753367257],
[115.02685546875, 30.088107753367257],
[115.02685546875, 32.7872745269555],
[109.2041015625, 32.7872745269555],
[109.2041015625, 30.088107753367257]
]
],
[
[
[112.9833984375, 26.82407078047018],
[116.69677734375, 26.82407078047018],
[116.69677734375, 29.036960648558267],
[112.9833984375, 29.036960648558267],
[112.9833984375, 26.82407078047018]
]
]
]
}
两个嵌套的多边形
{
"type": "MultiPolygon",
"coordinates": [
[
[
[101.6455078125, 27.68352808378776],
[114.78515624999999, 27.68352808378776],
[114.78515624999999, 35.209721645221386],
[101.6455078125, 35.209721645221386],
[101.6455078125, 27.68352808378776]
]
],
[
[
[104.2822265625, 30.107117887092357],
[108.896484375, 30.107117887092357],
[108.896484375, 33.76088200086917],
[104.2822265625, 33.76088200086917],
[104.2822265625, 30.107117887092357]
]
]
]
}
有孔洞的多边形
{
"type": "MultiPolygon",
"coordinates": [
[
[
[101.6455078125, 27.68352808378776],
[114.78515624999999, 27.68352808378776],
[114.78515624999999, 35.209721645221386],
[101.6455078125, 35.209721645221386],
[101.6455078125, 27.68352808378776]
],
[
[104.2822265625, 30.107117887092357],
[108.896484375, 30.107117887092357],
[108.896484375, 33.76088200086917],
[104.2822265625, 33.76088200086917],
[104.2822265625, 30.107117887092357]
]
]
]
}
2.1.7 几何集合 GeometryCollection
是多种基本地理要素的集合,就是里面可以包含点、线、面要素
{
"type": "GeometryCollection",
"geometries": [{
"type": "Point",
"coordinates": [108.62, 31.02819]
}, {
"type": "LineString",
"coordinates": [
[108.896484375, 30.1071178870],
[108.2184375, 30.91717870],
[109.5184375, 31.2175780]
]
}]
}
2.2 特征对象
- 类型为 Feature 的 GeoJSON 对象是特征对象
- 特征对象必须由一个名字为"geometry"的成员,这个几何成员的值是上面定义的几何对象或者JSON的null值。
- 特征对戏那个必须有一个名字为“properties"的成员,这个属性成员的值是一个对象(任何JSON对象或者JSON的null值)
{
"type":"Feature",
"properties":{},
"geometry":{ "type": "Point", "coordinates": [100.0, 0.0] }
}
2.3 特征集合对象
- 特征集合对象type为FeatureCollection。
- 特征集合对象必须由一个名字为"features"的成员。与“features"相对应的值是一个数组。这个数组中的每个元素都是上面定义的特征对象。
{
"type": "FeatureCollection",
"features": []
}
3 在各个数据库中的应用
3.1 mysql
1 geometry 类型
MySQL提供了数据类型geometry用来存储坐标信息,geometry类型支持以下三种数据存储
| 数据结构 | 示例 | 说明 |
| POINT(点) | POINT(113.3 40.08) | 用于存储点位信息,包含经纬度信息 |
| LINESTRING(线) | LineString(84.070 33.801,99.52 30.292) | 用来存储路线信息 |
| POLYGON(面) | POLYGON((84.070 33.801, 84.100 33.801,84.070 33.801)) | 用来存储面数据 |
2 格式化空间数据类型
数据库存储的空间数据通过可视化工具展示的明文结构为上面示例中所见,结构并不易于客户端解析,所以MySQL提供了几个空间函数用来解析及格式化空间数据,geojson是gis空间数据展示的标准格式,前端地图框架及后端空间分析相关框架都会支持geojson格式
| 操作 | 函数 |
| geojson -> geometry | ST_GeomFromGeoJSON |
| geometry -> geojson | ST_ASGEOJSON |
| geometry字符串 -> geometry | ST_GEOMFROMTEXT |
3 示例
新建表
CREATE TABLE `geojson` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`geojson` geometry NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
插入数据
insert into geojson(geojson) VALUES (ST_GeomFromGeoJSON('{"type": "Point", "coordinates": [121.0, 31.0]}'));
查询
select id,ST_AsGeoJSON(geojson) as geojson from geojson;
常用的空间函数
| 名称 | 描述 |
| ST_INTERSECTS() | 判断两个几何是否相交 |
| ST_DISTANCE() | 两个几何的距离 |
| ST_CONTAIONS() | 几何是否包含 |
| ST_ISVALID() | 几何是否有效 |
| ST_WITHIN() | 几何是否在里面,结果与ST_CONTAIONS()相反 |
SELECT
id,
ST_AsGeoJSON ( geojson ) AS geojson
FROM
geojson
WHERE
ST_CONTAINS (
ST_GeomFromText ( 'POLYGON((100 30,120 30,120 36,100 36,100 30))' ),
geojson
)
3.2 mongodb
1 支持地理空间索引
-
2dsphere 索引
- 用于地球表面类型的地图上
- 可以使用在 Legacy Coordinate Paris 保存的经纬度字段上和使用 GeoJSON 格式保存的点、线、多边形字段上
db.world.ensureIndex({"geometry" : "2dsphere"})
-
2d 索引
- 对于非球面(游戏地图,时间连续的数据等),可以使用 2d 索引代替 2dsphere
- 支持平面查询和一些球形查询,但是球形支持不是很好
- 只能对点进行索引
2 支持地理空间查询
主要支持 交集(intersection),包含(within),以及接近(nearness)
-
$geoIntersects
-
指出与查询位置相交的文档
-
支持操作符
- $geometry 指定 GeoJSON 格式的几何图形
-
-
$geoWithin
-
指出完全包含在某个区域的文档
-
支持操作符
-
$box
- 查出矩形范围内的所有文档
-
$center
- 查出圆形范围内的所有文档
-
$polygon
- 查出多边形范围内的所有文档
-
$centerSphere
- 查询出球面圆形范围内的所有文档
-
$geometry
- 指定 GeoJSON 格式的几何图形
-
-
-
$near
-
指出与查询位置从最近到最远的文档
-
支持操作符
-
$maxDistance
- 指定查询结果的最大距离
-
$minDistance
- 指定查询结果的最小距离
-
$geometry
- 指定 GeoJSON 格式的点
-
-
-
$nearSphere
-
使用球面几何计算近球面的距离,指出与查询位置从最近到最远的文档
-
支持操作符
-
$maxDistance
- 指定查询结果的最大距离
-
$minDistance
- 指定查询结果的最小距离
-
$geometry
- 指定 GeoJSON 格式的点
-
-
查询位置相交的文档
db.getCollection('GeoEntity').find({
location: {
$geoIntersects: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 30, 20 ], [ 30, 40 ], [ 40, 40 ],[ 40, 20 ],[ 30, 20 ]]
]
}
}
}
})
查询交叉位置的文档
db.getCollection('GeoEntity').find({ location: { $geoWithin: { $box: [ [ 30, 30 ], [ 32, 33 ]] } } })
3.3 redis
1 地理空间命令
-
geoadd
- geoadd key longitude latitude member [ longitude latitude member ... ]
- 将指定的空间元素添加到指定的 key 里
-
geodist
- geodist key member1 member2 [ unit ]
- unit 代表单位
- 返回指定位置之间的距离
-
geohash
- geohash key member [ member ... ]
- 返回一个标准的地理空间的 geohash 字符串
-
geopos
- geopos key member [ member ... ]
- 返回地理空间的经纬度
-
georadius
- georadius key longitude latitude radius m|km|ft|mi [ WITHCOORD ] [ WITHDIST ] [ WITHHASH ] [ COUNT count ]
- 查询指定半径范围内所有地理空间元素的集合
- longitude 经度
- latitude 纬度
- radius 半径距离数
- WITHDIST 将位置元素的中心之间的距离也一并返回
- WITHCOORD 将位置元素的经度和纬度也一并返回
- WITHHASH 以 52 位有符号整数的形式返回
- COUNT 返回所有匹配位置前 count 元素
-
georadiusbymember
- georadiusbymember key member radius m|km|ft|mi [ WITHCOORD ] [ WITHDIST ] [ WITHHASH ] [ COUNT count ]
- 查询指定半径内匹配到的最大距离的一个地理空间元素