需求
选择商铺类型后,按照距离当前用户所在位置从近到远的顺序,分页展示该类型的所有商铺。
接口:
- 参数:
- typeId:商铺类型
- current:页码
- x:经度
- y:纬度
- 返回值:所有typeId类型的商铺按照距离坐标(x, y)从近到远排序时的第current页数据。
GEO数据类型
- 每一个key对应一个地理坐标的集合,集合中的每一个地理坐标由<经度(longitude)、纬度(latitude)、值(member)>三部分组成。
- 底层用SortedSet数据类型实现,根据GeoHash编码方法计算出每一个地理坐标的分数(score),并按照score进行排序。
常用命令:
# 向key中添加地理坐标
GEOADD key longitude latitude member [longitude latitude member ...]
# 计算同一个key中的两个地理坐标之间的距离
GEODIST key member1 member2 [m|km|ft|mi]
# 获取某个地理坐标的GEOHASH值
GEOHASH key member
# 获取某个地理坐标的经度和纬度
GEOPOS key member
用于实现范围查找的命令:
- GEORADIUS(6以后已废弃)
# 获取以(x, y)为圆心,以r为半径的圆中的所有地理坐标,默认按照距离(x, y)从近到远的顺序排序(ASC)。
GEORADIUS key x y r [ASC|DESC]
- GEOSEARCH(6.2新功能)
3. GEOSEARCHSTORE(6.2新功能):与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key中。
缓存预热
提前将所有商铺的位置信息存入redis中(GEOADD)。
- key:“shop:geo:{typeId}”
- value:GEO类型
- member:“{shopId}”
- member:“{shopId}”
查询附近商户
- 用户提交查询附近商户的请求,携带四个参数:typeId,current,x,y。
- 计算分页参数:
int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;
int end = current * SystemConstants.DEFAULT_PAGE_SIZE;
- 从redis中查找距离坐标(x, y)最近的前end个商铺
String key = SHOP_GEO_KEY + typeId; // key = geo:shop:{typeId}
GEOSEARCH {key} BYLONLAT {x} {y} BYRADIUS 10 COUNT {end} WITHDISTANCE
- 截取from~end的部分
- 根据shopId查询数据库获取商铺的详细信息