Redis GeoHash 测距

Redis GeoHash 测距

GeoHash本质上是空间索引的一种方式,其基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码。以GeoHash方式建立空间索引,可以提高对空间poi数据进行经纬度检索的效率。由于采用的是base32编码方式,即Geohash中的每一个字母或者数字都是由5bits组成(2^5 = 32,base32),这5bits可以有32中不同的组合(0~31),这样我们可以将整个地图区域分为32个区域,通过00000 ~ 11111来标识这32个区域。

Redis 3.2版本之后增加。

使用场景:存储地理位置、附近的人。

代码实现方法

定义实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
js复制代码/**
* 地方实体
*
* @author fengyn
* @since 2021/4/26 15:50
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Place {

/**
* 地名
*/
private String name;

/**
* 经度
*/
private Double longitude;

/**
* 经度
*/
private Double latitude;

初始化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
js复制代码 @PostConstruct
private void setGeo(){
addGeo(new Place("浙港国际",120.093312,30.309403));
addGeo(new Place("丰潭路地铁口",120.109624,30.281936));
addGeo(new Place("杭州东站",120.212998,30.291331));
addGeo(new Place("杭州汽车西站",120.09105,30.261022));
}

private void addGeo(Place place){
String geo = "geo";
redisTemplate.opsForGeo().add(geo,
new Point(place.getLongitude(),place.getLatitude()),place.getName());
}
GeoHash实际上是存在zset里,score存geohash算法计算出来的值

企业微信截图_1619427763701.png

计算两个位置的距离

Distance distance(K var1, M var2, M var3, Metric var4);

Diststance有两个属性:double value(距离) Metric metric(单位)

var1 表示redis key值

var2 var3 表示zset两个位置的key值

var4 表示距离单位(可不传,默认单位为米)

1
2
js复制代码String geo = "geo";
Distance distance = redisTemplate.opsForGeo().distance(geo,"杭州东站", "杭州汽车西站", Metrics.KILOMETERS);

结果

1
2
3
4
js复制代码{
"value": 12.1894,
"metric": "KILOMETERS"
}

以中心位置为圆心找出指定半径范围内的位置

GeoResults radius(K var1, Circle var2, GeoRadiusCommandArgs var3);

GeoLocation有两个属性 : T name (zset中key值) ,Point point (返回 经纬度 double x,double y);

GeoResults有两个属性 : Distance averageDistance(平均距离) ,List content (返回GeoLocation属性);

var1 表示redis key值

var2 表示圆心坐标位置

var3 表示添加过滤排序条件

includeDistance 包含距离

includeCoordinates 包含经纬度

sortAscending 正序排序

limit 限定返回的记录数

1
2
3
4
5
6
js复制代码String geo = "geo";
GeoResults<RedisGeoCommands.GeoLocation<Object>> ret =
redisTemplate.opsForGeo().radius(geo, //丰潭路坐标
new Circle(new Point(120.109624,30.281936), new Distance(1, Metrics.KILOMETERS)),
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
.includeDistance().limit(3).includeCoordinates().sortAscending()));

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
js复制代码{
"averageDistance": {
"value": 2.1217666666666664, //平均距离
"metric": "KILOMETERS"
},
"content": [
{
"content": {
"name": "丰潭路地铁口",
"point": {
"x": 120.10962277650833,
"y": 30.281934749809132
}
},
"distance": {
"value": 2.0E-4,
"metric": "KILOMETERS"
}
},
{
"content": {
"name": "杭州汽车西站",
"point": {
"x": 120.09105116128922,
"y": 30.26102076552342
}
},
"distance": {
"value": 2.9317,
"metric": "KILOMETERS"
}
},
{
"content": {
"name": "浙港国际",
"point": {
"x": 120.09330958127975,
"y": 30.309403523012882
}
},
"distance": {
"value": 3.4334,
"metric": "KILOMETERS"
}
}
]
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%