• Redis Geo


    Geo

    GEO的底层结构使用的是Sorted set,由于其score不支持多参数,所以使用GeoHash算法进行编码

    php版GeoHash算法

    使用二分区间 + 区间编码,将经纬度转换成二进制表示

    /**
     * GEO
     * Class GEO
     */
    class GEO
    {
        public function hash($longitude, $latitude, $count)
        {
            $longitudeHash = $this->compute($longitude, $count, 180);
            $latitudeHash = $this->compute($latitude, $count, 90);
    
            $str = '';
            for ($i = 0; $i < $count; $i++) {
                $str .= $longitudeHash[$i] . $latitudeHash[$i];
            }
    
            return $str;
        }
    
        private function compute($value, $count = 5, $max = 180)
        {
            $left = [-$max, 0];
            $right = [0, $max];
            $str = '';
    
            while ($count-- > 0) {
                $copy = [];
                if ($value >= $right[0] && $value <= $right[1]) {
                    $str .= '1';
                    $copy = $right;
                } else {
                    $str .= '0';
                    $copy = $left;
                }
    
                $avg = array_sum($copy) / 2;
                $left = [$copy[0], $avg];
                $right = [$avg, $copy[1]];
            }
    
            return $str;
        }
    }
    
    $geo = new GEO();
    echo $geo->hash(116.37, 39.86, 20);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    GeoHash 算法结果图解
    // 第一列
    echo $geo->hash(-170, -70, 2) . PHP_EOL; //0000
    echo $geo->hash(-170, -30, 2) . PHP_EOL; //0001
    echo $geo->hash(-170, 30, 2) . PHP_EOL; //0100
    echo $geo->hash(-170, 70, 2) . PHP_EOL; //0101
    
    //第二列
    echo $geo->hash(-70, -70, 2) . PHP_EOL; //0010
    echo $geo->hash(-70, -30, 2) . PHP_EOL; //0011
    echo $geo->hash(-70, 30, 2) . PHP_EOL; //0110
    echo $geo->hash(-70, 70, 2) . PHP_EOL; //0111
    
    //第三列
    echo $geo->hash(70, -70, 2) . PHP_EOL; //1000
    echo $geo->hash(70, -30, 2) . PHP_EOL; //1001
    echo $geo->hash(70, 30, 2) . PHP_EOL; //1100
    echo $geo->hash(70, 70, 2) . PHP_EOL; //1101
    
    //第四列
    echo $geo->hash(170, -70, 2) . PHP_EOL; //1010
    echo $geo->hash(170, -30, 2) . PHP_EOL; //1011
    echo $geo->hash(170, 30, 2) . PHP_EOL; //1110
    echo $geo->hash(170, 70, 2) . PHP_EOL; //1111
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    可能GeoHash不太好理解,下面我从其大致的结果画图进行分析

    在这里插入图片描述

    从图中不难看出,值越接近的块的区域是比较近的,但是存在一点误差(比如:0111->1000),所以要多取周围几个块进行比较

    Geo使用
    1. GEOADD key longitude latitude member 给key的指定位置(member) 添加经纬度信息
    # GEOADD key longitude latitude member 给key的指定位置(member) 添加经纬度信息
    # member:key中的位置
    geoadd car_locations 116.37 39.86 1001
    geoadd car_locations 116.55 39.93 1002
    geoadd car_locations 117.12 41.22 1003
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. GEOPOS key member
    # geopos key member 展示指定key的指定位置
    geopos car_locations 1001
    
    • 1
    • 2
    1. GEODIST key member1 member2 [m|km|ft|mi] 返回两个位置的距离,常用单位m,km
    # GEODIST key member1 member2 [m|km|ft|mi] 返回两个位置的距离,常用单位m,km
    geodist car_locations 1001 1002 km
    
    • 1
    • 2
    1. GEORADIUS key longitude latitude radius [m|km|ft|mi],以经纬度为圆心,从key中查找符合指定radius距离的位置
    # GEORADIUS key longitude latitude radius m|km|ft|mi,以经纬度为圆心,从key中查找符合指定radius距离的位置
    georadius car_locations 116.33 39.82 8 km 
    
    # 后面可以跟一些排序,条数
    # 获取符合条件的倒序的两个位置
    georadius car_locations 116.33 39.82 200 km desc count 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.由于底层使用的是Sorted sort,故可以使用其相关操作方法

  • 相关阅读:
    java-net-php-python-63java长途汽车站售票系统计算机毕业设计程序
    算法|每日一题|只出现一次的数字Ⅱ|位运算
    使用uniapp开发APP时的调试/安卓打包等
    pytorch无法使用cuda
    【LeetCode】5. 最长回文子串
    C#网页打印功能实现
    TCP 三次握手与四次挥手深入探究(大图解)
    php实战案例记录(4)`include`和`require_once`的区别和用法
    Navicat连接postgresql时出现‘datlastsysoid does not exist‘报错的问题
    微信小程序
  • 原文地址:https://blog.csdn.net/qq_29744347/article/details/127801604