GEO是用来做什么的
GEO是一种用来存储地理信息(也就是经纬度)的数据结构。主要用来服务与LBS(Location-Based Service,基于位置的服务)。
GEO的底层实现
和BitMap还有HyperLogLog一样,GEO也是Redis的三种扩展数据类型之一。
BitMap的底层是String(字节数组),Redis在String的基础上增加了新的操作方式(按位操作)就有了BitMap。
而GEO和BitMap一样,它的底层也是基于五种基础数据结构之一的Sorted Set,因为LBS服务比如打车服务,都是需要范围查询的,需要将范围内可打的车按照与打车人之间的距离进行排序,所以自然而然要用能排序的数据结构。
相较于List,Sorted Set额外还能存储一个score信息,完美符合GEO的需求。通过GeoHash编码方式将经纬度信息转换成二进制编码再转成float类型存储到score中。score可以代表经纬度,且score相近则两个位置的经纬度也相近,也就方便我们查询指定范围内的坐标并对他们进行排序。
你看,除了可以在Redis5中基础数据结构上通过增加新的操作方式来实现新的扩展数据类型(BitMap)之外,也还可以通过使用新的编码方式来扩展数据类型(Geo)。
GeoHash编码
GeoHash编码本质上通过对经纬度区间进行二分法处理:“二分区间,区间编码”,具体编码方式如下:
为了能高效地对经纬度进行比较,Redis 采用了业界广泛使用的 GeoHash 编码方法,这个方法的基本原理就是“二分区间,区间编码”。当我们要对一组经纬度进行 GeoHash 编码时,我们要先对经度和纬度分别编码,然后再把经纬度各自的编码组合成一个最终编码。首先,我们来看下经度和纬度的单独编码过程。对于一个地理位置信息来说,它的经度范围是[-180,180]。GeoHash 编码会把一个经度值编码成一个 N 位的二进制值,我们来对经度范围[-180,180]做 N 次的二分区操作,其中 N 可以自定义。在进行第一次二分区时,经度范围[-180,180]会被分成两个子区间:[-180,0) 和[0,180](我称之为左、右分区)。此时,我们可以查看一下要编码的经度值落在了左分区还是右分区。如果是落在左分区,我们就用 0 表示;如果落在右分区,就用 1 表示。这样一来,每做完一次二分区,我们就可以得到 1 位编码值。然后,我们再对经度值所属的分区再做一次二分区,同时再次查看经度值落在了二分区后的左分区还是右分区,按照刚才的规则再做 1 位编码。当做完 N 次的二分区后,经度值就可以用一个 N bit 的数来表示了。
------- GEO是什么?还可以定义新的数据类型吗?
在我们日常的开发中,如果需要对一个二维且有限范围内的位置进行编码,”二分法“的思想值得借鉴。
自定义Redis数据类型
查看Redis源码,仿照String数据类型,来自定义创建新的数据类型。