前言

附近的人,这四个字的需求就大有文章可做了。很二逼的做法是,存每个人的经度纬度,然后遍历数据库所有数据,foreach循环,两点距离坐标公式。量少的时候,这个没啥问题。量大了,扫描全表 + 经纬度距离运算分分钟拖垮数据库。那么是否有方案可以解决这个痛点呢,今年就来说下Geohash

实现思路

想要不拖垮数据,要做到能走索引。就是跟你无关的点,不要扫描。减少扫描行数来实现减轻数据库的压力。那么减少扫描行数肯定要想到索引。可是经纬度有两个字段,且查询条件无论怎么写都没办法走索引。那么唯一能想到的就是二维变一维。 geohash基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码,这种方式简单粗暴,可以满足对小规模的数据进行经纬度的检索。两个点的距离越近,他们的编码前缀部分就相同,前缀部分相同越多,代表距离越近。然后我们做数据库扫描的时候 可以 WHERE geohash Like 'code%'这样就起到了走索引从而优化了执行效率。

代码思路(PHP)

class Geohash

{

const LATITUDE = 1;

const LONGITUDE = 2;

const BASE32 = array(

'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',

'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm',

'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',

'y', 'z');

public static function encode($latitude = 0, $longitude = 0, $level = 11)

{

$latitude_str = self::separate($latitude, '', 1, self::get_precision_level_num($level, self::LATITUDE), self::get_interval_value(self::LATITUDE));

$longitude_str = self::separate($longitude, '', 1, self::get_precision_level_num($level, self::LONGITUDE), self::get_interval_value(self::LONGITUDE));

return self::geohash_encode(self::combination($latitude_str, $longitude_str));

}

public static function decode($geohash)

{

$data = array();

$combination_str = self::geohash_decode($geohash);

$separate_str = self::de_combination($combination_str);

$data[self::LATITUDE] = self::de_separate($separate_str[self::LATITUDE],1,self::get_interval_value(self::LATITUDE));

$data[self::LONGITUDE] = self::de_separate($separate_str[self::LONGITUDE],1,self::get_interval_value(self::LONGITUDE));

return $data;

}

/**

* 编码

*/

/**

* @param float $num经度或纬度

* @param string $str递归字符串

* @param int $i 递归次数

* @param int $max_separate_num递归总次数

* @param array $data 区间值

* @return string

*/

public static function separate($num, $str = '', $i = 1, $max_separate_num = 20, $data = array('min' => -90, 'max' => 90))

{

$count = ($data['max'] - $data['min']) / 2;

$limit_0 = array(

'min' => $data['min'],

'max' => $data['min'] + $count

);

$limit_1 = array(

'min' => $data['min'] + $count,

'max' => $data['max']

);

$str .= $num > $limit_1['min'] ? 1 : 0;

if ($i >= $max_separate_num) {

return $str;

} else {

return self::separate($num, $str, $i + 1, $max_separate_num, $num > $limit_1['min'] ? $limit_1 : $limit_0);

}

}

/**

* @param $latitude_str 纬度

* @param $longitude_str 经度

*/

public static function combination($latitude_str, $longitude_str)

{

$str = '';

for ($i = 0; $i < strlen($longitude_str); $i++) {//根据精度表,可发现维度>=精度

$str .= $longitude_str{$i};

if(isset($latitude_str{$i})){

$str .= $latitude_str{$i};

}

}

return $str;

}

public static function geohash_encode($str)

{

$str_arr = str_split($str, 5);//按5位分割字符串

$encode_str = '';

foreach ($str_arr as $va) {

$decimal = bindec($va);

$encode_str .= self::BASE32[$decimal];

}

return $encode_str;

}

/**

* 编码

*/

/**

* 解码

*/

public static function geohash_decode($str)

{

//根据一位字符串进行切割

$str_arr = str_split($str, 1);

$decode_str = '';

$base32 = array_flip(self::BASE32);

foreach ($str_arr as $va) {

$decode_str .= str_pad(decbin($base32[$va]),5,'0',STR_PAD_LEFT);

}

return (string)$decode_str;

}

/**

* 解码二进制组合

* @param $str

* @return array

*/

public static function de_combination($str)

{

$latitude_str = '';

$longitude_str = '';

//根据两位字符串切割

$str_arr = str_split($str, 2);

foreach ($str_arr as $va) {

$longitude_str .= $va[0];

if(isset($va[1])){//根据精度表,可发现维度>=精度

$latitude_str .= $va[1];

}

}

return array(

self::LATITUDE=>$latitude_str,

self::LONGITUDE=>$longitude_str,

);

}

/**

* 解码二分区间

* @param $str

* @param string $i//执行次数

* @param array $data、、区间

*/

public static function de_separate($str,$i=1,$data = array('min' => -90, 'max' => 90)){

$count = ($data['max'] - $data['min']) / 2;

$limit_0 = array(

'min' => $data['min'],

'max' => $data['min'] + $count

);

$limit_1 = array(

'min' => $data['min'] + $count,

'max' => $data['max']

);

if($str[$i-1]==0){

$data = $limit_0;

}else{

$data = $limit_1;

}

if ($i >= strlen($str)) {

return $data;

} else {

return self::de_separate($str, $i + 1, $data);

}

}

/**

* 解码

*/

/**

* 根据精度获取二分次数

* @param $level

* @param $type

*/

public static function get_precision_level_num($level, $type = self::LATITUDE)

{

$precision = array(

1 => array(

self::LATITUDE => 2,

self::LONGITUDE => 3,

),

2 => array(

self::LATITUDE => 5,

self::LONGITUDE => 5,

),

3 => array(

self::LATITUDE => 7,

self::LONGITUDE => 8,

),

4 => array(

self::LATITUDE => 10,

self::LONGITUDE => 10,

),

5 => array(

self::LATITUDE => 12,

self::LONGITUDE => 13,

),

6 => array(

self::LATITUDE => 15,

self::LONGITUDE => 15,

),

7 => array(

self::LATITUDE => 17,

self::LONGITUDE => 18,

),

8 => array(

self::LATITUDE => 20,

self::LONGITUDE => 20,

),

9 => array(

self::LATITUDE => 22,

self::LONGITUDE => 23,

),

10 => array(

self::LATITUDE => 25,

self::LONGITUDE => 25,

),

11 => array(

self::LATITUDE => 27,

self::LONGITUDE => 28,

),

12 => array(

self::LATITUDE => 30,

self::LONGITUDE => 30,

),

);

return $precision[$level][$type];

}

/**

* 获取区间

* @param $type

* @return mixed

*/

public static function get_interval_value($type = self::LATITUDE)

{

$interval = array(

self::LATITUDE => array(

'min' => -90,

'max' => 90

),

self::LONGITUDE => array(

'min' => -180,

'max' => 180

),

);

return $interval[$type];

}

}

