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| 欧美精品久久96人妻无码| 一本大道东京热无码aⅴ| 日韩小视频网站| 国产精品人人妻人人爽人人牛| 久久撸在线视频| 妞干网视频在线观看| 乱子伦视频在线看| 日日噜噜夜夜狠狠久久丁香五月 | 欧洲美女亚洲激情| 免费无码毛片一区二三区| 邪恶网站在线观看| 午夜xxxxx| 人人干人人干人人| 99久热在线精品视频| 波多野结衣综合网| 精品亚洲一区二区三区四区| 国产精品av免费观看| 黄色一级二级三级| 国产特级淫片高清视频| 亚洲成人福利在线| 色婷婷一区二区三区av免费看| 国产原创精品在线| 在线观看视频黄色| 无码精品国产一区二区三区免费| 在线一区二区不卡| 成人黄色一区二区| 欧美爱爱视频免费看| 五月天色婷婷综合| 一女二男3p波多野结衣| 国产视频九色蝌蚪| 国产真人做爰毛片视频直播| www.久久com| 小泽玛利亚视频在线观看| 国产极品粉嫩福利姬萌白酱 | 少妇高清精品毛片在线视频| 国产免费xxx| 91免费网站视频| 在线观看岛国av| 国产1区2区在线| 欧美成人免费高清视频| 日韩av中文字幕第一页| 50度灰在线观看| 久久久久久久久影视| 手机福利在线视频| 国产系列第一页| 四虎4hu永久免费入口| 天天操天天干天天玩| 91热视频在线观看| jizz18女人| 欧美大片久久久| 手机在线国产视频| 超碰91在线播放| 一级全黄肉体裸体全过程| 国产高清精品软男同| 亚洲一区二区三区四区精品| 香蕉视频色在线观看| 国产精品jizz在线观看老狼| 国内自拍中文字幕| 丰满少妇大力进入| 欧美亚洲一二三区| 午夜免费福利在线| 九九九九九伊人| 亚洲精品天堂成人片av在线播放| 国产a级片免费看| 国产乱子伦精品无码专区| 妞干网在线观看视频| 国产成人无码精品久久久性色| 男女午夜激情视频| 亚洲三级视频网站| av在线网址导航| 青青草原播放器| 日韩av高清在线看片| 香蕉视频在线网址| 国产精品jizz在线观看老狼| 亚洲精品中文字幕乱码无线| 日本成人黄色网| 日本新janpanese乱熟| 国产免费人做人爱午夜视频| 日本十八禁视频无遮挡| 国产一级爱c视频| 国产极品粉嫩福利姬萌白酱| 高清av免费看| www.男人天堂网| 成人一级片网站| 色婷婷一区二区三区在线观看| 9色porny| 午夜激情视频网| 免费国产成人av| www.99riav| 亚洲图色中文字幕| 少妇高潮毛片色欲ava片| 岛国av在线免费| 自拍日韩亚洲一区在线| 国产91av视频在线观看| 日韩久久一级片| 99久久免费观看| 在线播放黄色av| 日本老熟妇毛茸茸| 成人免费毛片在线观看| 国产女同无遮挡互慰高潮91| www黄色av| 国内精品在线观看视频| 奇米777在线| 爱情岛论坛成人| 精品一区二区中文字幕| 精品一二三四五区| 天堂网成人在线| 爱情岛论坛vip永久入口| 黄色一级视频片| 欧美激情亚洲天堂| 一本二本三本亚洲码 | 国产又大又长又粗又黄| 亚洲精品20p| 一级在线免费视频| 欧美视频免费播放| 国产偷人视频免费| 91国视频在线| 波多野结衣50连登视频| 欧美激情视频免费看| 久久男人资源站| 欧美a级免费视频| 天天做天天爱天天高潮| 99999精品| √天堂资源在线| 蜜桃福利午夜精品一区| 最新免费av网址| 久久久国产精华液999999 | 国产精品第12页| 国产av无码专区亚洲精品| av免费观看网| 日韩av资源在线| 精品国产无码在线| 三级a在线观看| 久久精品视频16| 在线黄色免费看| 国产一区二区视频播放| av在线网址导航| 免费一级特黄毛片| 国产3p在线播放| 美女福利视频在线| 日韩中文字幕亚洲精品欧美| 色综合av综合无码综合网站| 亚洲精品手机在线观看| 2018国产在线| 色国产在线视频| 欧美美女一级片| 熟妇熟女乱妇乱女网站| 黄色成人在线免费观看| 国产乱子伦农村叉叉叉| 亚洲天堂av线| 精品日韩在线播放| 欧美深夜福利视频| 九九热免费在线观看| 乱子伦一区二区| 天天摸天天碰天天添| 91香蕉国产线在线观看| 国产日韩av网站| 三年中国国语在线播放免费| 亚洲天堂一区二区在线观看| 国产精品www在线观看| 久久久精品麻豆| 超碰超碰超碰超碰超碰| 久久9精品区-无套内射无码| 奇米777在线视频| 男人天堂网视频| 中文字幕免费高| 妓院一钑片免看黄大片| 男同互操gay射视频在线看| 农村妇女精品一二区| 成人免费看片视频在线观看| 麻豆av免费在线| 精品久久久无码人妻字幂| 国产福利影院在线观看| 亚洲精品蜜桃久久久久久| 自拍偷拍一区二区三区四区| 妞干网在线视频观看| 秋霞在线一区二区| 奇米影音第四色| 亚洲 高清 成人 动漫| 国产精品jizz在线观看老狼| 日本免费观看网站| 欧美日韩精品在线一区二区| 日本福利视频导航| 日本xxxx黄色| 不要播放器的av网站| 青青草视频在线免费播放| 日本黄xxxxxxxxx100| 伊人免费视频二| 亚洲精品20p| 九九热在线免费| 日本免费黄视频| 国产91美女视频| a级黄色一级片| 日韩日韩日韩日韩日韩| 加勒比海盗1在线观看免费国语版| 三上悠亚在线一区|