2023年7月26日发(作者:)
基于Redis位置查询GEO信息Redis 的 GEO 特性将在 Redis 3.2 版本释出, 这个功能可以将⽤户给定的地理位置信息储存起来, 并对这些信息进⾏操作。本⽂将对 Redis 的 GEO 特性进⾏介绍, 说明这个特性相关命令的⽤户, 并在最后说明如何使⽤这些命令去实现“查找附近的⼈”以及“摇⼀摇”这两个功能,GEO⽬前提供以下6个命令。1. geoadd:增加某个地理位置的坐标。2. geopos:获取某个地理位置的坐标。3. geodist:获取两个地理位置的距离。4. georadius:根据给定地理位置坐标获取指定范围内的地理位置集合。5. georadiusbymember:根据给定地理位置获取指定范围内的地理位置集合。6. geohash:获取某个地理位置的geohash值。地理位置的坐标是以WGS84为标准,WGS84,全称World Geodetic System 1984,是为GPS全球定位系统使⽤⽽建⽴的坐标系统。1、版本要求因为 Redis ⽬前的稳定版本为 Redis 3.0 , ⽽ GEO 特性是 Redis 3.2 版本的特性, 所以如果你想要使⽤这个特性的话, 那么就需要到Redis 的 GitHub 页⾯去克隆 unstable 分⽀ 然后编译 unstable 版本的 Redis 源码, 这样才能⽤到 Redis GEO 特性。2、添加位置和获取位置为了进⾏地理位置相关操作, 我们⾸先需要将具体的地理位置记录起来, 这⼀点可以通过执⾏ GEOADD 命令来完成, 该命令的基本格式如下:GEOADD location-set longitude latitude name [longitude latitude name ...]GEOADD 命令每次可以添加⼀个或多个经纬度地理位置。 其中 location-set 为储存地理位置的集合, ⽽ longitude 、 latitude 和 name则分别为地理位置的经度、纬度、名字。举个例⼦, 以下代码展⽰了如何通过 GEOADD 命令, 将清远、⼴州、佛⼭、东莞、深圳等数个⼴东省的市添加到位置集合 Guangdong-cities ⾥⾯:redis> GEOADD Guangdong-cities 113.2099647 23.593675 Qingyuan-- 成功添加⼀个位置redis> GEOADD Guangdong-cities 113.2278442 23.1255978 Guangzhou 113.106308 23.0088312 Foshan 113.7943267 22.9761989 Dongguan 114.0538788 22-- 成功添加四个位置在将位置记录到位置集合之后, 我们可以使⽤ GEOPOS 命令, 输⼊位置的名字并取得位置的具体经纬度:GEOPOS location-set name [name ...]⽐如说, 如果我们想要获取清远、⼴州和佛⼭的经纬度, 那么可以执⾏以下代码:redis> GEOPOS Guangdong-cities Qingyuan Guangzhou Foshan1) "113.29" -- 清远的经度2) "23.593675019671288" -- 清远的纬度3) "113.22784155607224" -- ⼴州的经度4) "23.0807" -- ⼴州的纬度5) "113.15" -- 佛⼭的经度6) "23.539" -- 佛⼭的纬度3、计算两个位置之间的距离在拥有了地理数据之后, 我们就可以基于这些数据进⾏各种各样的操作。 针对地理位置信息的其中⼀个最简单的操作, 就是计算两个位置之间的距离。在 Redis ⾥⾯, 计算两个位置之间的距离可以通过 GEODIST 命令来实现:GEODIST location-set location-x location-y [unit]在调⽤这个命令时, ⽤户需要给定想要计算差距的地点 location-x 和 location-y , 以及储存这两个地点的地理位置集合。可选参数 unit ⽤于指定计算距离时的单位, 它的值可以是以下单位的其中⼀个:m 表⽰单位为⽶。km 表⽰单位为千⽶。mi 表⽰单位为英⾥。ft 表⽰单位为英尺。如果⽤户没有指定 unit 参数, 那么 GEODIST 默认使⽤⽶为单位。作为例⼦, 以下代码展⽰了如何计算清远和⼴州之间的距离:redis> GEODIST Guangdong-cities Qingyuan Guangzhou"52094.433840356309" -- 两地相聚 52094 ⽶上⾯的计算结果使⽤了⽶来表⽰清远和⼴州两地的距离, 不过在表⽰⽐较长的距离时, 我们更习惯采⽤公⾥(km)作为单位。 通过显式地给定 km (千⽶)作为单位, 我们可以让 GEODIST 显⽰两个地点之间相距的公⾥数:redis> GEODIST Guangdong-cities Qingyuan Guangzhou km"52.309" -- 两地相聚 52 公⾥4、获取指定范围内的元素除了计算两地的距离之外, 另⼀个常见的地理位置操作就是找出特定范围之内的其他存在的地点。 ⽐如找出地点 x 范围 100 ⽶之内的所有地点, 找出地点 y 范围 50 公⾥之内的所有地点等等。Redis 提供了 GEORADIUS 和 GEORADIUSBYMEMBER 两个命令来实现查找特定范围内地点的功能, 它们的作⽤⼀样, 只是指定中⼼点的⽅式不同: GEORADIUS 使⽤⽤户给定的经纬度作为计算范围时的中⼼点, ⽽ GEORADIUSBYMEMBER 则使⽤储存在位置集合⾥⾯的某个地点作为中⼼点。 以下是这两个命令的基本格式:GEORADIUS location-set longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]GEORADIUSBYMEMBER location-set location radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]这两个命令的各个参数的意义如下:m|km|ft|mi 指定的是计算范围时的单位;如果给定了可选的 WITHCOORD , 那么命令在返回匹配的位置时会将位置的经纬度⼀并返回;如果给定了可选的 WITHDIST , 那么命令在返回匹配的位置时会将位置与中⼼点之间的距离⼀并返回;在默认情况下, GEORADIUS 和 GEORADIUSBYMEMBER 的结果是未排序的, ASC 可以让查找结果根据距离从近到远排序, ⽽DESC 则可以让查找结果根据从远到近排序;COUNT 参数指定要返回的结果数量。
作为⽰例, 我们可以使⽤ GEORADIUSBYMEMBER 去找出位于⼴州 50 公⾥、 100 公⾥以及 150 公⾥以内的城市:redis> GEORADIUSBYMEMBER Guangdong-cities Guangzhou 50 km1) "Foshan"2) "Guangzhou"redis> GEORADIUSBYMEMBER Guangdong-cities Guangzhou 100 km1) "Foshan"2) "Guangzhou"3) "Dongguan"4) "Qingyuan"redis> GEORADIUSBYMEMBER Guangdong-cities Guangzhou 150 km1) "Foshan"2) "Guangzhou"3) "Dongguan"4) "Qingyuan"5) "Shenzhen"5、⽰例:查找附近的⼈好的, 在了解了 Redis GEO 特性的基本信息之后, 接下来我们该思考如何使⽤这些特性去解决实际的问题了。为了让⽤户可以⽅便地找到⾃⼰附近的其他⽤户, 每个社交⽹站基本上都内置了“查找附近的⼈”这⼀功能, 通过 Redis , 我们也可以实现同样的功能, 以下是实现该功能的伪代码:def pin(user, longitude, latitude): """ 记录⽤户的地理位置。 """ GEOADD('user-location-set', longitude, latitude, user)def find_nearby(user, n): """ 返回指定⽤户附近 n 公⾥的所有其他⽤户。 """ return GEORADIUSBYMEMBER('user-location-set', user, n, unit='km')6、⽰例:摇⼀摇为了增加乐趣性, 我们可以对“查找附近的⼈”这⼀功能进⾏修改 —— 程序不是返回指定范围内的所有⼈, ⽽是随机地返回指定范围内的某个⼈, 这也就是⾮常著名的“摇⼀摇”功能。 以下是实现该功能的伪代码:RANDOM_RADIUS = 1 # 随机查找的范围为 1 公⾥def find_random(user): # 获取范围内的所有其他⽤户 get_all_near_users = find_nearby(user, RANDOM_RADIUS) # 将查找的结果从 Python 列表转换为 Python 集合 user_set = set(get_all_near_users) # 然后调⽤ pop() ⽅法,从集合⾥⾯随机地移除并返回⼀个元素 return user_()7、效率优化现在的 find_random() 函数可以实现“摇⼀摇”功能, 但它的效率并不⾼: 因为程序每次执⾏这个函数的时候都需要重新执⾏find_nearby() 函数以查找⽤户附近的位置, 然⽽⼤部分⽤户的位置并不经常改变, 并且 GEORADIUSBYMEMBER 命令的执⾏代价并不低, 因此每次执⾏ find_random() 都重新执⾏ find_nearby() 是⼀种⾮常低效的做法。为了优化 find_random() 的效率, 我们可以为 find_random() 的结果创建缓存: 把每个执⾏“摇⼀摇”的⽤户的 find_nearby() 结果储存到⼀个 Redis 集合⾥⾯, 并设置⼀个过期时间(⽐如 5 分钟), 然后通过对集合使⽤ SRANDMEMBER 来随机地获取⽤户。 这样⽤户在指定过期时间内执⾏的所有“摇⼀摇”操作都只会引起⼀次 GEORADIUSBYMEMBER , 这将极⼤地提⾼ find_random() 的执⾏效率。另外, 如果⽤户密集地聚集在⼀起, 那么通过使⽤ GEORADIUSBYMEMBER 命令提供的 COUNT 参数可以有效地减少指定范围内的⽤户数量, 这可以提⾼ find_nearby() 的效率, 从⽽提⾼ find_random() 的效率。因为篇幅关系, 优化版的 find_random() 的具体实现这⾥就不给出了, 有兴趣的读者可以⾃⼰尝试完成这个函数。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1690367678a339092.html
评论列表(0条)