日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

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

發(fā)布時(shí)間:2024/3/24 php 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 geohash php_场景解决方案:附近的人(GeoHash的应用) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

附近的人,這四個(gè)字的需求就大有文章可做了。很二逼的做法是,存每個(gè)人的經(jīng)度緯度,然后遍歷數(shù)據(jù)庫(kù)所有數(shù)據(jù),foreach循環(huán),兩點(diǎn)距離坐標(biāo)公式。量少的時(shí)候,這個(gè)沒(méi)啥問(wèn)題。量大了,掃描全表 + 經(jīng)緯度距離運(yùn)算分分鐘拖垮數(shù)據(jù)庫(kù)。那么是否有方案可以解決這個(gè)痛點(diǎn)呢,今年就來(lái)說(shuō)下Geohash

實(shí)現(xiàn)思路

想要不拖垮數(shù)據(jù),要做到能走索引。就是跟你無(wú)關(guān)的點(diǎn),不要掃描。減少掃描行數(shù)來(lái)實(shí)現(xiàn)減輕數(shù)據(jù)庫(kù)的壓力。那么減少掃描行數(shù)肯定要想到索引。可是經(jīng)緯度有兩個(gè)字段,且查詢條件無(wú)論怎么寫(xiě)都沒(méi)辦法走索引。那么唯一能想到的就是二維變一維。 geohash基本原理是將地球理解為一個(gè)二維平面,將平面遞歸分解成更小的子塊,每個(gè)子塊在一定經(jīng)緯度范圍內(nèi)擁有相同的編碼,這種方式簡(jiǎn)單粗暴,可以滿足對(duì)小規(guī)模的數(shù)據(jù)進(jìn)行經(jīng)緯度的檢索。兩個(gè)點(diǎn)的距離越近,他們的編碼前綴部分就相同,前綴部分相同越多,代表距離越近。然后我們做數(shù)據(jù)庫(kù)掃描的時(shí)候 可以 WHERE geohash Like 'code%'這樣就起到了走索引從而優(yōu)化了執(zhí)行效率。

代碼思路(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經(jīng)度或緯度

* @param string $str遞歸字符串

* @param int $i 遞歸次數(shù)

* @param int $max_separate_num遞歸總次數(shù)

* @param array $data 區(qū)間值

* @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 經(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ù)一位字符串進(jìn)行切割

$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;

}

/**

* 解碼二進(jìn)制組合

* @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];

}

}

精度值

如圖,當(dāng)前綴碼相同為7相差76米左右,為8相差19米,為9的話可以近似理解為那個(gè)人就在你身邊了。

總結(jié)

以上是生活随笔為你收集整理的geohash php_场景解决方案:附近的人(GeoHash的应用)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。