gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

教你使用PHP實現查找你想要的附近人

最近有個業務場景使用到了查找附近的人,于是查閱了相關資料,并對使用PHP實現相關功能的多種方式和具體實現做一篇技術總結,歡迎各位看官提出意見和糾錯,下面開始進入正題:

LBS(基于位置的服務)

查找附近的人有個更大的專有名詞叫做LBS(基于位置的服務),LBS是指是指通過電信移動運營商的無線電通訊網絡或外部定位方式,獲取移動終端用戶的位置信息,在GIS平臺的支持下,為用戶提供相應服務的一種增值業務。因此首先得獲取用戶的位置,獲取用戶的位置有基于GPS、基于運營商基站、WIFI等方式,一般由客戶端獲取用戶位置的經緯度坐標上傳至應用服務器,應用服務器對用戶坐標進行保存,客戶端獲取附近的人數據的時候,應用服務器基于請求人的地理位置配合一定的條件(距離,性別,活躍時間等)去數據庫進行篩選和排序。

根據經緯度如何得出兩點之間的距離?

我們都知道平面坐標內的兩點坐標可以使用平面坐標距離公式來計算,但經緯度是利用三度空間的球面來定義地球上的空間的球面坐標系統,假定地球是正球體,關于球面距離計算公式如下:

教你使用PHP實現查找你想要的附近人

具體推斷過程有興趣的推薦這篇文章:【數學公式及推導】根據經緯度計算地面兩點間的距離

PHP函數代碼如下:

/**      * 根據兩點間的經緯度計算距離      * @param $lat1      * @param $lng1      * @param $lat2      * @param $lng2      * @return float      */     public static function getDistance($lat1, $lng1, $lat2, $lng2){         $earthRadius = 6367000; //approximate radius of earth in meters         $lat1 = ($lat1 * pi() ) / 180;         $lng1 = ($lng1 * pi() ) / 180;         $lat2 = ($lat2 * pi() ) / 180;         $lng2 = ($lng2 * pi() ) / 180;         $calcLongitude = $lng2 - $lng1;         $calcLatitude = $lat2 - $lat1;         $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);         $stepTwo = 2 * asin(min(1, sqrt($stepOne)));         $calculatedDistance = $earthRadius * $stepTwo;         return round($calculatedDistance);     }

MySQL代碼如下:

SELECT     id, (       3959 * acos (         cos ( radians(78.3232) )         * cos( radians( lat ) )         * cos( radians( lng ) - radians(65.3234) )         + sin ( radians(78.3232) )         * sin( radians( lat ) )       )     ) AS distance   FROM markers   HAVING distance < 30   ORDER BY distance   LIMIT 0 , 20;

除了上面通過計算球面距離公式來獲取,我們可以使用某些數據庫服務得到,比如Redis和MongoDB:

Redis 3.2提供GEO地理位置功能,不僅可以獲取兩個位置之間的距離,獲取指定位置范圍內的地理信息位置集合也很簡單。Redis命令文檔

1.增加地理位置

GEOADD key longitude latitude member [longitude latitude member ...]

2.獲取地理位置

GEOPOS key member [member ...]

3.獲取兩個地理位置的距離

GEODIST key member1 member2 [unit]

4.獲取指定經緯度的地理信息位置集合

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

5.獲取指定成員的地理信息位置集合

GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

MongoDB專門針對這種查詢建立了地理空間索引。 2d和2dsphere索引,分別是針對平面和球面。 MongoDB文檔

1.添加數據

db.location.insert( {uin : 1 , loc : { lon : 50 , lat : 50 } } )

2.建立索引

db.location.ensureIndex( { loc : "2d" } )

3.查找附近的點

db.location.find( { loc :{ $near : [50, 50] } )

4.最大距離和限制條數

db.location.find( { loc : { $near : [50, 50] , $maxDistance : 5 } } ).limit(20)

5.使用geoNear在查詢結果中返回每個點距離查詢點的距離

db.runCommand( { geoNear : "location" , near : [ 50 , 50 ], num : 10, query : { type : "museum" } } )

6.使用geoNear附帶查詢條件和返回條數,geoNear使用runCommand命令不支持find查詢中分頁相關limit和skip參數的功能

db.runCommand( { geoNear : "location" , near : [ 50 , 50 ], num : 10, query : { uin : 1 } })

PHP多種方式和具體實現

1.基于MySql

成員添加方法:

public function geoAdd($uin, $lon, $lat) {     $pdo = $this->getPdo();     $sql = 'INSERT INTO `markers`(`uin`, `lon`, `lat`) VALUES (?, ?, ?)';     $stmt = $pdo->prepare($sql);     return $stmt->execute(array($uin, $lon, $lat)); }

查詢附近的人(支持查詢條件和分頁):

public function geoNearFind($lon, $lat, $maxDistance = 0, $where = array(), $page = 0) {     $pdo = $this->getPdo();     $sql = "SELECT                 id, (                   3959 * acos (                     cos ( radians(:lat) )                     * cos( radians( lat ) )                     * cos( radians( lon ) - radians(:lon) )                     + sin ( radians(:lat) )                     * sin( radians( lat ) )                   )                 ) AS distance               FROM markers";      $input[':lat'] = $lat;     $input[':lon'] = $lon;      if ($where) {         $sqlWhere = ' WHERE ';         foreach ($where as $key => $value) {             $sqlWhere .= "`{$key}` = :{$key} ,";             $input[":{$key}"] = $value;         }         $sql .= rtrim($sqlWhere, ',');     }      if ($maxDistance) {         $sqlHaving = " HAVING distance < :maxDistance";         $sql .= $sqlHaving;         $input[':maxDistance'] = $maxDistance;     }      $sql .= ' ORDER BY distance';      if ($page) {         $page > 1 ? $offset = ($page - 1) * $this->pageCount : $offset = 0;         $sqlLimit = " LIMIT {$offset} , {$this->pageCount}";         $sql .= $sqlLimit;     }      $stmt = $pdo->prepare($sql);     $stmt->execute($input);     $list = $stmt->fetchAll(PDO::FETCH_ASSOC);      return $list; }

2.基于Redis(3.2以上)

PHP使用Redis可以安裝redis擴展或者通過composer安裝predis類庫,本文使用redis擴展來實現。

成員添加方法:

public function geoAdd($uin, $lon, $lat) {     $redis = $this->getRedis();     $redis->geoAdd('markers', $lon, $lat, $uin);     return true; }

查詢附近的人(不支持查詢條件和分頁):

public function geoNearFind($uin, $maxDistance = 0, $unit = 'km') {     $redis = $this->getRedis();     $options = ['WITHDIST']; //顯示距離     $list = $redis->geoRadiusByMember('markers', $uin, $maxDistance, $unit, $options);     return $list; }

3.基于MongoDB

PHP使用MongoDB的擴展有mongo(文檔)和mongodb(文檔),兩者寫法差別很大,選擇好擴展需要對應相應的文檔查看,由于mongodb擴展是新版,本文選擇mongodb擴展。

假設我們創建db庫和location集合

設置索引:

db.getCollection('location').ensureIndex({"uin":1},{"unique":true})  db.getCollection('location').ensureIndex({loc:"2d"}) #若查詢位置附帶查詢,可以將常查詢條件添加至組合索引 #db.getCollection('location').ensureIndex({loc:"2d",uin:1})

成員添加方法:

public function geoAdd($uin, $lon, $lat) {     $document = array(         'uin' => $uin,         'loc' => array(             'lon' =>  $lon,             'lat' =>  $lat,         ),     );      $bulk = new MongoDBDriverBulkWrite;     $bulk->update(         ['uin' => $uin],         $document,         [ 'upsert' => true]     );     //出現noreply 可以改成確認式寫入     $manager = $this->getMongoManager();     $writeConcern = new MongoDBDriverWriteConcern(1, 100);     //$writeConcern = new MongoDBDriverWriteConcern(MongoDBDriverWriteConcern::MAJORITY, 100);     $result = $manager->executeBulkWrite('db.location', $bulk, $writeConcern);      if ($result->getWriteErrors()) {         return false;     }     return true; }

查詢附近的人(返回結果沒有距離,支持查詢條件,支持分頁)

public function geoNearFind($lon, $lat, $maxDistance = 0, $where = array(), $page = 0) {     $filter = array(         'loc' => array(             '$near' => array($lon, $lat),         ),     );     if ($maxDistance) {         $filter['loc']['$maxDistance'] = $maxDistance;     }     if ($where) {         $filter = array_merge($filter, $where);     }     $options = array();     if ($page) {         $page > 1 ? $skip = ($page - 1) * $this->pageCount : $skip = 0;         $options = [             'limit' => $this->pageCount,             'skip' => $skip         ];     }      $query = new MongoDBDriverQuery($filter, $options);     $manager = $this->getMongoManager();     $cursor = $manager->executeQuery('db.location', $query);     $list = $cursor->toArray();     return $list; }

查詢附近的人(返回結果帶距離,支持查詢條件,支付返回數量,不支持分頁):

public function geoNearFindReturnDistance($lon, $lat, $maxDistance = 0, $where = array(), $num = 0) {     $params = array(         'geoNear' => "location",         'near' => array($lon, $lat),         'spherical' => true, // spherical設為false(默認),dis的單位與坐標的單位保持一致,spherical設為true,dis的單位是弧度         'distanceMultiplier' => 6371, // 計算成公里,坐標單位distanceMultiplier: 111。 弧度單位 distanceMultiplier: 6371     );      if ($maxDistance) {         $params['maxDistance'] = $maxDistance;     }     if ($num) {         $params['num'] = $num;     }     if ($where) {         $params['query'] = $where;     }      $command = new MongoDBDriverCommand($params);     $manager = $this->getMongoManager();     $cursor = $manager->executeCommand('db', $command);     $response = (array) $cursor->toArray()[0];     $list = $response['results'];     return $list; }

注意事項:

1.選擇好擴展,mongo和mongodb擴展寫法差別很大

2.寫數據時出現noreply請檢查寫入確認級別

3.使用find查詢的數據需要自己計算距離,使用geoNear查詢的不支持分頁

4.使用geoNear查詢的距離需要轉化成km使用spherical和distanceMultiplier參數

上述demo可以戳這里:demo

總結

以上介紹了三種方式去實現查詢附近的人的功能,各種方式都有各自的適用場景,比如數據行比較少,例如查詢用戶和幾座城市之間的距離使用Mysql就足夠了,如果需要實時快速響應并且普通查找范圍內的距離,可以使用Redis,但如果數據量大并且多種屬性篩選條件,使用mongo會更方便,以上只是建議,具體實現方案還要視具體業務去進行方案評審。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
爱情岛论坛亚洲首页入口章节| 免费看污污视频| 福利在线一区二区| 影音先锋男人的网站| 老司机av福利| 亚洲精品国产suv一区88| 国产又粗又爽又黄的视频| 欧洲精品视频在线| 乱人伦xxxx国语对白| 免费成人午夜视频| 日韩欧美在线免费观看视频| 亚洲精品怡红院| 免费在线观看污网站| av动漫免费观看| 欧美视频免费看欧美视频| 欧美在线观看成人| 一级黄色特级片| 日本a在线天堂| 北条麻妃69av| 亚洲涩涩在线观看| 亚洲精品久久久久久久蜜桃臀| 精品国产免费av| 日本人69视频| 妞干网在线播放| 一区二区三区入口| 国产精品视频一二三四区| 国产在线青青草| aaa免费在线观看| 四虎永久在线精品无码视频| 亚洲午夜激情影院| 成人观看免费完整观看| 国产资源中文字幕| 国产91在线免费| 只有这里有精品| 日日躁夜夜躁aaaabbbb| 国产亚洲黄色片| 日韩人妻精品一区二区三区| 天天夜碰日日摸日日澡性色av| 亚洲天堂av一区二区| 国产乱子夫妻xx黑人xyx真爽| gai在线观看免费高清| 内射国产内射夫妻免费频道| 久久久成人精品一区二区三区| 蜜臀久久99精品久久久酒店新书| 91看片淫黄大片91| xxx中文字幕| 色一情一区二区三区| 50路60路老熟妇啪啪| 国产色一区二区三区| 色乱码一区二区三区熟女| 欧美男女交配视频| 国产成人手机视频| 黑人糟蹋人妻hd中文字幕| 国产freexxxx性播放麻豆| 韩国黄色一级大片| 热这里只有精品| 手机在线视频一区| 久久久久久久久久久久久久久国产| 毛葺葺老太做受视频| 亚洲爆乳无码专区| 欧美精品一区二区三区免费播放| 欧美爱爱视频免费看| 香港三级韩国三级日本三级| 妞干网在线视频观看| 青青草成人免费在线视频| 毛片在线播放视频| 国产午夜福利视频在线观看| 男人操女人免费| 免费激情视频在线观看| 国产精品天天av精麻传媒| 麻豆三级在线观看| 999热精品视频| 久久久久久久香蕉| 男女高潮又爽又黄又无遮挡| 欧美日韩激情视频在线观看| 美女黄色片视频| 超碰在线超碰在线| 成人av在线不卡| 久草热视频在线观看| 成年人免费大片| 九九九久久久久久久| 欧美一区二区视频在线播放| 久在线观看视频| 日韩av.com| 人妻久久久一区二区三区| 日韩免费高清在线| a级网站在线观看| 九色在线视频观看| 69久久久久久| 日韩xxxx视频| 不卡的在线视频| 性一交一乱一伧国产女士spa| 亚洲国产精品久久久久爰色欲| 成人性生生活性生交12| 国产1区2区3区中文字幕| 日韩亚洲在线视频| 国产 欧美 日韩 一区| 手机在线免费观看毛片| 久久这里只有精品18| 波多结衣在线观看| 欧美日韩性生活片| 中国一级大黄大黄大色毛片| 成人久久久久久久久| 国产91沈先生在线播放| 中文字幕66页| 五月婷婷深爱五月| 拔插拔插海外华人免费| 三日本三级少妇三级99| 男人的天堂日韩| 国产成人a亚洲精v品无码| 欧美一级爱爱视频| 天天综合中文字幕| 亚洲一区二区福利视频| 欧美视频免费播放| 欧美极品欧美精品欧美| 免费观看亚洲视频| av动漫在线播放| xxxxxx在线观看| 天天想你在线观看完整版电影免费| 日本人视频jizz页码69| 日本黄色三级大片| 欧美视频在线播放一区| 日本网站免费在线观看| 日韩成人三级视频| 无码人妻精品一区二区三区99v| 日韩va在线观看| 亚洲一二三av| 成年人免费观看的视频| 手机成人av在线| 最近免费观看高清韩国日本大全| 亚洲一区二区在线视频观看| 国产无色aaa| 国产成人精品免费看在线播放| 日本黄色a视频| 今天免费高清在线观看国语| 特级西西444| 性欧美大战久久久久久久| 国产中文字幕视频在线观看| 国模无码视频一区二区三区| 无遮挡又爽又刺激的视频| 无码人妻精品一区二区三区66| 欧美大尺度做爰床戏| 咪咪色在线视频| 日本人体一区二区| 色婷婷综合久久久久中文字幕 | 亚洲娇小娇小娇小| 三级在线免费看| 欧美少妇一级片| 热99这里只有精品| 性欧美videossex精品| 视频区 图片区 小说区| 日韩a级黄色片| 亚洲成人av免费看| 糖心vlog在线免费观看| 国产网站免费在线观看| 手机免费看av网站| 国产女主播自拍| 日本超碰在线观看| 免费看黄在线看| av噜噜在线观看| 九色在线视频观看| 精品一区二区成人免费视频| 国产二区视频在线播放| 激情文学亚洲色图| 免费黄色日本网站| 穿情趣内衣被c到高潮视频| 久久国产色av免费观看| 欧美交换配乱吟粗大25p| 欧美韩国日本在线| 国产欧美123| 五月天开心婷婷| 国产免费一区二区三区视频| 黄色小视频大全| 9l视频白拍9色9l视频| 欧美 国产 综合| 欧美交换配乱吟粗大25p| 国产三级国产精品国产专区50| 国产欧美日韩网站| 国产精品免费看久久久无码| 看看黄色一级片| 亚洲黄色a v| 妓院一钑片免看黄大片| 黄色网页免费在线观看| 日韩欧美精品免费| mm131午夜| 超级碰在线观看| av动漫在线免费观看| 国产日产欧美一区二区| 大地资源第二页在线观看高清版| 天天视频天天爽| wwww.国产| 国产无色aaa| 亚洲在线观看网站| 手机成人av在线| 精品视频在线观看一区二区| 日韩不卡一二区| 青青青青在线视频| 欧美午夜性视频| 37pao成人国产永久免费视频| 日本一区二区黄色|