精度值

如图,当前缀码相同为7相差76米左右,为8相差19米,为9的话可以近似理解为那个人就在你身边了。

geohash php_场景解决方案:附近的人(GeoHash的应用)相关推荐

  1. 查找附近的人-geohash使用方法

    geohash已有java的封装: 1,导入geohash的jar包 <dependency><groupId>ch.hsr</groupId><artifa ...

  2. TDengine与中泰证券正式签约,打造金融量化交易场景解决方案

    中泰证券股份有限公司(原名齐鲁证券有限公司)成立于 2001 年 5 月,是全国大型综合类上市券商),在全国 28 个省市自治区设有 45 家分公司.284 家证券营业部,员工 9000 多人,控股中 ...

  3. (转)腾讯区块链方案白皮书:底层技术平台及五大场景解决方案

    腾讯区块链方案白皮书:底层技术平台及五大场景解决方案 2017-04-24 腾讯研究院 日前,腾讯正式发布了区块链方案白皮书,旨在与合作伙伴共同推动可信互联网的发展,打造区块链的共赢生态.与此同时,具 ...

  4. 华为ALL in Al:全面公布AI战略及全栈全场景解决方案,AI芯片将不单独对外销售...

    雷锋网按:历史上成功的顶级科技公司大都经历过相似的处境,在走向伟大的过程中小错误不断,但是决定生死的关键节点却都能走对路,比如微软是第一家真正重视软件的公司,谷歌确立"移动优先"战 ...

  5. 虚拟形象+动作捕捉+虚拟场景,虚拟数字人解锁综艺创意新玩法

    近两年来,元宇宙概念炙手可热,娱乐产业自然也想分一杯羹.继<2060元音之境>上线后,由爱奇艺出品的虚拟现实游戏闯关真人秀<元音大冒险>也在近日与观众见面.本次节目,借助数字人 ...

  6. 直播软件开发,看智播如何为各行业提供直播场景解决方案?

    2019独角兽企业重金招聘Python工程师标准>>> 一.智播的简介 智播,专注于直播应用场景解决方案,为各行业视频直播软件开发提供从底层到应用层的一体化直播应用,针对不同行业和场 ...

  7. 智播,如何为各行业提供直播场景解决方案?

    2019独角兽企业重金招聘Python工程师标准>>> 一.智播的简介 智播,专注于直播应用场景解决方案,为各行业视频直播软件开发提供从底层到应用层的一体化直播应用,针对不同行业和场 ...

  8. KW 新闻 | KaiwuDB 亮相数字中国并发布离散制造场景解决方案

    4月26-30日,以"加快数字中国建设,推进中国式现代化"为主题的第六届数字中国建设峰会在福州市圆满召开.KaiwuDB 受邀亮相大会参展并发布"离散制造场景解决方案&q ...

  9. 逐鹿澳洲市场 宁德时代储能全场景解决方案亮相澳大利亚全能源展

    文|智能相对论 作者|陈先森 全球储能高需求,造就出一条优质赛道. 一方面,国外经历能源危机,很难找到可替代能源,储能设备的经济性更为凸显:另一方面,全球各国陆续推出政策补贴,鼓励推动储能市场快速发展 ...

