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);
    }
}

打印效果:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值