Redis GEO 52 位整数的经纬分布
文章目录
- Geohash 编码的位排列规则
- 编码过程原理(源码解析)
- 为什么采用交错存储?
- 解码过程
- 精度说明
在 Redis 的 GEO 实现中,经度和纬度的编码方式是 交错存储而不是分离存储的。在 52 位的 Geohash 编码中,经度(longitude)和纬度(latitude)的比特位是 交替排列的,而不是物理上分开的区块。
具体结构如下:
Geohash 编码的位排列规则
位位置(从最高位开始) | 0 | 1 | 2 | 3 | 4 | … | 50 | 51 |
---|---|---|---|---|---|---|---|---|
对应坐标 | 经度 | 纬度 | 经度 | 纬度 | 经度 | … | 经度 | 纬度 |
- 偶数索引位(0,2,4,…,50):存储经度信息(共 26 位)
- 奇数索引位(1,3,5,…,51):存储纬度信息(共 26 位)
编码过程原理(源码解析)
Redis 的 Geohash 编码实现在 geohash.c
文件中,核心逻辑在 geohashEncode()
函数中:
// redis/src/geohash.c
void geohashEncode(...) {// ...for (i = 0; i < step; i++) {double lat_offset, lng_offset;uint64_t bits = 0;// 交替处理经度和纬度if (i % 2 == 0) {// 偶数位:处理经度lng_offset = (lng_range[0] + lng_range[1]) / 2;if (longitude >= lng_offset) {bits |= 1;lng_range[0] = lng_offset;} else {lng_range[1] = lng_offset;}} else {// 奇数位:处理纬度lat_offset = (lat_range[0] + lat_range[1]) / 2;if (latitude >= lat_offset) {bits |= 1;lat_range[0] = lat_offset;} else {lat_range[1] = lat_offset;}}hash->bits = (hash->bits << 1) | bits;}
}
为什么采用交错存储?
- 空间局部性保留:
- 经纬度交错排列保持了地理位置的连续性
- 相邻地理位置的 Geohash 值会有更长的公共前缀(临界特性)
- 范围查询优化:
// redis/src/geo.c
void georadiusGetAreasByShape(geoRange *r) {// 范围查询时会自动对齐Z阶曲线geohashBoundingBox(r->longitude, r->latitude, r->radius);
}
这种排列使得经度/纬度联合查询可以直接通过位操作实现
- 与Z阶曲线的兼容:
交错存储本质上实现了莫顿码(Morton Code),将二维坐标映射到一维曲线时能最小化空间跳跃
解码过程
当需要反向获取坐标时,Redis 会分离这些位:
// redis/src/geohash.c
int decodeGeohash(uint64_t bits, double *xy) {double lat_range[] = {-90, 90};double lng_range[] = {-180, 180};// 交替处理52位for (int i = 51; i >= 0; i--) {uint64_t bit = (bits >> i) & 1;if (i % 2 == 0) { // 经度位double mid = (lng_range[0] + lng_range[1]) / 2;if (bit) lng_range[0] = mid;else lng_range[1] = mid;} else { // 纬度位double mid = (lat_range[0] + lat_range[1]) / 2;if (bit) lat_range[0] = mid;else lat_range[1] = mid;}}xy[0] = (lng_range[0] + lng_range[1]) / 2;xy[1] = (lat_range[0] + lat_range[1]) / 2;
}
精度说明
坐标轴 | 比特位数 | 理论精度 |
---|---|---|
经度 | 26 bits | 约 0.0000429° (赤道约 4.78m) |
纬度 | 26 bits | 约 0.0000215° (约 2.39m) |
这种交错编码方式虽然增加了编解码的复杂性,但使 Redis 的 GEO 查询性能达到了 O(log N) 的优异水平,是空间与时间的完美平衡。