摘要:前言附近的人,这四个字的需求就大有文章可做了。很二逼的做法是,存每个人的经度纬度,然后遍历数据库所有数据循环,两点距离坐标公式。减少扫描行数来实现减轻数据库的压力。两个点的距离越近,他们的编码前缀部分就相同,前缀部分相同越多,代表距离越近。
前言
附近的人,这四个字的需求就大有文章可做了。很二逼的做法是,存每个人的经度纬度,然后遍历数据库所有数据,foreach循环,两点距离坐标公式。量少的时候,这个没啥问题。量大了,扫描全表 + 经纬度距离运算分分钟拖垮数据库。那么是否有方案可以解决这个痛点呢,今年就来说下Geohash
实现思路想要不拖垮数据,要做到能走索引。就是跟你无关的点,不要扫描。减少扫描行数来实现减轻数据库的压力。那么减少扫描行数肯定要想到索引。可是经纬度有两个字段,且查询条件无论怎么写都没办法走索引。那么唯一能想到的就是二维变一维。 geohash基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码,这种方式简单粗暴,可以满足对小规模的数据进行经纬度的检索。两个点的距离越近,他们的编码前缀部分就相同,前缀部分相同越多,代表距离越近。然后我们做数据库扫描的时候 可以 WHERE geohash Like "code%"这样就起到了走索引从而优化了执行效率。
代码思路(PHP)-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的话可以近似理解为那个人就在你身边了。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/30978.html
摘要:数据将具有如下个特点将二维的经纬度转换成字符串,比如下图展示了北京个区域的字符串,分别是,等等,每一个字符串代表了某一矩形区域。例如,坐标对,位于北京安定门附近,后形成的值为。 作者简介:戴嘉乐( Mr.Maple ) | 前百度高级研发工程师 | IPFS应用实践者&布道师|个人网站:https://www.daijiale.cn联系方式:微信号:daijiale6239。 show...
摘要:辗转流传出班车手册后发现搜索实在是太不方便了,于是有了一个主义,想做一个可以搜索房子地址,找出附近班车点类似大众点评的定位搜索附近餐馆的功能。 起因 七月份要去某厂报道了,异地租房的时候发现想租一个有公司班车的地方,却不知道哪里有班车。辗转流传出班车手册后发现搜索实在是太不方便了,于是有了一个主义,想做一个可以搜索房子地址,找出附近班车点(类似大众点评的定位搜索附近餐馆的功能)。现在做...
阅读 1268·2021-11-11 10:57
阅读 3690·2021-09-07 10:10
阅读 3429·2021-08-03 14:03
阅读 3046·2019-08-30 13:45
阅读 659·2019-08-29 11:19
阅读 1020·2019-08-28 18:07
阅读 3066·2019-08-26 13:55
阅读 774·2019-08-26 12:17