13、Redis的GeoHash支持

学习目标:

1、了解GeoHash 算法

2、掌握redis对GeoHash的命令的支持

学习过程:

一、了解GeoHash 算法

地图上一般是使用经度和纬度两个维度来唯一的确定一个点,而geohash采用经纬度二维值转为一维的值。只需要对一个字段进行索引,提高性能、降低复杂度,可转成可排序,可比较的字符串,满足灵活的需求,具体的GeoHash的说明可以参考维基百科。

https://en.wikipedia.org/wiki/Geohash

GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。当我们想要计算「附近的人时」,首先将目标位置映射到这条线上,然后在这个一维的线上获取附近的点就行了。

目前很多数据库都对GeoHash支持了,比如mysql、mongodb、hbase等都对其实现了支持。在真正的生产环境中,需要根据需要采用不通的技术,并不一定使用redis。

二、redis的geohas的命令

在 Redis 里面,经纬度的信息是使用zset 储存的,经纬度使用 52 bit的整数进行编码,score 是 值就是该的 52 位整数值, value 就是元素的 key。zset 的 score 虽然是浮点数,但是对于 52 位的整数值,它可以无损存储。

redis的相关GetHash命令就是对zset的封装使用,在添加信息是会把经纬度转换,在比较时会使用排序等算法,同时也可以把score重新转换位经纬度信息,以获得原始的坐标。

首先我们先获得对应的经纬度信息

http://api.map.baidu.com/lbsapi/getpoint/index.html

redis支持的GeoHash相关命令

geoadd  添加
geopos  获取元素经纬度
geohash 获取base32 编码
geodist 计算距离
georadiusbymember  根据member获得距离最近的信息
georadius  根据指定的经纬度获得信息

1、geoadd  添加,可以一次一个,也可以一次多个,我这里添加了几个车站的坐标信息

127.0.0.1:6379> geoadd station 113.348694 23.176776 tianhekeyunzhan
(integer) 1
127.0.0.1:6379> geoadd station 113.330584 23.156044 guangzhoudongzhan  113.258289  23.15498  shengkehuzhan  113.278986  23.165347  guangyuankyz
(integer) 3

2、geopos  获取元素经纬度

我们获取一下刚才添加的坐标信息,可以看到精度和添加的时候有点出入。

127.0.0.1:6379> geopos station tianhekeyunzhan
1) 1) "113.34869652986526489"
   2) "23.17677675698901396"


3、geohash 获取base32 编码

127.0.0.1:6379> geohash station tianhekeyunzhan
1) "ws0eg74n800"


4、geodist 计算距离,计算两个元素之间的距离

127.0.0.1:6379> geodist station  tianhekeyunzhan guangzhoudongzhan km
"2.9577"
127.0.0.1:6379> geodist station  tianhekeyunzhan guangzhoudongzhan m
"2957.7020"


5、georadiusbymember  根据member获得距离最近的信息

GEORADIUSBYMEMBER location-set
location radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

这个命令参数比较多

比如我们要查询以tianhekeyunzhan为中心,半径30KM,最近的前三个,并显示距离WITHDIST,注意这个命令会包含自己的。

127.0.0.1:6379> georadiusbymember station tianhekeyunzhan 30 km WITHDIST count 3 asc
1) 1) "tianhekeyunzhan"
   2) "0.0000"
2) 1) "guangzhoudongzhan"
   2) "2.9577"
3) 1) "guangyuankyz"
   2) "7.2407"


6、georadius  根据指定的经纬度获得信息

GEORADIUS location-set
longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]

这个命令和上一个参数几乎一样,就是经纬度由自己输入,这个在定位导航时更常见,比如我现在在某个地方,想查询离我最近的车站在哪里,就可以使用这个命令

127.0.0.1:6379> GEORADIUS station 113.301407 23.146075 30 km withdist count 5 asc
1) 1) "guangyuankyz"
   2) "3.1389"
2) 1) "guangzhoudongzhan"
   2) "3.1834"
3) 1) "shengkehuzhan"
   2) "4.5195"
4) 1) "tianhekeyunzhan"
   2) "5.9201"

三、JRedis对GeoHash的封装和使用

添加信息

@Test
public void testGeoAdd() {
	Map<Serializable, Point> memberCoordinateMap = new HashMap<Serializable, Point>();
	memberCoordinateMap.put("fangcunkehuzhan", new Point(113.24166, 23.085442));
	memberCoordinateMap.put("jiaokoukehuzhan", new Point(113.214794, 23.119942));

	long result = template.opsForGeo().geoAdd("station", memberCoordinateMap);

	System.out.println(result);
}

查询

@Test
public void testGeoRadiusByMember() {
	
	//KILOMETERS 千米
	Distance distance=new Distance(30D,Metrics.KILOMETERS);
	GeoRadiusCommandArgs geoArgs=GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(5).sortAscending();
	GeoResults<GeoLocation<Serializable>>  result= template.opsForGeo().geoRadiusByMember("station", "fangcunkehuzhan",distance,geoArgs);
	Iterator<GeoResult<GeoLocation<Serializable>>> itero =	result.iterator();
	while(itero.hasNext()) {
		GeoResult<GeoLocation<Serializable>> geoResult=itero.next();
System.out.println(geoResult.getContent().getName()+":"+geoResult.getDistance().getValue());
	}
}

@Test
public void testGeoRadius() {
	Distance distance=new Distance(30D,Metrics.KILOMETERS);
	Circle within=new Circle(new Point(113.212197,23.120106), distance);
	GeoRadiusCommandArgs geoArgs=GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(5).sortAscending();
	GeoResults<GeoLocation<Serializable>>  result= template.opsForGeo().geoRadius("station", within,geoArgs);
	Iterator<GeoResult<GeoLocation<Serializable>>> itero =	result.iterator();
	while(itero.hasNext()) {
		GeoResult<GeoLocation<Serializable>> geoResult=itero.next();
System.out.println(geoResult.getContent().getName()+":"+geoResult.getDistance().getValue());
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值