Redis那些事儿(三)

这篇具有很好参考价值的文章主要介绍了Redis那些事儿(三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 前言

        接着上一篇Redis那些事儿(二) ,这一篇主要介绍Redis基于Geo数据结构实现的地理服务,它提供了一种方便的方式来存储和处理与地理位置相关的数据。Geo数据结构是Redis的一种特殊数据类型,用于存储地理位置信息,每个地理位置被表示为经度和纬度的坐标,可以将这些坐标与一个或多个成员关联起来。Redis的地理服务提供了一套简单而强大的功能,可以方便地存储和处理与地理位置相关的数据,它适用于许多应用场景,如地理定位、附近的人、附近的店铺搜索、附近的停车场、附近的地铁站…等等,大大提升了定位排序的效率。

2. 常用api介绍

        Redis地理服务API方法包括:GEOADD(向Geo数据结构中添加一个或多个地理位置信息);GEODIST(计算两个地理位置之间的距离);GEORADIUS(获取给定地理位置附近一定范围内的成员);GEOPOS(获取给定成员的经纬度坐标);GEOHASH(获取给定成员的Geohash值)…以上都是Geo地理服务内置的常用方法,接下来还是基于开发中的StringRedisTemplate对象作为切入点,更直观地说明实际应用中对于Geo地理服务地应用。
        StringRedisTemplate中定义了RedisGeoCommands的接口,RedisGeoCommands中封装了一系列的内置方法及子类,所以Redis中基于opsForGeo()的操作都离不开RedisGeoCommands,如下为部分截图:
Redis那些事儿(三),Redis,redis,缓存

Geo数据结构中存入坐标数据,redisTemplate.opsForGeo().add(key, locations)

		List<Park> parks = getParks(); //TODO 获取停车场列表信息
    	//初始化Redis区域对象集合
        List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>();
        for (Park park : parks) {
        	//实例化ponit对象,传参[经度、纬度]
            Point point = new Point(park.getLng(), park.getLat());
            //构造location对象,传参[name值(一般取ID)、point对象]
            RedisGeoCommands.GeoLocation<String> location = new RedisGeoCommands.GeoLocation<>(
                   park.getParkId() + "", point);
            locations.add(location);
        }
        String key = "GEO_PARK_KEY";
        //存入坐标数据
        redisTemplate.opsForGeo().add(key, locations);

Geo数据结构中删除坐标数据,redisTemplate.opsForGeo().remove(key, …members)

		String key = "GEO_PARK_KEY";
		//删除单个坐标数据(parkId为单个停车场ID,类型为String)
		redisTemplate.opsForGeo().remove(key, parkId);
    	//删除多个坐标数据(第一个参数为key,后面可以传入多个parkId)
    	redisTemplate.opsForGeo().remove(key, parkId1, parkId2, parkId3);

Geo数据结构中检索坐标数据由近到远,redisTemplate.opsForGeo().radius(key, within, args)

		String key = "GEO_PARK_KEY";
		//检索20公里内的
		Distance distance = new Distance(20, Metrics.KILOMETERS);
		//以目标坐标为圆心,distance为半径的圆圈范围,其中lng代表中心坐标的经度、lat代表中心坐标的纬度
		Circle within = new Circle(new Point(lng, lat), distance);
		//条件参数,按照距离查询,默认就是升序
		RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance();
		//执行查询
    	GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, within, args);

Geo数据结构中检索坐标数据由近到远,redisTemplate.opsForGeo().search(key, reference, distance, args)

		String key = "GEO_PARK_KEY";
		//检索20公里内的
		Distance distance = new Distance(20, Metrics.KILOMETERS);
		//条件参数,按照距离查询,默认就是升序
		RedisGeoCommands.GeoSearchCommandArgs args = RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance();
		//中心点位确认,其中lng代表中心坐标的经度、lat代表中心坐标的纬度
		GeoReference<String> reference = GeoReference.fromCoordinate(lng, lat);
		//执行查询
    	GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().search(key, reference, distance, args);

        以上列了四个最常用的方式,类似于我们最常规的CURD,其中最后两个radius和search是查询方法,二者最终查询的结果是一致的,只是手段方式不同而已!

