Java集成RedisGeo计算两点之间的距离

Java实现RedisGeo计算两点距离

一、概述

        Redis Geo是Redis中专门用于处理地理位置数据的模块,它利用有序集合Sorted Set和Geohash编码技术存储经纬度信息。

        核心功能包括:

        1.GEOADD添加地理坐标

        2.GEODIST计算两点间距离

        3.GEORADIUSGEORADIUSBYMEMBER搜索指定半径内的位置。

        这些特性使得Redis Geo在实现如“查找附近的人或地点、计算间隔距离”等功能时表现出色,特别适用于需要高效地理空间查询的应用场景。

二、依赖

        使用restTemplate的方式,可以更方便的使用redis其它功能。

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.3.2.RELEASE</version>
</dependency>

三、RedisGeo工具类

package com.jwzj.redisdemo.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;

/**
 * RedisGeo工具类
 *
 * @author CQller
 */
@Configuration
public class RedisGeoUtil {

    /**
     * 地点A经纬度在redis中key前缀
     */
    public static final String DEALER_PREFIX_KEY = "GEO:AREA_LONGITUDE_AND_LATITUDE";

    /**
     * redisTemplate。
     */
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 自动装配redisTemplate。
     *
     * @param redisTemplate redisTemplate
     */
    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * Redis添加地点A经纬度
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param name      位置名称
     * @return {@link Long}
     */
    public Long redisGerAdd(double longitude, double latitude, String name) {
        return redisTemplate.opsForGeo().add(DEALER_PREFIX_KEY, new Point(longitude, latitude), name);
    }

    /**
     * 经纬度查距离最近的地点A
     *
     * @param lon 经度
     * @param lat 纬度
     * @return {@link Object}
     */
    public Object recentDealer(double lon, double lat) {
        Circle circle = new Circle(lon, lat, Metrics.KILOMETERS.getMultiplier());
        RedisGeoCommands.GeoRadiusCommandArgs args;
        args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                .includeDistance().includeCoordinates().sortAscending().limit(1);
        return redisTemplate.opsForGeo().radius(DEALER_PREFIX_KEY, circle, args);
    }

    /**
     * 删除指定名称地点A
     *
     * @param dealerName 地点A名称
     * @return {@link List<String>}
     */
    public Long delRedisGeo(String dealerName) {
        return redisTemplate.opsForZSet().remove(DEALER_PREFIX_KEY, dealerName);
    }

    /**
     * 获得经纬度
     *
     * @param key      键名
     * @param nameList 位置名称集合
     * @return {@link List <Point>}
     */
    public List<Point> redisGeoGet(String key, List<String> nameList) {
        return redisTemplate.opsForGeo().position(key, nameList.toArray());
    }

    /**
     * 获得两点之间距离
     *
     * @param key   键名
     * @param name1 位置1
     * @param name2 位置2
     * @return {@link Distance}
     */
    public Distance redisGeoDist(String key, String name1, String name2) {
        return redisTemplate.opsForGeo().distance(key, name1, name2, RedisGeoCommands.DistanceUnit.KILOMETERS);
    }

    /**
     * 根据位置名称获得指定距离的位置信息
     *
     * @param key      键名
     * @param name     位置名称
     * @param distance 距离
     * @param count    数
     * @return {@link Object}
     */
    public Object redisGeoRadius(String key, String name, Double distance, int count) {
        RedisGeoCommands.GeoRadiusCommandArgs args;
        args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(count);
        return redisTemplate.opsForGeo().radius(key, name, new Distance(distance, Metrics.KILOMETERS), args);
    }

    /**
     * 获得位置geohash表示
     *
     * @param key      键名
     * @param nameList 位置名称
     * @return {@link List<String>}
     */
    public List<String> redisGeoHash(String key, List<String> nameList) {
        return redisTemplate.opsForGeo().hash(key, nameList.toArray());
    }

    /**
     * 根据key清除数据
     *
     * @param key 键
     * @return {@link List<String>}
     */
    public Boolean del(String key) {
        System.out.println(DEALER_PREFIX_KEY.replace("{dealerId}", key));
        return redisTemplate.delete(DEALER_PREFIX_KEY.replace("{dealerId}", key));
    }

}

四、请求结果演示

        调用redisGerAdd方法分别录入两个位置的经纬度后,

        使用redisGeoDist方法计算两点之间的距离:

        

### Java项目中使用Redis Geo功能 #### 导入依赖库 为了在Java项目中集成并使用Redis的Geo功能,需要引入Jedis客户端或其他兼容RedisJava客户端。通常情况下,在Maven项目的`pom.xml`文件里添加如下依赖项来获取最新版本的Jedis: ```xml <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.0.1</version> </dependency> ``` #### 初始化连接池配置 建立与Redis服务器之间的稳定连接对于高效执行命令至关重要。下面是一个基于JedisPoolConfig设置连接池参数的例子。 ```java import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class RedisConnection { private static JedisPool pool; public static void init() { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大空闲数 config.setMaxIdle(10); // 设置最小空闲数 config.setMinIdle(5); // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true config.setBlockWhenExhausted(true); String host = "localhost"; int port = 6379; pool = new JedisPool(config, host, port); } public static Jedis getConnection(){ return pool.getResource(); } } ``` #### 执行Geo相关操作 一旦建立了可靠的连接之后就可以调用各种Geo方法来进行地理空间的数据处理了。这里给出几个常见的例子说明如何利用这些API完成特定的任务。 ##### 添加地理位置信息 通过`geoadd`函数向给定键名下插入新的坐标点及其关联的名字成员。 ```java try (Jedis jedis = RedisConnection.getConnection()) { Long result = jedis.geoadd("cities", new GeoCoordinate(13.361389, 38.115556), "Palermo", new GeoCoordinate(15.087269, 37.502669), "Catania"); System.out.println(result + " locations were added."); } catch(Exception e){ e.printStackTrace(); } ``` ##### 查询某个地点的位置 如果想要知道之前存入数据库中的某些地方的具体经纬度,则可以通过`geopos`指令获得它们的确切位置。 ```java try(Jedis jedis = RedisConnection.getConnection()){ List<GeoCoordinate> coordinates = jedis.geopos("cities","Palermo"); if(!coordinates.isEmpty()){ double longitude = coordinates.get(0).getLongitude(); double latitude = coordinates.get(0).getLatitude(); System.out.printf("The position of Palermo is (%f,%f)\n",longitude,latitude); }else{ System.out.println("Location not found!"); } }catch(Exception e){ e.printStackTrace(); } ``` ##### 计算两地间距离 借助于`geodist`命令能够轻松求得任意两个已知坐标的直线距离(单位可选米/千米等)。 ```java try(Jedis jedis = RedisConnection.getConnection()){ Double distance = jedis.geodist("cities","Palermo","Catania","km"); System.out.printf("Distance between Palermo and Catania:%f km\n",distance); }catch(Exception e){ e.printStackTrace(); } ``` 上述代码片段展示了基本的Redis Geo API的应用方式[^1]。除此之外还有更多高级特性等待探索,比如按半径搜索附近的对象(`GEORADIUS`)或是按照会员名称检索周围区域内的实体(`GEORADIUSBYMEMBER`)等功能都可以帮助构建更加复杂而实用的地图服务应用程序[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值