Skip to content

空间关系

有时业务里需要显示特定范围的数据(点, 线, 面等, 一般都是点, 比如警情五公里内的监控探头), 具体的如下图:

查询在特定范围内的数据我们称之为 空间查询

总体原则

  • 数据量大要在服务端做
  • 数据量小的可以在前端做, 数据量一般不超过1w条
  • 查询的图形一般为圆或者任意多边形

前端查询

就是一次性加载所有的数据, 然后计算哪些数据落在这个图形边界内, 点在圆内,点在多边形内等. 常用的库有:

业务很简单的情况下推荐使用 geolib ,因为其很简单和小巧,比如查询圆内的落点, 针对 turfjs 我们也做了个简单的封装, 详情请查看 插件目录里的yymap.turf

简单的示例代码:

js
const center = [120, 31], //圆的中心点
    radius = 1000; //半径
//geolib
const result = data.filter(d => {
    return YY.geolib.getDistance(d.lnglat, center) <= radius;
});
// result 就是圆内的数据

//turfjs
const centerPoint = new YY.Point(center);

const result = data.filter(d => {
    return YY.Turf.distance(new YY.Point(d.lnglats), centerPoint) <= radius;
})

警告

再次强调该方法仅适用于数据量小的情况

服务端查询

服务端地理数据常见的存储方式:

  • 数据库直接存地理数据(推荐):数据库层面一般数据库都支持 空间查询 , 比如PostgreSQL(PostGIS), SQL SERVER , ORCALDB 等。 数据库层面的 空间查询 需要你的数据以空间数据结构的方式存储, 如果你的数据就是这样存储的, 那么你可以直接利用数据库提供的原生函数来进行 空间查询

警告

如果你的业务强烈的这种需求,推荐PostgreSQL(PostGIS) 作为你们的数据库

  • elasticsearch 直接存地理数据: 如果你的业务里有使用elasticsearch, 你也可以使用elasticsearch来存储地理数据并提供查询服务query shape

警告

注意不能为了用而用, 根据自己的业务的真实需求进行技术选型, 毕竟数据库和elasticsearch的数据同步也是个头疼问题

  • 以普通的关系数据库存数据:可能都是因为一些历史原因导致的, 或者你的业务不是强GIS, 即使这么做也可以完成业务需求, 这个存储方式需要搭配 JTS 来进行空间计算

警告

如果你的业务数据是 数据请把经纬度拆开存储, 比如分成两个字段 lng , lat , 方面在 SQL 层面根据范围来查询,这样就不用查询所有数据了和业务里进行大量的空间关系计算了

sql
//示例代码
select * from tablename wheren lng>=minx and lng<= maxx and lat>=miny and lat<=maxy

服务端常用的工具库有:

各种方案对比表:

方案优点缺点适用场景
数据库直接存地理数据数据库直接原生支持空间查询, 无需写业务代码, 直接在SQL层面就可以了业务里对数据库的增删改查都需要构造地理结构, 相对来说业务工作量变大了常规需求, 一般系统都是这么设计和技术选型
elasticsearch直接存地理数据elasticsearch支持空间查询, 且速度比较快需要维护一个elasticsearch, 还有elasticsearch和数据库数据同步的问题大规模的地理数据查询服务
以普通的关系数据库存数据数据的存储比较简单,业务代码比较简单, 无需要构造各种地理结构进行增删改查一般都需要把所有数读入内存来进行计算, 数据量大了,业务里容易把数据库拖死或者业务里内存溢出地理数据服务不强, 数据量不大的情况

服务端接口设计上

一般是提供 lnglats , radius 两个参数,分别表示中心点和半径, 前端提供这两个参数给服务端,服务端返回对应的结果给前端(点在圆内,点在多边形内等.)

js
 ip: port / xxxxx / xxx ? lnglats = 120, 31 & radius = 5

建议

TIP

建议空间数据最好存在空间数据库里, 当然如果你的业务不是强GIS的或者因为一些其他的原因等还是保留原来的方式, 可能原因:

  • 业务里对地理数据需求不强烈,简单的数据存储已经能满足业务需求
  • 由于一些历史原因和兼容性不能随便切换数据库

This document is generated by vitepress and Edit by deyihu