3. 需求假设(获取离我最近的停车场)

        这个时候有人就说了:我使用GeodeticCalculator工具类在代码中计算距离也很方便的啊。我想了想,确实很方便,只需要引入geodesy的依赖,就可以直接使用GeodeticCalculator的calculateGeodeticCurve方法就可以计算了,还不需要麻烦的用redis搞那么长的代码了。但是,问题来了,就以停车场为例,假如只有十几个停车场,遍历一下然后按升序排个序,很快就计算出了离我最近的停车场列表了。如果我有上千个或者上万个停车场,总不能遍历上万次然后再排序吧,那这速度就一言难尽了…如果这个时候使用redis的geo数据结构来读取,那就完美解决这个问题了。Redis提供的GeoHash算法功能对于这方面的需求就太好用了,那么,附近的停车场、附近的人、附近的商家就都是一个思路了!

4. 代码示例

	/**
     * 获取距离最近的停车场列表,由近到远
     * @param lng 当前位置经度
     * @param lat 当前位置纬度
     * @param page 页数(第n页)
     * @param size 每页数量(10、20...)
     * @param value 公里范围内(搜索范围半径)
     * @return
     */
    public List<Park> getLatestParks(Double lng, Double lat, Integer page, Integer size, Double value){
        //计算分页起始参数
        Integer start = (page - 1) * size;
        Integer end = page * size;
        //查询redis,按照距离排序
        String key = "GEO_PARK_KEY";
        //检索value公里内的
        Distance distance = new Distance(value, Metrics.KILOMETERS);
        //以目标坐标为圆心,distance为半径的圆圈范围,其中lng代表中心坐标的经度、lat代表中心坐标的纬度
        Circle within = new Circle(new Point(lng, lat), distance);
        //条件参数,按照距离查询,默认就是升序,截止到end
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(end);
        //执行查询
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, within, args);
        if (results == null) {
            return new ArrayList<>();
        }
        //获取最终检索的内容
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = results.getContent();
        //截取从起始到结束,如果总数小于起始数就证明已经页数超了,返回空集合
        if (content.size() <= start) {
            return new ArrayList<>();
        }
        //初始化parkId集合
        List<Long> parkIds = new ArrayList<>();
        //初始化距离map
        Map<String, Distance> distanceMap = new HashMap<>();
        //分页跳过之前的数据,并遍历赋值
        content.stream().skip(start).forEach(i->{
            String parkIdStr = i.getContent().getName();
            parkIds.add(Long.valueOf(parkIdStr));
            Distance dis = i.getDistance();
            distanceMap.put(parkIdStr, dis);
        });
        //固定排序
        String join = StringUtils.join(parkIds,",");
        //根据parkId集合获取park集合
        List<Park> newParks = parkService.list(new QueryWrapper<Park>().in("park_id", parkIds)
                .last("ORDER BY FIELD(park_id," + join + ")")).stream().map(i -> {
                    i.setDistance(distanceMap.get(i.getParkId() + "").getValue());
                    return i;
        }).collect(Collectors.toList());
        return newParks;
    }

以上代码为由近到远获取距离最近的停车场列表的示例方法,仅供参考文章来源地址https://www.toymoban.com/news/detail-744173.html

