一,解决问题
目前动态派工算法获取师傅到目标点的距离及时间,是通过百度API获取的。目前调用百度API所需的时间相对较长,且有调用次数及并发数限制。并且这部分数据没有积累。因此打算开发智能路径系统,一期将调用百度API的数据采集起来,在测算距离及时间的起始点重复时,复用数据。二期将通过获取多能工轨迹,通过机器学习,对保存的距离时间做自优化。
二,设计思路
1.地图数据网格化
在保存从百度地图API获取的两点间距离及时间数据时,如果保存点到点的信息,则需要保存无数个点到点的信息,这样的数据量太大,大大增加了数据存储难度及系统的复杂度。所以采用化繁为简的方式,将地图划分为若干个方形的经纬网格,存储数据时,存储起始网格中心点到目的网格中心点的距离及时间数据。当计算地图上某两点的距离时,则看这两点的经纬度落到哪两个网格内,返回已存储的这两个网格中心点的时间及距离数据即可。网格越小,则精确度越高。
按照上述经纬度距离换算公式,将地图划分为若干个200米*222米的经纬网格,则构筑这个网格的四个顶点坐标为(m代表纬度,n代表经度)[m,n],[m+0.002,n],[m,n+0.002],[m+0.002,n+0.002],该网格中心点的坐标为[m+0.001,n+0.001]。当某一点的坐标[M,N]满足条件m<M≤m+0.002,n<N≤n+0.002时,则将坐标[M,N]≈[m+0.001,n+0.001]进行距离及时间计算。
如图所示(比例尺为100米/厘米),为廊坊e城e家营业厅(尚都金茂营业厅)到星盛园小区的实际距离,图中黑色网格为200米*222米的经纬网格,实际存储及使用的为图中橙色两点的距离。
2.网格化数据存储
按照上述经纬网格的划分方式,以廊坊市为例,廊坊市两个市区安次区及广阳区的面积为908平方公里。黑色网格的面积为200米*222米≈0.04平方公里。则908平方公里会划分为22700个经纬网格。
按照上述的计算公式,廊坊市区所有经纬网格的数据条数为22700*(22700-1)/2=257633650(两亿五千万)条数据。
在线服务名称 | 未认证用户 | 认证用户 | ||||
个人 | 企业 | |||||
配额(次/日) | 并发(次/分钟) | 配额(次/日) | 并发(次/分钟) | 配额(次/日) | 并发(次/分钟) | |
批量算路(Route Matrix v2.0) | 2000 | 1200 | 30000 | 3000 | 300000 | 12000 |
由于实际数据来源为百度地图API批量算路(Route Matrix v2.0),上表为批量算路(Route Matrix v2.0)API的配额,企业认证用户每天只可以查询30万次。如果查询整个廊坊市区的经纬网格的距离时间数据需要833天才可以。所以不能按照廊坊市区范围去选取经纬网格调用百度API,而是按照服务区域去进行数据获取。※由于全城模式数据量巨大,全城模式中师傅与目标点距离的数据不进行预存储。
3.服务区网格数据预存储
如图所示,假设蓝色虚线为划分的服务区,该服务区的顶点坐标为[m1,n1],[m2,n2],[m3,n3],[m4,n4]......从这些顶点坐标中找到最大及最小纬度M,m,最大及最小经度N,n,则将服务区转化为长方形的区域,四个顶点坐标为[m,n],[M,n],[m,N],[M,N]。从而算出该服务区的经纬网格范围为淡蓝色长方形所示。按照章节2的逻辑,将服务区经纬网格数据进行预存储。
4.地图海量数据的存储与查询
按照上述存储逻辑,每个城市的经纬网格间距离及时间数据的数量级是千万级的,全国若干个城市数据的集合应该是十亿级以上。对如此大的数据进行存储查询,需要采用大数据存储。采用的方案为Hbase+Solr的解决方案。
初期数据查询的需求是通过指定起始点经纬网格中心的经纬度,目标点网格中心的经纬度,如果这个数据已经实现存储,则返回存储的数据,否则调用百度地图API并将获取到的数据存储。所以合理的设计Hbase的Rowkey,暂时不需要使用Solr做二级索引。
因为从经纬网格A到经纬网格B之间的距离时间与从经纬网格B到经纬网格A之间的距离时间接近相等。则在存储数据时【A,B】,【B,A】的数据保存一条即可。在查询数据时,为了保证查询【A,B】,【B,A】返回唯一的结果,在存储数据时需要遵循以下原则将标量化的数据转化为矢量化的数据。
为了保证每次查询的数据范围不至于太大,在进行Hbase数据存储时,每个城市的数据存储到以城市命名的Hbase表中,在进行查询时,首先根据传入参数中的城市找到指定的Hbase的表,在将坐标按照上述的逻辑排序后生成Hbase Rowkey,进行查询。
5.地图海量数据HBase的RowKey设计
按照章节4设计的数据存储逻辑,Rowkey只要存储排序后的AB两点的经纬网格中心点的坐标即可。可以按照如下几种方式生成Rowkey:
A.精确到三位小数直接存储:
廊坊e城e家营业厅(尚都金茂营业厅) 经纬度坐标 [39.5334240000,116.7145800000] ,所在网格中心点的坐标为[39.5330000000,116.7140000000]
廊坊康乐花园小区门口经纬度坐标 [39.5351570000,116.7298310000],所在网格中心点的坐标为[39.5350000000,116.7290000000]
精确到第三位小数,并且方便区分,RowKey的格式为:【39.533,116.714/39.535,116.729】,字节数为29。
B.采用Geohash算法计算后存储:
经过Geohash算法处理后,廊坊e城e家营业厅(尚都金茂营业厅) 所在网格中心点的坐标转化为wx4bzuu8,廊坊康乐花园小区门口所在网格中心点的坐标转化为wx50bjpk。
则RowKey的格式为【wx4bzuu8/wx50bjpk】,字节数为17。
采用Geohash算法计算后存储的优点除了Rowkey的字节数之外,还有如下优点:
- Geohash的数据是可以重用的,Geohash base32编码长度为8时,精度在19米左右,实际上取得是19米范围的正方形的中心点。目前经纬网格的大小为200米,后续数据做精确化存储时,可以将经纬网格缩小到19米,这样之前收集的数据是可以重用的。
- Geohash base32编码前缀可以代表更大的范围, 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash然后取其前缀进行查询 。
- Geohash base32编码是可排序,可以比较的,一次比较就可以比较出经纬度两个值的差异,减少运算次数。
所以推荐使用Geohash base32对经纬度计算后的值做为Hbase的Rowkey。