摘要:前言附近的人,這四個字的需求就大有文章可做了。很二逼的做法是,存每個人的經(jīng)度緯度,然后遍歷數(shù)據(jù)庫所有數(shù)據(jù)循環(huán),兩點距離坐標公式。減少掃描行數(shù)來實現(xiàn)減輕數(shù)據(jù)庫的壓力。兩個點的距離越近,他們的編碼前綴部分就相同,前綴部分相同越多,代表距離越近。
前言
??附近的人,這四個字的需求就大有文章可做了。很二逼的做法是,存每個人的經(jīng)度緯度,然后遍歷數(shù)據(jù)庫所有數(shù)據(jù),foreach循環(huán),兩點距離坐標公式。量少的時候,這個沒啥問題。量大了,掃描全表 + 經(jīng)緯度距離運算分分鐘拖垮數(shù)據(jù)庫。那么是否有方案可以解決這個痛點呢,今年就來說下Geohash
實現(xiàn)思路??想要不拖垮數(shù)據(jù),要做到能走索引。就是跟你無關的點,不要掃描。減少掃描行數(shù)來實現(xiàn)減輕數(shù)據(jù)庫的壓力。那么減少掃描行數(shù)肯定要想到索引??墒墙?jīng)緯度有兩個字段,且查詢條件無論怎么寫都沒辦法走索引。那么唯一能想到的就是二維變一維。 geohash基本原理是將地球理解為一個二維平面,將平面遞歸分解成更小的子塊,每個子塊在一定經(jīng)緯度范圍內(nèi)擁有相同的編碼,這種方式簡單粗暴,可以滿足對小規(guī)模的數(shù)據(jù)進行經(jīng)緯度的檢索。兩個點的距離越近,他們的編碼前綴部分就相同,前綴部分相同越多,代表距離越近。然后我們做數(shù)據(jù)庫掃描的時候 可以 WHERE geohash Like "code%"這樣就起到了走索引從而優(yōu)化了執(zhí)行效率。
代碼思路(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 經(jīng)度 */ public static function combination($latitude_str, $longitude_str) { $str = ""; for ($i = 0; $i < strlen($longitude_str); $i++) {//根據(jù)精度表,可發(fā)現(xiàn)維度>=精度 $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) { //根據(jù)一位字符串進行切割 $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 = ""; //根據(jù)兩位字符串切割 $str_arr = str_split($str, 2); foreach ($str_arr as $va) { $longitude_str .= $va[0]; if(isset($va[1])){//根據(jù)精度表,可發(fā)現(xiàn)維度>=精度 $latitude_str .= $va[1]; } } return array( self::LATITUDE=>$latitude_str, self::LONGITUDE=>$longitude_str, ); } /** * 解碼二分區(qū)間 * @param $str * @param string $i//執(zhí)行次數(shù) * @param array $data、、區(qū)間 */ 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); } } /** * 解碼 */ /** * 根據(jù)精度獲取二分次數(shù) * @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]; } /** * 獲取區(qū)間 * @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的話可以近似理解為那個人就在你身邊了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/30978.html
摘要:數(shù)據(jù)將具有如下個特點將二維的經(jīng)緯度轉(zhuǎn)換成字符串,比如下圖展示了北京個區(qū)域的字符串,分別是,等等,每一個字符串代表了某一矩形區(qū)域。例如,坐標對,位于北京安定門附近,后形成的值為。 作者簡介:戴嘉樂( Mr.Maple ) | 前百度高級研發(fā)工程師 | IPFS應用實踐者&布道師|個人網(wǎng)站:https://www.daijiale.cn聯(lián)系方式:微信號:daijiale6239。 show...
摘要:輾轉(zhuǎn)流傳出班車手冊后發(fā)現(xiàn)搜索實在是太不方便了,于是有了一個主義,想做一個可以搜索房子地址,找出附近班車點類似大眾點評的定位搜索附近餐館的功能。 起因 七月份要去某廠報道了,異地租房的時候發(fā)現(xiàn)想租一個有公司班車的地方,卻不知道哪里有班車。輾轉(zhuǎn)流傳出班車手冊后發(fā)現(xiàn)搜索實在是太不方便了,于是有了一個主義,想做一個可以搜索房子地址,找出附近班車點(類似大眾點評的定位搜索附近餐館的功能)?,F(xiàn)在做...
閱讀 1379·2021-11-11 10:57
閱讀 3801·2021-09-07 10:10
閱讀 3494·2021-08-03 14:03
閱讀 3133·2019-08-30 13:45
閱讀 755·2019-08-29 11:19
閱讀 1104·2019-08-28 18:07
閱讀 3169·2019-08-26 13:55
閱讀 881·2019-08-26 12:17