到了这里,关于Redis那些事儿(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis学习(三)分布式缓存、多级缓存、Redis实战经验、Redis底层原理

    单节点Redis存在着: 数据丢失问题:单节点宕机,数据就丢失了。 并发能力和存储能力问题:单节点能够满足的并发量、能够存储的数据量有限。 故障恢复问题:如果Redis宕机,服务不可用,需要一种自动的故障恢复手段。 RDB持久化 RDB(Redis database backup file,Redis数据库备份

    2024年02月16日
    浏览(27)
  • Redis应用(1)缓存(1.2)------Redis三种缓存问题

    三者出现的根本原因是:Redis缓存命中率下降,请求直接打到DB上了。  一、 缓存穿透: 1、定义: 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。所谓穿透,就是直接透过了redis,直接透到数据库。 2、原因

    2024年01月24日
    浏览(32)
  • 【Redis】Redis作为缓存

    【Redis】Redis常见面试题(2) 缓存在计算机系统中有着重要的作用,它可以显著提高系统的性能和响应速度 提升系统性能: 缓存将常用的数据或计算结果存储在高速的存储介质中,如内存,以便快速地响应请求。通过减少对慢速存储介质(如硬盘或数据库)的访问次数,可

    2024年02月09日
    浏览(27)
  • 【Redis-02】Redis的缓存

    缓存( Cache),就是数据交换的 缓冲区 ,俗称的缓存就是 缓冲区内的数据 。 一句话:因为 速度快,好用 。缓存数据存储于代码中,而代码运行在内存中, 内存的读写性能远高于磁盘 ,缓存可以大大降低 用户访问并发量带来的 服务器读写压力。 使用根据id查询的例子来进行说明 1.3

    2024年02月16日
    浏览(29)
  • redis缓存设计-Redis(八)

    上篇文章介绍了redis缓存设计,热点key,bigkey注意事项。 原创 redis缓存设计-Redis(七) https://blog.csdn.net/ke1ying/article/details/131268967 命令使用 hgetall,lrange,smembers,zrange,sinter等并非不能使用,要指定明确的值,遍历的话要使用 hscan、sscan、zscan 代替。 禁止使用keys,flushall,

    2024年02月10日
    浏览(25)
  • 【Redis(8)】Spring Boot整合Redis和Guava,解决缓存穿透、缓存击穿、缓存雪崩等缓存问题

    在缓存技术的挑战及设计方案我们介绍了使用缓存技术可能会遇到的一些问题,那么如何解决这些问题呢? 在构建缓存系统时,Spring Boot和Redis的结合提供了强大的支持,而Guava的 LoadingCache 则为缓存管理带来了便捷的解决方案。下面我将介绍如何通过整合Spring Boot、Redis和Gu

    2024年04月22日
    浏览(39)
  • redis 缓存雪崩 && 缓存击穿 && 缓存穿透

    什么是缓存雪崩 当我们提到缓存系统中的问题,缓存雪崩是一个经常被讨论的话题。缓存雪崩是指在某一时刻发生大量的缓存失效,导致瞬间大量的请求直接打到了数据库,可能会导致数据库瞬间压力过大甚至宕机。尤其在高并发的系统中,这种情况会导致连锁反应,整个系

    2024年02月07日
    浏览(36)
  • Redis 缓存穿透、缓存雪崩、缓存击穿

    缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。 常见的解决方案有两种:         缓存空对象                  优点:实现简单,维护方便                 缺点: 额外的内存消耗 可能造

    2024年02月02日
    浏览(31)
  • Redis-缓存穿透、缓存崩溃、缓存击穿

    本文主要介绍Redis中缓存穿透、缓存崩溃和缓存击穿 一般情况下,用户请求到后台,会先从缓存中取数据。如果在缓存中取到数据,就直接返回 结果;如果取不到数据就需要查询数据库,从数据库中取到数据后会同步更新到缓存,并返回结果。下一个用户就可以直接从缓存中

    2024年02月16日
    浏览(27)
  • Redis学习(三)持久化机制、分布式缓存、多级缓存、Redis实战经验

    单节点Redis存在着: 数据丢失问题:单节点宕机,数据就丢失了。 并发能力和存储能力问题:单节点能够满足的并发量、能够存储的数据量有限。 故障恢复问题:如果Redis宕机,服务不可用,需要一种自动的故障恢复手段。 RDB持久化 RDB(Redis database backup file,Redis数据库备份

    2024年02月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包