最新文章

  1. 【硬核干货 | 程序的编译、链接、装载与运行】
  2. sina stock历史数据
  3. 虚拟机克隆,并设置新的ip,配置hostname,配合hostname,hosts
  4. java面试题总结(二)----java中级面试题 含答案
  5. java 什么是内部类_讨论Java中的内部类是什么?
  6. 一张图学会python3高清图-一张图理清 Python3 所有知识点
  7. 2021-07-04应用的生命周期
  8. expect+shell脚本实现免密登录
  9. RRR-RR五边形平面并联机构分析:Kinematics of a five-bar RRR-RR mechanism
  10. 计算机学科a类排名,哈工大17个学科排名位列A类
  11. openssl升级解决系统安全漏洞问题
  12. SV绿皮书笔记(九)暂时完结
  13. 简单hashtab的实现
  14. 华为鸿蒙os 新闻,华为P50无限延期,谁来组成华为鸿蒙OS“头部”?
  15. 【线段树】【cogs775】山海经
  16. serverlet 原理_serverlet_servlet工作原理面试题_serverlet和jsp(3)
  17. 高效的CSS代码(1)
  18. jQuery 绑定3种鼠标事件 click(鼠标点击),mouseover(鼠标移入),mouseout(鼠标移开)
  19. 百万级用户接入PLC远程监控,10%的工控人都在使用的实用工具
  20. 超级操作,海量数据任你爬,无惧ip限制

热门文章

  1. echarts 地图统计
  2. Cognex - DS925B3D相机取像参数配置
  3. Alink在线学习(Online Learning)之Java示例【五】
  4. linux 宏碁 删除分区,宏碁笔记本如何将磁盘C和磁盘D合并成一个分区
  5. mysql限制查询/外连接查询和内连接查询/联合查询
  6. Java web产品开发经验分享
  7. 怎么用计算机打出来江海不渡你,江海不渡你简谱-诗人凉演唱-孙世彦制谱
  8. 学人工智能专业后悔死了?
  9. 小猪的Python学习之旅 —— 18.Python微信转发小宇宙早报
  10. APK安装失败的原因之一