redis计算经纬度距离

Posted 野生java研究僧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis计算经纬度距离相关的知识,希望对你有一定的参考价值。

使用场景:
1.用户查询附近的酒店
2.游戏查看附件一起玩的人
3.交友app查看附件的人
注意:redis需要从3.2版本开始才支持

import lombok.NonNull;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * redis经纬度计算工具类
 *
 * @author compass
 * @date 2023-02-12
 * @since 1.0
 **/
@Component
public class GeoUtils 

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public static final String GEO_CACHE_KEY = "geo_cache_key";

    /**
     * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
     *
     * @param cacheKey 缓存key
     * @param point    经纬度位置
     * @param certId   成员标识
     * @return boolean
     * @author compass
     * @date 2023/2/12 23:39
     * @since 1.0.0
     **/
    public boolean geoAdd(String cacheKey, Point point, String certId) 
        Long result = redisTemplate.opsForGeo().add(cacheKey, point, certId);
        return result != null && result > 0;
    


    /**
     * 将经纬度信息添加到redis中
     *
     * @param cacheKey 缓存主键
     * @param params   params key为成员标识,value为经纬度信息
     * @return boolean
     * @author compass
     * @date 2023/2/13 9:57
     * @since 1.0.0
     **/
    public boolean geoAddAll(String cacheKey, Map<Object, Point> params) 
        GeoOperations<String, Object> ops = redisTemplate.opsForGeo();
        Long result = ops.add(cacheKey, params);
        return result != null && result > 0;

    

    /**
     * 计算两个人之间的距离
     *
     * @param cacheKey    缓存主键
     * @param selfCertId  第一个标识
     * @param otherCertId 第二个标识
     * @return double
     * @author compass
     * @date 2023/2/13 10:23
     * @since 1.0.0
     **/
    public double distanceBetween(String cacheKey, String selfCertId, String otherCertId) 
        GeoOperations<String, Object> geoOperations = redisTemplate.opsForGeo();
        Distance distance = geoOperations.distance(cacheKey, selfCertId, otherCertId);
        if (distance != null) 
            return distance.getValue();
        
        return -1;
    


    /**
     * 查询距离某个人指定范围内的人,包括距离多少米
     *
     * @param cacheKey 缓存主键
     * @param certId   目标标识
     * @param distance 距离(米)
     * @param limit    距离单位
     * @param limit    限制个数
     * @return java.util.Map<java.lang.String, java.lang.Double>
     * @author compass
     * @date 2023/2/13 9:59
     * @since 1.0.0
     **/
    public Map<String, Double> distanceInclude(String cacheKey, String certId, double distance, long limit, RedisGeoCommands.DistanceUnit distanceUnit) 
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                .sortAscending()// 排序
                .limit(limit)// 输出元素的个数
                .includeCoordinates();// 输出经纬度
        GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResults = redisTemplate.opsForGeo().radius(cacheKey, certId, new Distance(distance, distanceUnit), geoRadiusCommandArgs);
        HashMap<String, Double> resultMap = new HashMap<>();
        if (geoResults != null) 
            List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> content = geoResults.getContent();
            for (GeoResult<RedisGeoCommands.GeoLocation<Object>> item : content) 
                RedisGeoCommands.@NonNull GeoLocation<Object> itemContent = item.getContent();
                String otherCertId = itemContent.getName().toString();
                double between = distanceBetween(cacheKey, certId, otherCertId);
                resultMap.put(otherCertId, between);
            
        
        return resultMap;
    

    /**
     * 查询距离某个人指定范围内的人,包括距离多少米
     * @param cacheKey 缓存主键
     * @param certId   目标标识
     * @param distance 距离(米)
     * @return java.util.Map<java.lang.String, java.lang.Double>
     * @author compass
     * @date 2023/2/13 11:06
     * @since 1.0.0
     **/
    public Map<String, Double> distanceInclude(String cacheKey, String certId, double distance) 
        Map<String, Double> map = new LinkedHashMap<>();
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = geoOperations.radius(cacheKey, certId, new Distance(distance), geoRadiusCommandArgs.includeDistance());
        if (geoResults != null) 
            Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>> iterator = geoResults.iterator();
            while (iterator.hasNext()) 
                GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult = iterator.next();
                // 与目标点相距的距离信息
                Distance geoResultDistance = geoResult.getDistance();
                // 该点的信息
                RedisGeoCommands.GeoLocation<String> geoResultContent = geoResult.getContent();
                map.put(geoResultContent.getName(), geoResultDistance.getValue());
            
        
        return map;
    


    /**
     * 获取指定目标的经纬度
     *
     * @param cacheKey 缓存主键
     * @param certId   目标标识
     * @return java.util.List<org.springframework.data.geo.Point>
     * @author compass
     * @date 2023/2/13 3:06
     * @since 1.0.0
     **/
    public List<Point> position(String cacheKey, String certId) 
        return redisTemplate.opsForGeo().position(cacheKey, certId);
    

    /**
     * 将指定单位从geo中异常
     *
     * @param cacheKey 缓存主键
     * @param certIds  成员标识
     * @return boolean
     * @author compass
     * @date 2023/2/13 9:56
     * @since 1.0.0
     **/
    public boolean remove(String cacheKey, String... certIds) 
        Long result = redisTemplate.opsForGeo().remove(cacheKey, certIds);
        return result != null && result > 0;
    

    /**
     * 获取地理位置的哈希值
     *
     * @param cacheKey 缓存主键
     * @param certIds  成员标识
     * @return java.util.List<java.lang.String>
     * @author compass
     * @date 2023/2/13 10:22
     * @since 1.0.0
     **/
    public List<String> hashByCertId(String cacheKey, String... certIds) 
        return redisTemplate.opsForGeo().hash(cacheKey, certIds);
    


以上是关于redis计算经纬度距离的主要内容,如果未能解决你的问题,请参考以下文章

redis 简介,安装

REDIS10_GEO添加距离半径命令美团附近酒店推送案例

Redis三种特殊数据类型

Redis三种特殊数据类型

Redis学习--- 三种特殊数据类型(GeospatialHyperloglogBitmap)

redis&nginx入门