GEO 存储方案与空间索引
1 存储方案
目前支持空间数据存储的方案很多,Esri 公司的 ArcSDE(Spatial Database Engine,空间数据库引擎),包括 Oracle,SQL Server,IBM DB2 都做了很好的支持,不过都是商业数据库,需要收费。开源领域,mysql、redis、elasticsearch、mongodb、postgreSQL 等都做了相关支持。实现方案各自不同,使用上也有差异,简单理解,都是数据+索引结构组成的支撑,通过 api 来进行调用(废话)。
2 空间索引
目前空间索引的实现有 R 树和其变种 GIST 树、四叉树、网格索引等。GeoHash 也是空间索引的一种方式,并且特别适合点数据,而对线、面数据采用 R 树索引更有优势。
Redis GEO
1 命令
Redis 3.2 版本新增了 geo 相关命令,用于存储和操作地理位置信息。提供的命令包括添加、计算位置之间距离、根据中心点坐标和距离范围来查询地理位置集合等,说明如下:
- geoadd:添加地理位置的坐标。
- geopos:获取地理位置的坐标。
- geodist:计算两个位置之间的距离。
- georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
- geohash:返回一个或多个位置对象的 geohash 值。
2 原理:redis 源码解析
2.1 数据结构简述
Redis geo 并不是全新的数据结构,而是基于 Sorted Set 来实现的(这点我们会在后面进行说明)。说起 sorted set,大家肯定了解 zset,也是 redis 中常用的数据结构。
我们看一下 redis geo 的源码,从中可以更好地理解数据结构和操作原理。redis 源码可从
https://github.com/redis/redis获取,我们切换到正在使用的 3.2branch(也可以根据实际使用情况,切换到对应版本的分支)。3.2 下的 geo 相关源码文件主要是 src 下的 geo.h 和 geo.c,以及 deps/geohash-int 下的 geohash.c,geohash.h,geohash_helper.h 和 geohash_helper.c。
2.2 geo.h
geo.h 是数据结构定义,里面包括了 geoPoint 和 geoArray 两个结构体,内容如下:
#ifndef __GEO_H__
#define __GEO_H__
#include "server.h"
/* Structures used inside geo.c in order to represent points and array of
* points on the earth. */
typedef struct geoPoint {
double longitude;
double latitude;
double dist;
double score;
char *member;
} geoPoint;
typedef stru