geohash算法二种实现方式

第一种、根据经纬度进行计算,采用java编写

package com.xxxx.sentinel.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author nick
 */
public class GeoHash {


    public static final double  MINLAT = -90;

    public static final double  MAXLAT = 90;

    public static final double  MINLNG = -180;

    public static final double  MAXLNG = 180;

    public static final int ORIGINPRECISION = 30;

    //经纬度二分法
    private static List<Integer> latLng(double latAndLng, double min, double max) {
        List<Integer> lngAndLatList = new ArrayList();
        if (latAndLng < min || latAndLng > max) {
            return null;
        }
        if (ORIGINPRECISION < 1) {
            return null;
        }
        for (int i = 0; i < ORIGINPRECISION; i++) {
            double mid = (min + max) / 2.0;
            if (latAndLng > mid) {
                lngAndLatList.add(1);
                min = mid;
            } else {
                lngAndLatList.add(0);
                max = mid;
            }
        }
        return lngAndLatList;
    }

    public static void main(String[] args) {
        //latLng(31.1688749, 121.3975184);
        //将经纬度转成二分法
        System.out.println(latLng(31.1688749,MINLAT,MAXLAT));
        System.out.println(latLng(121.3975184,MINLNG,MAXLNG));
        //合并经纬度
        System.out.println(listToString(latLng(121.3975184,MINLNG,MAXLNG),latLng(31.1688749,MINLAT,MAXLAT)));
        //二进制转成十进制,5个一组
        System.out.println(twoTurnTen(listToString(latLng(121.3975184,MINLNG,MAXLNG),latLng(31.1688749,MINLAT,MAXLAT))));
        //base32 映射
        System.out.println(baseCode(twoTurnTen(listToString(latLng(121.3975184,MINLNG,MAXLNG),latLng(31.1688749,MINLAT,MAXLAT)))));
    }

    //偶数位放经度,奇数位放纬度
    public static StringBuffer listToString(List<Integer> lngList, List<Integer> latList){
        StringBuffer latAndLng = new StringBuffer();
        for (int i = 0; i < ORIGINPRECISION; i++) {
            latAndLng.append(lngList.get(i) * lngList.get(i));
            latAndLng.append(latList.get(i) * latList.get(i));
        }
        return latAndLng;
    }

    //二进制转成十进制,5个一组
    public static List<Integer> twoTurnTen(StringBuffer latAndLng){
        List<Integer> code =new ArrayList<>();
        int z = 0;
        for(int i=0;i<latAndLng.length() / 5;i++){
            String a = latAndLng.substring(z,z+5);
            code.add(Integer.parseInt(a, 2));
            z = z+5;
        }
        return code;
    }


     //base32 映射
     public static StringBuffer baseCode(List<Integer> code){
         Map<Integer,String> map = new HashMap<>(32);
         map.put(0, "0");
         map.put(1, "1");
         map.put(2, "2");
         map.put(3, "3");
         map.put(4, "4");
         map.put(5, "5");
         map.put(6, "6");
         map.put(7, "7");
         map.put(8, "8");
         map.put(9, "9");
         map.put(10, "b");
         map.put(11, "c");
         map.put(12, "d");
         map.put(13, "e");
         map.put(14, "f");
         map.put(15, "g");
         map.put(16, "h");
         map.put(17, "j");
         map.put(18, "k");
         map.put(19, "m");
         map.put(20, "n");
         map.put(21, "p");
         map.put(22, "q");
         map.put(23, "r");
         map.put(24, "s");
         map.put(25, "t");
         map.put(26, "u");
         map.put(27, "v");
         map.put(28, "w");
         map.put(29, "x");
         map.put(30, "y");
         map.put(31, "z");
         StringBuffer stringBuffer = new StringBuffer();
         for (Integer codes:code) {
              if(map.keySet().contains(codes)){
                  stringBuffer.append(map.get(codes));
              }
         }
         return stringBuffer;
     }
}

第二种、根据redis的GEO实现

package com.xxxx.sentinel.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.List;

/**
 * @author nick
 */
public class GeoHashRedis {
    
    //################################
    // Springboot redis 实现
    //###############################

    @Autowired
    //操作k-v都是字符串的
    StringRedisTemplate stringRedisTemplate;

    /*@Autowired
    RedisTemplate redisTemplate;  //k-v都是对象的*/

    @Autowired
    RedisTemplate<Object, Object> redisTemplate;

    //geoadd 添加地理位置
    private void geoadd(double lat,double lng){
        stringRedisTemplate.opsForGeo().add("geoTest",new Point(31.1688749, 121.3975184),"xxxx");
    }
    //geopos 查看位置信息
    private void geopos(){
        List<Point> position = stringRedisTemplate.opsForGeo().position("genoTest", "xxxx");
        System.out.println(position);
    }
    //geodist 计算距离
    private void geodist(){

    }
    //georadis 查看以某一点为中心,以某长度为半径的成员信息
    private void georadis(){

    }
    //geohash计算geohash值
    private void geohash(){
        stringRedisTemplate.opsForGeo().hash("geoTest","xxxx");
    }

    //############################################################
    // jedis 实现
    //############################################################
    /**
     * 增加地理位置的坐标
     * @param key
     * @param coordinate
     * @param memberName
     * @return
     */
    public static Long geoadd(String key, GeoCoordinate coordinate, String memberName) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geoadd(key,coordinate.getLongitude(),coordinate.getLatitude(),memberName);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis)
                jedis.close();
        }
        return null;
    }

    /**
     * 批量添加地理位置
     * @param key
     * @param memberCoordinateMap
     * @return
     */
    public static Long geoadd(String key, Map<String, GeoCoordinate> memberCoordinateMap){
        RedisProperties.Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geoadd(key, memberCoordinateMap);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
        return null;
    }

    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序,)
     * @param key
     * @param coordinate
     * @param radius
     * @return  List<GeoRadiusResponse>
     */
    public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.georadius(key, coordinate.getLongitude(), coordinate.getLatitude(), radius, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis)
                jedis.close();
        }
        return null;
    }

    /**
     * 根据给定地理位置获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序,)
     * @param key
     * @param member
     * @param radius
     * @return  List<GeoRadiusResponse>
     */
    List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius){
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.georadiusByMember(key, member, radius, GeoUnit.KM, GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis)
                jedis.close();
        }
        return null;
    }


    /**
     * 查询两位置距离
     * @param key
     * @param member1
     * @param member2
     * @param unit
     * @return
     */
    public static Double geoDist(String key, String member1, String member2, GeoUnit unit){
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geodist(key, member1, member2, unit);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis)
                jedis.close();
        }
        return null;
    }

    /**
     * 可以获取某个地理位置的geohash值
     * @param key
     * @param members
     * @return
     */
    public static List<String> geohash(String key, String... members){ 
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geohash(key, members);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis)
                jedis.close();
        }
        return null;
    }

    /**
     * 获取地理位置的坐标
     * @param key
     * @param members
     * @return
     */
    public static List<GeoCoordinate> geopos(String key, String... members){
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.geopos(key, members);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            if (null != jedis) {
                jedis.close();
            }
        }
        return null;
    }
}

参考:https://zhuanlan.zhihu.com/p/90889887
参考:https://blog.csdn.net/xiangnan10/article/details/80225929

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值