久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      教你使用PHP實(shí)現(xiàn)查找你想要的附近人

      最近有個(gè)業(yè)務(wù)場景使用到了查找附近的人,于是查閱了相關(guān)資料,并對(duì)使用PHP實(shí)現(xiàn)相關(guān)功能的多種方式和具體實(shí)現(xiàn)做一篇技術(shù)總結(jié),歡迎各位看官提出意見和糾錯(cuò),下面開始進(jìn)入正題:

      LBS(基于位置的服務(wù))

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

      根據(jù)經(jīng)緯度如何得出兩點(diǎn)之間的距離?

      我們都知道平面坐標(biāo)內(nèi)的兩點(diǎn)坐標(biāo)可以使用平面坐標(biāo)距離公式來計(jì)算,但經(jīng)緯度是利用三度空間的球面來定義地球上的空間的球面坐標(biāo)系統(tǒng),假定地球是正球體,關(guān)于球面距離計(jì)算公式如下:

      教你使用PHP實(shí)現(xiàn)查找你想要的附近人

      具體推斷過程有興趣的推薦這篇文章:【數(shù)學(xué)公式及推導(dǎo)】根據(jù)經(jīng)緯度計(jì)算地面兩點(diǎn)間的距離

      PHP函數(shù)代碼如下:

      /**      * 根據(jù)兩點(diǎn)間的經(jīng)緯度計(jì)算距離      * @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;

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

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

      1.增加地理位置

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

      2.獲取地理位置

      GEOPOS key member [member ...]

      3.獲取兩個(gè)地理位置的距離

      GEODIST key member1 member2 [unit]

      4.獲取指定經(jīng)緯度的地理信息位置集合

      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專門針對(duì)這種查詢建立了地理空間索引。 2d和2dsphere索引,分別是針對(duì)平面和球面。 MongoDB文檔

      1.添加數(shù)據(jù)

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

      2.建立索引

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

      3.查找附近的點(diǎn)

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

      4.最大距離和限制條數(shù)

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

      5.使用geoNear在查詢結(jié)果中返回每個(gè)點(diǎn)距離查詢點(diǎn)的距離

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

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

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

      PHP多種方式和具體實(shí)現(xiàn)

      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擴(kuò)展或者通過composer安裝predis類庫,本文使用redis擴(kuò)展來實(shí)現(xiàn)。

      成員添加方法:

      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的擴(kuò)展有mongo(文檔)和mongodb(文檔),兩者寫法差別很大,選擇好擴(kuò)展需要對(duì)應(yīng)相應(yīng)的文檔查看,由于mongodb擴(kuò)展是新版,本文選擇mongodb擴(kuò)展。

      假設(shè)我們創(chuàng)建db庫和location集合

      設(shè)置索引:

      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]     );     //出現(xiàn)noreply 可以改成確認(rèn)式寫入     $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; }

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

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

      查詢附近的人(返回結(jié)果帶距離,支持查詢條件,支付返回?cái)?shù)量,不支持分頁):

      public function geoNearFindReturnDistance($lon, $lat, $maxDistance = 0, $where = array(), $num = 0) {     $params = array(         'geoNear' => "location",         'near' => array($lon, $lat),         'spherical' => true, // spherical設(shè)為false(默認(rèn)),dis的單位與坐標(biāo)的單位保持一致,spherical設(shè)為true,dis的單位是弧度         'distanceMultiplier' => 6371, // 計(jì)算成公里,坐標(biāo)單位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; }

      注意事項(xiàng):

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

      2.寫數(shù)據(jù)時(shí)出現(xiàn)noreply請(qǐng)檢查寫入確認(rèn)級(jí)別

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

      4.使用geoNear查詢的距離需要轉(zhuǎn)化成km使用spherical和distanceMultiplier參數(shù)

      上述demo可以戳這里:demo

      總結(jié)

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

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)