1.Redis的源码数据类型-GEO
2.LBS - 空间索引Spatial Index
3.Redis GEO 命令学习及原理浅析
4.redis应用 8:GeoHash
5.使用Go语言手写一个简易版Redis,项目经验稳了!源码
6.Redis 源码限流的 3 种方式,还有谁不会!源码
Redis的数据类型-GEO
Redis新增的GEO数据类型主要用于存储和操作地理位置信息。GEO实际上是源码源码到汇编码的工具一种有序集合(zset),每个元素包含经度、源码纬度和位置名称,源码通过这些属性,源码可以在Redis中存储和操作地理坐标。源码 使用场景主要涉及地图应用、源码位置服务、源码地理空间分析等,源码例如商家定位、源码位置搜索和推荐、源码用户位置分析等。常用命令
1. 添加:GEOADD命令 功能:用于存储指定的地理空间位置,可以将一个或多个经度、纬度和位置名称添加到指定的key中。 语法:GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member ...] 参数说明:longite:地点的经度,范围:-度到度,经度必须放在纬度之前。
latitude:地点的纬度,范围:-.度到.度。
member:地点名称。
选项说明:NX:不添加新元素,只更新既有元素,v6.2.0版本出现。
XX:不更新既有元素,只添加新元素,v6.2.0版本出现。
CH:返回变更过的元素数量,同时包含新增和更新,v6.2.0版本出现。
返回值:整型,返回新增或变更的元素数量。 注意:使用GEOADD命令添加坐标时,若已有相同位置,则使用新坐标替换已有坐标。 示例: 2. 查询:GEOPOS命令 功能:从给定key中返回指定名称的位置(经度和纬度)。 语法:GEOPOS key member [member ...] 返回:数组,每个元素为一个包含经度和纬度的snatshot源码子数组。 示例: 3. 计算举例:GEODIST命令 功能:返回两个成员之间的距离,基于地球为完美球体的假设,计算结果可能存在%0.5误差。 语法:GEODIST key member1 member2 [M | KM | FT | MI] 选项说明:M:单位:米。
KM:单位:公里(千米)。
FT:单位:英里。
M:单位:英尺。
返回:可以转换为双精度浮点型的字符串。 4. 获取GEOHASH值:GEOHASH命令 Geohash是一种地理编码系统,将经纬度编码为数字和字母组成的字符串。虽然表示的是区域,但可以用于隐私保护。 功能:返回指定成员的地理位置的GEOHASH值。 语法:GEOHASH key member [member ...] 返回值:数组,包含每个位置成员对应的GEOHASH值。 示例: 5. 查询指定范围的地点:GEOSEARCH命令 功能:以经纬度为中心,返回距离不超过最大距离的所有位置元素。 语法:GEOSEARCH key FROMMEMBER member | FROMLONLAT longitude latitude BYRADIUS radius [ASC | DESC][COUNT count [ANY]][WITHCOORD][WITHDIST][WITHHASH] 选项说明:FROMMEMBER:指定起始成员。
FROMLONLAT:指定经纬度。
BYRADIUS:指定最大距离。
ASC | DESC:返回结果的排序。
COUNT:返回结果的数量。
WITHCOORD:返回经度和纬度。
WITHDIST:返回与中心点的距离。
WITHHASH:返回GEOHASH值。
返回值:数组,包含名称、经纬度、距离、GEOHASH值等信息。 示例: 6. 查询指定范围的地点:GEOSEARCHSTORE命令 功能:存储匹配结果,将位置信息存储到目标键中。默认存储位置信息,可选以距离作为分数存储。 语法:GEOSEARCHSTORE destination source FROMMEMBER member | FROMLONLAT longitude latitude BYRADIUS radius [ASC | DESC] [COUNT count [ANY]][STOREDIST] 返回值:整型,存储的成员数量。 示例:LBS - 空间索引Spatial Index
空间索引Spatial Index
在O2O行业中,LBS(基于位置的服务)应用广泛,例如根据用户定位召回附近商家,或召回附近空闲出租车。这些服务依赖空间检索(Spatial Index)技术,iterable源码通常将球面坐标系通过墨卡托投影映射到二维平面坐标系,以此实现位置检索。
空间索引的基本概念包括GeoHash、R-树、四叉树等。GeoHash通过将二维矩形区域映射成一维字符串,实现空间对象的高效存储和检索。R-树是一种基于矩形的平衡树,适用于处理空间数据的索引。四叉树是二维空间的递归细分,适合存储和查询有二维属性的数据。
不同存储系统如MySQL、PostgreSQL、Redis、MongoDB和ElasticSearch在空间索引方面具有各自特点。MySQL 5.7引入了原生的GeoHash支持和空间索引功能,适合需要高性能和可扩展性的应用。PostgreSQL通过PostGIS扩展支持复杂查询,效率极高。Redis在3.2版本后增加了空间索引支持,适用于数据量较小的应用。MongoDB提供灵活的空间索引和查询,支持多种几何操作。ElasticSearch提供强大的地理位置功能和全文搜索结合,适用于复杂查询和分析。
在实际业务中,应综合考虑数据量、检索复杂度和运维需求,选择合适的存储引擎。例如,MySQL适用于需要高性能和可扩展性的应用,而MongoDB则在处理大量非结构化数据时表现良好。ElasticSearch在复杂查询和分析场景中展现出色性能。
本文旨在介绍空间索引的基本概念和技术,并对比不同存储系统的特点,希望为开发者在空间检索服务技术评估和选型时提供参考。
Redis GEO 命令学习及原理浅析
Redis GEO命令在地理位置服务应用中发挥着关键作用,它利用Sorted Set数据结构和GeoHash编码实现高效地基于经纬度的查询。GeoHash编码将经纬度转换为分数值,确保了具有相近分数的元素在实际地理空间上也接近。通过划分小方格并映射到一维空间,源码传输Redis GEO允许精准的"搜索附近"功能。
例如,GEOADD命令在≥3.2.0版本可用,它将地理位置信息添加到Sorted Set中,使用O(log(N))的时间复杂度。GEOPOS命令用于获取指定元素的经纬度,GEODIST则计算两点间的距离。GEOHASH则返回元素的GeoHash编码,便于范围查询。而6.2.0版本之后,GEORADIUS和GEORADIUSBYMEMBER命令被废弃,推荐使用GEOSEARCH和GEOSEARCHSTORE,它们提供了更灵活的查询和结果处理方式。
总结来说,Redis GEO利用GeoHash编码和Sorted Set的数据结构,为基于位置的服务提供了高效且精确的查询能力。通过理解这些命令的原理和使用方法,开发者可以更好地在实际应用中利用Redis GEO实现地理位置相关的需求。
redis应用 8:GeoHash
Redis在3.2版本后加入的GEO模块使我们能利用Redis实现地理定位功能,如摩拜单车的"附近Mobike"、美团与饿了么的"附近餐馆"。
地图元素位置数据用二维经纬度表示,范围在经度(-, ],纬度(-, ]。掘金办公室在望京SOHO的坐标(.,.)正数,中国位于东北半球。
当元素距离不遥远时,使用勾股定理计算距离。但考虑经纬度坐标密度不均,计算距离时需加权。精确计算时,避免加权。
经度度,维度度,距离密度非2:1,原因在于地球形状。
计算"附近的人",即给定坐标,按距离排序元素,如何入手?
遍历计算所有元素距离过于耗时,应使用矩形区域限定元素数量,objviewer源码计算区域内元素距离,再排序。选择半径r,通过SQL圈定区域。用户不满意结果时,扩大半径继续筛选。
高性能矩形区域算法要求数据表在经纬度坐标上加双向复合索引(x, y)。
高并发场景下,数据库查询性能有限,大量"附近的人"查询可能不是一个好方案。
GeoHash算法
业界常用GeoHash算法计算地理距离。Redis采用GeoHash。该算法将二维坐标映射到一维整数,元素距离相近的坐标映射后点间距亦相近。需计算附近的人时,将目标位置映射到线上,获取线上的附近点。
GeoHash算法如何映射坐标?假设地球为二维平面,分割成正方形方格,每格唯一。方格越小,坐标越精确。然后对这些方格进行整数编码,越近的方格编码越接近。编码法为“切蛋糕法”,将正方形蛋糕二刀均分成四块,标记为、、、四个二进制整数。接着将每个小正方形继续切割,每块使用4bit二进制整数表示。如此递归,正方形变小,二进制整数变长,精确度提高。
编码后,每个坐标变为整数,损失程度与整数长度相关。对于"附近的人"功能,损失的精度忽略不计。
GeoHash算法将整数base编码,存入Redis的zset中,score为元素key,值为位整数。
在Redis进行Geo查询时,注意其内部结构为zset(skiplist),通过score排序获取坐标附近的元素。将score还原为坐标值即可得到元素原始坐标。
Redis Geo指令
Redis提供6个Geo指令,易于掌握。使用时,需牢记其本质上是zset。
增加指令:使用geoadd添加集合名称和多个经纬度名称三元组。
距离计算:使用geodist指令计算两个元素距离,携带集合名称、名称和单位。
获取位置:geopos指令获取集合中任意元素经纬度坐标,一次可获取多个。
获取元素hash值:使用geohash指令获取元素经纬度编码字符串,可用于查询。
附近公司查询:georadiusbymember指令查询指定元素附近元素,参数复杂。
总结与注意事项
地图应用中,数据量庞大,使用Redis Geo结构时,应避免单个key数据量过大影响集群迁移,线上服务运行。推荐使用单独的Redis实例部署Geo数据,避免集群环境。
数据量过大时,Geo数据应按国家、省、市乃至区拆分,降低单个集合大小。
使用Go语言手写一个简易版Redis,项目经验稳了!
大家好,我是 G哥! 今天,我向大家分享一个利用 Go 语言打造的简易版 Redis 项目,这个项目旨在帮助开发者深入了解 Go 语言和构建高并发中间件。 这个简易版 Redis 具备基本功能,如数据存储、缓存和键值对操作等,满足开发者学习和实践需求。通过探索此项目,不仅能够深化对 Go 语言的理解,还能够领略到使用 Go 语言开发高性能、并发处理系统的魅力。 项目提供了 Darwin (MacOS) 和 Linux 版本的可执行文件,使用简便。启动方法如下:下载项目可执行文件
运行启动命令
启动后,即可通过 redis-cli 或其他 Redis 客户端连接到默认监听的 端口,进行数据交互。 项目代码量较多,但学习并非难事。作者提供了详尽的教程指南,覆盖从 Go 编写 TCP 服务器到实现内存数据库、GeoHash 搜索功能等核心内容,对学习者友好。 感谢作者对开源社区的贡献,通过这个项目,开发者能够在实践中学到宝贵的经验。项目地址如下: github.com/HDT/godi... 通过探索和实践这个简易版 Redis 项目,相信你能够提升编程技能,更好地理解 Go 语言在并发处理和高性能系统构建中的应用。Redis 限流的 3 种方式,还有谁不会!
面对越来越多的高并发场景,限流显示的尤为重要。当然,限流有许多种实现的方式,Redis具有很强大的功能,我用Redis实践了三种的实现方式,可以较为简单的实现其方式。Redis不仅仅是可以做限流,还可以做数据统计,附近的人等功能,这些可能会后续写到。
第一种:基于Redis的setnx的操作我们在使用Redis的分布式锁的时候,大家都知道是依靠了setnx的指令,在CAS(Compare and swap)的操作的时候,同时给指定的key设置了过期实践(expire),我们在限流的主要目的就是为了在单位时间内,有且仅有N数量的请求能够访问我的代码程序。所以依靠setnx可以很轻松的做到这方面的功能。
比如我们需要在秒内限定个请求,那么我们在setnx的时候可以设置过期时间,当请求的setnx数量达到时候即达到了限流效果。代码比较简单就不做展示了。
当然这种做法的弊端是很多的,比如当统计1-秒的时候,无法统计2-秒之内,如果需要统计N秒内的M个请求,那么我们的Redis中需要保持N个key等等问题。
第二种:基于Redis的数据结构zset其实限流涉及的最主要的就是滑动窗口,上面也提到1-怎么变成2-。其实也就是起始值和末端值都各+1即可。
而我们如果用Redis的list数据结构可以轻而易举的实现该功能。
我们可以将请求打造成一个zset数组,当每一次请求进来的时候,value保持唯一,可以用UUID生成,而score可以用当前时间戳表示,因为score我们可以用来计算当前时间戳之内有多少的请求数量。而zset数据结构也提供了range方法让我们可以很轻易的获取到2个时间戳内有多少请求
代码如下
publicResponselimitFlow(){ LongcurrentTime=newDate().getTime();System.out.println(currentTime);if(redisTemplate.hasKey("limit")){ Integercount=redisTemplate.opsForZSet().rangeByScore("limit",currentTime-intervalTime,currentTime).size();//intervalTime是限流的时间System.out.println(count);if(count!=null&&count>5){ returnResponse.ok("每分钟最多只能访问5次");}}redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);returnResponse.ok("访问成功");}通过上述代码可以做到滑动窗口的效果,并且能保证每N秒内至多M个请求,缺点就是zset的数据结构会越来越大。实现方式相对也是比较简单的。
第三种:基于Redis的令牌桶算法提到限流就不得不提到令牌桶算法了。
令牌桶算法提及到输入速率和输出速率,当输出速率大于输入速率,那么就是超出流量限制了。
也就是说我们每访问一次请求的时候,可以从Redis中获取一个令牌,如果拿到令牌了,那就说明没超出限制,而如果拿不到,则结果相反。
依靠上述的思想,我们可以结合Redis的List数据结构很轻易的做到这样的代码,只是简单实现
依靠List的leftPop来获取令牌
//输出令牌publicResponselimitFlow2(Longid){ Objectresult=redisTemplate.opsForList().leftPop("limit_list");if(result==null){ returnResponse.ok("当前令牌桶中无令牌");}returnResponse.ok(articleDescription2);}再依靠Java的定时任务,定时往List中rightPush令牌,当然令牌也需要唯一性,所以我这里还是用UUID进行了生成
//S的速率往令牌桶中添加UUID,只为保证唯一性@Scheduled(fixedDelay=_,initialDelay=0)publicvoidsetIntervalTimeTask(){ redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());}综上,代码实现起始都不是很难,针对这些限流方式我们可以在AOP或者filter中加入以上代码,用来做到接口的限流,最终保护你的网站。
Redis其实还有很多其他的用处,他的作用不仅仅是缓存,分布式锁的作用。他的数据结构也不仅仅是只有String,Hash,List,Set,Zset。有兴趣的可以后续了解下他的GeoHash算法;BitMap,HLL以及布隆过滤器数据(Redis4.0之后加入,可以用Docker直接安装Redislabs/rebloom)结构。
有问题欢迎留言探讨。
原文链接:/lmx/article/details/
redis学习笔记(二) - redis的数据类型bitmap/hyperloglog/GEO
数据类型与应用案例
在日常应用中,常见数据类型如bitmap、hyperloglog与GEO数据结构用于处理大规模数据的收集与统计,具有存取高效、多维度统计分析的优势。
例如,手机App中的每天用户登录信息、电商网站商品的用户评论列表、用户在App上的签到打卡信息以及网页访问信息等,这些场景下数据量大,需要快速存取与统计。
面试问题可能涉及如何利用集合数据进行统计分析,如在移动应用中统计每日新增用户数与留存用户数,电商网站评论列表中最新评论的处理,签到打卡中连续打卡用户的数量统计,以及网页访问记录中独立访客数量的计算。
数据类型选择与功能
针对统计需求,常用数据类型包括:
二值统计(如bitmap):用于表示集合中元素的取值,仅支持0和1两种状态,适合记录如用户是否登录过、**是否被点击播放等二元信息。
基数统计(如hyperloglog):用于统计集合中不重复的元素个数,即去重后的真实数量,适合计算UV(独立访客)、PV(页面访问量)、DAU(日活跃用户量)和MAU(月活跃用户量)等指标。
地理定位(如GEO):在需要处理地理位置数据的应用中,如滴滴打车等,GEO数据结构可实现高效地理位置查询与存储。
应用场景举例
日活跃用户统计、连续签到打卡情况分析、一周活跃用户列表、特定用户登录天数统计等,均可以通过上述数据类型实现高效、准确的数据统计与分析。
以抖音应用的最新留言评价为例,需要对评论进行排序与分页显示,此时可使用Redis数据结构实现排序与分页功能,提高用户体验。
关于签到打卡统计,bitmap数据类型能够高效记录用户是否签到的状态,节省存储空间,且便于计算连续签到天数等统计指标。
基数统计如hyperloglog,则适用于处理大量数据的UV与PV等统计需求,通过概率算法降低内存占用,牺牲部分准确率以换取更高的效率。
GEO数据结构在地理信息处理中,如滴滴打车定位车辆位置,通过GEOHash算法将三维坐标转换为一维点块,再进行高效查询。
综合而言,Redis提供的多种数据类型与操作命令,能够针对不同场景与需求提供高效的数据存储与统计分析能力,实现大数据环境下应用的性能优化。
2024-12-24 10:03
2024-12-24 09:30
2024-12-24 08:23
2024-12-24 08:17
2024-12-24 08:12
2024-12-24 07:32