redis实现“附近的人”

最近在做一款交友软件的APP,现在有一个功能需要实现搜索附近的人。后来发现用redis 的GEO功能实现非常简单。

先说一下设计思路,每个用户在登陆的时候都会添加一下经纬度,这个是APP端获取的,然后设置一下这个经纬度到mysql数据库中,最后把经纬度同步到redis数据库中。我们先来了解一下 redis GEO功能。

我们在用到redis的geo功能时候一定要把版本设置到3.2版本以上,3.2版本以上才有这些方法。

核心的用到的pom配置

 <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.4.2</version>
        </dependency>

核心方法

geoadd:增加某个地理位置的坐标。
geopos:获取某个地理位置的坐标。
geodist:获取两个地理位置的距离。
georadius:根据给定地理位置坐标获取指定范围内的地理位置集合。
georadiusbymember:根据给定地理位置获取指定范围内的地理位置集合。
geohash:获取某个地理位置的geohash值。

具体实现代码:

实体类:

package com.example.demo.entity;

import lombok.Data;

/**
 * @author XuYangWei
 * @Description:
 * @Date 2021/7/21 11:41
 */
@Data
public class Coordinate {

    double latitude;
    double longitude;
    String key;
}

工具包:

package com.example.demo.utils;

import com.example.demo.entity.Coordinate;
import redis.clients.jedis.*;
import redis.clients.jedis.params.GeoRadiusParam;

import java.util.List;

public class RedisUtil {
       private static JedisPool jedisPool = null;
        // Redis服务器IP  
        private static String ADDR = "127.0.0.1";
        // Redis的端口号  
        private static int PORT = 6379;
        // 访问密码  
//        private static String AUTH = "";
  
        /** 
         * 初始化Redis连接池 
         */  
        static {  
            try {  
                JedisPoolConfig config = new JedisPoolConfig();
                // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true  
                config.setBlockWhenExhausted(true);  
                // 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)  
                config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");  
                // 是否启用pool的jmx管理功能, 默认true  
                config.setJmxEnabled(true);  
                // 最大空闲连接数, 默认8个 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。  
                config.setMaxIdle(8);  
                // 最大连接数, 默认8个  
                config.setMaxTotal(200);  
                // 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;  
                config.setMaxWaitMillis(1000 * 100);  
                // 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;  
                config.setTestOnBorrow(true);  
                jedisPool = new JedisPool(config, ADDR, PORT, 3000);
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
        /** 
         * 获取Jedis实例 
         *  
         * @return 
         */  
        public synchronized static Jedis getJedis() {  
            try {  
                if (jedisPool != null) {  
                    Jedis resource = jedisPool.getResource();  
                    return resource;  
                } else {  
                    return null;  
                }  
            } catch (Exception e) {  
                e.printStackTrace();  
                return null;  
            }  
        }  
  
        /** 
         * 释放jedis资源 
         *  
         * @param jedis 
         */  
        public static void close(final Jedis jedis) {  
            if (jedis != null) {  
                jedis.close();  
            }  
        }  
  
  
        /** 
         * 添加坐标 
         * key 经度  维度  距离 
         * return m 表示单位为米*/  
        public static Long addReo(Coordinate coordinate) {  
            Jedis jedis = null;  
            try {  
                jedis = jedisPool.getResource();  
                //第一个参数可以理解为表名  
                return jedis.geoadd("test",coordinate.getLongitude(),coordinate.getLatitude(),coordinate.getKey());  
            } catch (Exception e) {  
                System.out.println(e.getMessage());  
            } finally {  
                if (null != jedis)  
                    jedis.close();  
            }  
            return null;  
        }  
        /** 
         * 查询附近人 
         * key 经度  维度  距离 
         * return GeoRadiusResponse*/  
        public static List<GeoRadiusResponse> geoQuery(Coordinate coordinate) {
            Jedis jedis = null;  
            try {  
                jedis = jedisPool.getResource();  
                //200F GeoUnit.KM表示km   
                return jedis.georadius("test",coordinate.getLongitude(),coordinate.getLatitude(),200F, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist());
            } catch (Exception e) {  
                System.out.println(e.getMessage());  
            } finally {  
                if (null != jedis)  
                    jedis.close();  
            }  
            return null;  
        }


}  

测试方法:

package com.example.demo;

import com.example.demo.entity.Coordinate;
import com.example.demo.utils.RedisUtil;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.Jedis;

import java.util.List;

import static com.example.demo.utils.RedisUtil.addReo;
import static com.example.demo.utils.RedisUtil.geoQuery;

/**
 * @author XuYangWei
 * @Description:
 * @Date 2021/7/21 11:48
 */
public class TestRedis {
    public static void main(String[] args) {
        Jedis jedis = RedisUtil.getJedis();
        java.text.DecimalFormat df = new java.text.DecimalFormat("#.######");//保留六位小数
        //添加经纬度
        Coordinate coordinate = new Coordinate();
        coordinate.setLatitude(31.244803);  //维度
        coordinate.setLongitude(121.483671); //经度
        coordinate.setKey("1");  //可以作为用户表的id

        //添加经纬度
        Coordinate coordinate1 = new Coordinate();
        coordinate1.setLatitude(31.245321);  //维度
        coordinate1.setLongitude(121.485015); //经度
        coordinate1.setKey("2");  //可以作为用户表的id

        //添加经纬度
        Coordinate coordinate2 = new Coordinate();
        coordinate2.setLatitude(31.245456);  //维度
        coordinate2.setLongitude(121.485285); //经度
        coordinate2.setKey("3");  //可以作为用户表的id

        addReo(coordinate);
        addReo(coordinate1);
        addReo(coordinate2);

        //添加经纬度
        coordinate.setLatitude(31.244803);  //维度
        coordinate.setLongitude(121.483671); //经度
        coordinate.setKey("1");  //用户表的id 以当前用户作为查询条件,查询他周围的人数
        List<GeoRadiusResponse> list = geoQuery(coordinate);
        for (GeoRadiusResponse geo : list) {
            System.out.println(geo.getMemberByString()); //主键 有主键了个人信息就很简单了
            System.out.println(df.format(geo.getDistance()));  //距离多少米
        }

        RedisUtil.close(jedis);
    }
}

打印效果:

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
定位功能可以使用 Redis 的地理位置数据结构来实现Redis 使用的地理位置数据结构是有序合(Sorted Set),每个元素都有一个对应的经度和纬度值,可以根据这些值来进行地理位置的计算和查询。 通过 Redis 的地理位置命令,你可以将地点和坐标添加到有序合中,并且可以通过坐标计算两个地点之间的距离,或者获取某个地点周围指定范围内的其他地点。 以下是一些常用的 Redis 地理位置命令: - `GEOADD key longitude latitude member [longitude latitude member ...]`:将一个或多个地点及其经纬度添加到指定的有序合中。 - `GEODIST key member1 member2 [unit]`:计算两个地点之间的距离。可以指定单位(如m、km、mi、ft)。 - `GEOPOS key member [member ...]`:获取一个或多个地点的经纬度坐标。 - `GEORADIUS key longitude latitude radius m|km|mi|ft [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]`:获取指定坐标周围指定范围内的地点。可以选择返回结果中包含坐标、距离、哈希值等信息,并可以限制返回结果的数量和排序方式。 - `GEORADIUSBYMEMBER key member radius m|km|mi|ft [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]`:与 `GEORADIUS` 类似,不过是根据一个地点的 member 值来查询周围的地点。 这些命令可以用于实现地理定位相关的功能,例如附近的人、周边商店、地点推荐等。你可以根据自己的需求选择合适的命令进行使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值