sqlite 可视化_千万级poi点可视化方案

本文使用 Zhihu On VSCode 创作并发布

这篇文章主要对前段时间的两千万个点数据可视化展示问题进行一个总结,经过两个周左右的努力,在当前阶段,采用缓存加多线程的方式很好的解决了千万级poi点在单机环境下高效的可视化的问题。

技术探究

项目的总体要求就是,两千万左右的数据量下,不使用集群技术,减少硬件成本,找到合理的高效的数据展示方案,前端浏览不能卡顿。我们的数据在地理空间分布上集中于广东、深圳区域,也就是大约覆盖一个省的空间范围,数据点分布较为集中。
在面临千万级数据量下,如果以栅格瓦片的方式将数据发布为服务,这也是没问题的,但是栅格瓦片不能进行交互。既然栅格瓦片不行,那就试试矢量瓦片吧。
于是,笔者一开始是打算用矢量瓦片去解决这个问题的。个人理解,矢量瓦片的特点主要集中于两点,一是在栅格瓦片的基础上,将栅格瓦片中金字塔分级组织数据的方式应用到矢量数据中,以分级金字塔的方式组织矢量数据;二是在前后端数据传输中采用的数据压缩方案,比如mapbox 提出的Mapbox Vector Tiles格式的瓦片方案。那么,接下来,就是如何利用生成矢量瓦片了。
个人对矢量瓦片的生成技术总结如下图所示,总体可以分为预切片与实时切片两种。预切片的含义时,借助切片工具来,提前生成、组织好瓦片,提供瓦片服务给前端。实时切片的含义是在前端发起瓦片请求后,后端服务去动态的生成瓦片数据,返回给前端渲染。实时切片技术所带来的好处就是,数据可以实时更新,对原始数据进行修改后,无需再重新进行切片工作,可以直接在瓦片中看见变化了的数据。而如果采用预切片技术,就必须重新进行切片,发布切片服务后才能查看数据的最新变化。

98ca3010bf5583e6553f47ab5f24bae8.png
图1 矢量瓦片生成方案

在预切片中,我们有两种技术方案。第一是采用geoserver(arcgis server等商业软件也具备这样的能力)进行数据切片,服务发布工作,然后前端通过leaflet、openlayers 等gis框架就可直接加载矢量瓦片服务。第二种方案分为两步,首先采用Tippecanoe(mapbox 开源的矢量切片工具,支持geojson、csv等多种数据格式) 等切片工具,将原始数据转换为切片文件,其中切片文件可以以瓦片文件目录的方式进行组织,或者以Mbtiles(mapbox 开源的,以sqlite数据库方式存储瓦片的方案) 格式进行组织。然后使用node、go 等搭建静态瓦片服务器,处理前端瓦片请求,其整个过程如下图所示。

258d2317e7699d0fa09d997b283e9434.png
预切片方案
在第二种方案中,其优势就是借助node、go 的高并发能力,提供高并发的瓦片请求处理能力,具体实践方案和效果可以参加这篇文章 https://www. cnblogs.com/weiqingfeng /p/9590983.html

在实时瓦片生成方案下,在不采用大数据组件的方案下,我们可以借助postgis 去动态的生成mvt格式的矢量瓦片,详细的过程可以参见另一篇文章。 https://zhuanlan.zhihu.com/p/156887308

在笔者实验之后,在500万的数据量下,使用geoserver 发布矢量瓦片,进行浏览就已经很卡顿了。所以简单使用geoserver来解决目前的问题是行不通的。而且,在笔者的实践中发现,对于poi数据的切片其实并没有进行多层次细节的处理,后端响应的是当前前端空间范围内所有的点数据,并没有根据缩放级别去进行细节抽稀等处理。这可能就是poi点展示和线、面等数据的不同,在线、面数据中,我们可以使用道格拉斯-普克算法 等算法来根据不同的层级进行数据抽稀,但是对于单个poi点只有有无之分,并没有减少数据量的说法。除此之外,在poi点的数据展示中,我们一次性加载展示所有的数据点其实是没有意义的,密密麻麻的数据点只会给人造成密集恐惧症,对数据展示并没有任何实质性的帮助。

前端展示方案

在对千万级poi点的前端展示方案上,我们采取的总的思路是进行分级别显示,在高层(也就是缩放层级较高,zoom=0为最高)时使用热力图、聚集图等数据概览、统计的方式进行数据展示。当用户缩放到低层后,此时给用户展示真实的点数据。
热力图带来的好处是,你可以通过颜色的深浅来判断数据的分布趋势,但是效果的好坏其实是和你后端统计的数据息息相关的。

ee220a0c3204034017e67c793fbee936.png
热力图
聚集图是我认为另一种比较好的展示方式,如下图所示,聚集图带来的好处是,你可以通过数字直观的看见区域内的数据分布。但是,就我近期查阅的资料来看,聚集图都是在前端进行数据聚集后产生的效果,在一两万的数据量下,产生聚集图应该是没什么问题的,但是不适用于大规模的数据展示。

62c41f605ebeda1b355868bd545bb7be.png
聚集图

最终,我们选用的是通过格网划分的方式进行数据展示。在高层,通过格网的颜色深浅和格网内数量来进行数据展示。当用户缩放到低层后,我们直接加载点数据。

0e9b612a4aa235bf9a074977f77802ba.png
格网展示效果图

后端处理方案

在这个方案中,后端服务主要有两个功能,第一是在高层缩放级别时,处理前端的格网请求,返回格网的空间范围和要素数量。第二是在低层缩放级别时,处理前端的要素请求,返回当前视野内所有的poi点要素。如下图所示,在数据处理的过程中,我们的格网是需要根据前端的缩放级别和视野范围进行动态变化的。

d77b2e92ef42547607072fc3fc6999d3.png
格网动态变化
为了支撑前端的数据展示,我们后端需要解决两个问题。
  1. 格网和要素统计
  2. 高并发请求处理

格网要素统计主要是为我们的格网展示服务,我们必须获生成格网和相应的要素数量。同时,在用户进行缩放和移动过程中,前端会发起大量的数据请求。而且,即使只展示格网,我们需要传递的格网数据依旧很大。在动态的生成格网的过程中,我们有大量的空间查询操作。在千万级别的数据下进行空间查询是很耗时的操作。只有减少后端的请求处理时间,我们才能保证请求不超时,浏览不卡顿。

解决这个问题的办法是使用geohash算法,geohash算法是空间填充曲线的一种,其特征是能够对数据进行降维处理,将二维的空间数据转换为hash字符串,将负载的空间查询计算转换为字符串的比较。在我们的项目中,我们再数据入库过程中,使用postgis 的函数,为每个坐标点生成geohash串,同时进行也基于geohash算法进行格网划分,数据统计,最终生成格网数据。

在构建高并发服务方面,主要的解决思路在两点。第一是使用redis缓存机制,提高缓存命中率,减少数据的查询时间。第二是利用线程池和异步处理技术,对前端的数据请求进行异步处理,使用线程池进行数据查询,查询完成后再将数据返回给前端。具体的技术方案是使用spingboot 的事件机制和DeferredResult进行异步处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值