基于Redisson实现附近的人-Java示例

使用Redisson实现"附近的人"功能可以通过Redis的地理空间索引特性来完成。Redis的地理空间数据结构允许你将地理位置信息(经度和纬度)与某个键关联,并且能够查询给定范围内的所有键。

原理:

Redis 的 GEO 命令集基于 geohash,它将二维的经纬度转换成一个字符串。Redis 使用这些 geohashes 来快速检索特定区域内的元素。当你添加一个地理位置时,Redis 会计算其 geohash,并将其存储在排序集合中。当你查询附近的用户时,Redis 会找到 geohash 范围内的所有用户,计算它们与给定点的距离,并返回结果。 Redis的GEO数据结构基于排序集合(sorted set),其中每个成员都与一个地理位置(经度和纬度)关联。Redis使用geohash技术将地理位置编码为一个字符串,并将其存储在排序集合中。这允许执行高效的范围查询来找到接近某个点的成员。

代码:

首先,确保你的项目中包含了Redisson的依赖:

xml 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>最新版本</version>
</dependency>

创建一个服务,该服务提供方法来添加用户位置和查询附近的用户。

java 复制代码
import org.redisson.api.GeoUnit;
import org.redisson.api.RGeo;
import org.redisson.api.RedissonClient;
import org.redisson.api.geo.GeoSearchArgs;
import org.redisson.api.geo.OptionalGeoSearch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class GeospatialService {

    @Autowired
    private RedissonClient redissonClient;

    private final String GEO_KEY = "users:location";

    public void addUserLocation(String userId, double longitude, double latitude) {
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY);
        geo.add(longitude, latitude, userId);
    }

    public Map<String, Double> findNearbyUsers(double longitude, double latitude, double radius, GeoUnit unit) {
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY);
        return geo.search(GeoSearchArgs.from(longitude, latitude).radius(radius, unit))
                   .entrySet()
                   .stream()
                   .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDistance()));
    }
}

import org.redisson.api.GeoUnit;
import org.redisson.api.RGeo;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class GeospatialService {

    @Autowired
    private RedissonClient redissonClient;

    private final String GEO_KEY = "users:location";

    public void addUserLocation(String userId, double longitude, double latitude) {
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY);
        geo.add(longitude, latitude, userId);
    }

    public Map<String, Double> findNearbyUsers(String userId, double radius, GeoUnit unit) {
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY);
        return geo.radiusWithDistance(userId, radius, unit);
    }
}

当然高版本中可以使用:

arduino 复制代码
public Map<String, Double> findNearbyUsers(double longitude, double latitude, double radius, GeoUnit unit) {  
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY);  
        // 获取附近的人,并计算他们与指定位置的距离  
        return geo.radius(longitude, latitude, radius, unit)  
                .stream()  
                .collect(Collectors.toMap(  
                        geoPosition -> geoPosition.getMember(), // 用户ID  
                        geoPosition -> geoPosition.getDistance() // 距离  
                ));  
    }

在这个服务中:

  • addUserLocation 方法将用户的地理位置信息添加到Redis中。这里使用的是 RGeo 对象,它是Redisson提供的地理空间操作的接口。
  • findNearbyUsers 方法接受一个经度、纬度和搜索半径,并返回一个Map,其中包含在指定范围内的用户ID及其到中心点的距离。
  • 当调用 findNearbyUsers 方法时,Redisson会发送一个 GEORADIUSGEORADIUSBYMEMBER 命令到Redis服务器,该命令会计算出在指定半径内的所有位置,并返回它们。

优点

高效:Redis的地理空间索引查询非常快,适合实时应用。 简单:Redisson为复杂的Redis命令提供了简单的Java API,使得操作变得简单直观。 可扩展:Redis是可扩展的,可以处理大量的位置数据和高并发的查询。

缺点

内存限制:因为Redis是内存数据库,所以存储大量的地理位置数据可能会占用大量内存。 持久性和备份:虽然Redis提供了持久化选项,但它是以牺牲一定的性能为代价的。在数据量非常大的情况下,备份和恢复可能会成为挑战。 精度:geohash编码有固定的精度,可能不适合所有应用场景。

在实际部署时,你可能需要根据你的具体需求调整查询逻辑和性能优化措施。 如果使用 Redis 的 GEO 功能需要 Redis 版本 3.2 或更高。此外确保 Redisson 客户端的版本与你的 Redis 服务器版本兼容。

相关推荐
m0_7482345222 分钟前
【Spring Boot】Spring AOP动态代理,以及静态代理
spring boot·后端·spring
Y编程小白38 分钟前
Redis可视化工具--RedisDesktopManager的安装
数据库·redis·缓存
好评笔记2 小时前
AIGC视频扩散模型新星:Video 版本的SD模型
论文阅读·深度学习·机器学习·计算机视觉·面试·aigc·transformer
程序员小灰2 小时前
当了leader才发现,大厂最想裁掉的,不是上班总迟到的,也不是下班搞失联的,而是经常把这3句话挂在嘴边的!
面试
东软吴彦祖3 小时前
包安装利用 LNMP 实现 phpMyAdmin 的负载均衡并利用Redis实现会话保持nginx
linux·redis·mysql·nginx·缓存·负载均衡
工业甲酰苯胺4 小时前
深入解析 Spring AI 系列:解析返回参数处理
javascript·windows·spring
言之。4 小时前
【Java】面试中遇到的两个排序
java·面试·排序算法
小高不明5 小时前
仿 RabbitMQ 的消息队列2(实战项目)
java·数据库·spring boot·spring·rabbitmq·mvc
DZSpace5 小时前
使用 Helm 安装 Redis 集群
数据库·redis·缓存
言之。6 小时前
【面试】Java 记录一次面试过程 三年工作经验
java·面试·职场和发展