成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

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

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

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

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

查找附近的人有個(gè)更大的專有名詞叫做LBS(基于位置的服務(wù)),LBS是指是指通過(guò)電信移動(dòng)運(yùn)營(yíng)商的無(wú)線電通訊網(wǎng)絡(luò)或外部定位方式,獲取移動(dòng)終端用戶的位置信息,在GIS平臺(tái)的支持下,為用戶提供相應(yīng)服務(wù)的一種增值業(yè)務(wù)。因此首先得獲取用戶的位置,獲取用戶的位置有基于GPS、基于運(yùn)營(yíng)商基站、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ù)庫(kù)進(jìn)行篩選和排序。

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

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

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

具體推斷過(guò)程有興趣的推薦這篇文章:【數(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;

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

Redis 3.2提供GEO地理位置功能,不僅可以獲取兩個(gè)位置之間的距離,獲取指定位置范圍內(nèi)的地理信息位置集合也很簡(jiǎn)單。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查詢中分頁(yè)相關(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)); }

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

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

成員添加方法:

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

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

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庫(kù)和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é)果沒(méi)有距離,支持查詢條件,支持分頁(yè))

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ù)量,不支持分頁(yè)):

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查詢的不支持分頁(yè)

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

上述demo可以戳這里:demo

總結(jié)

以上介紹了三種方式去實(shí)現(xiàn)查詢附近的人的功能,各種方式都有各自的適用場(chǎng)景,比如數(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)
亚洲AV永久无码一区| 色噜噜人妻av无码| 日韩精品无码久久久久久| 日韩乱码人妻无码中文字幕视频 | 337P粉嫩胞人体高清视频免费| 1024久久亚洲精品无码| MM1313亚洲精品无码久久| 成年无码动漫AV片在线尤物| 国产精品毛片A∨一区二区三区| 黄A大片AV永久免费| 浪荡受NP纯肉公共场合BL男男 | 性一交一乱一色一视频| 亚洲欧美日韩综合一区| 中文字幕亚洲欧美专区| 成人毛片无码一区二区| 国产一区日韩二区欧美三区| 久久青草亚洲AV无码麻豆| 欧美性VIDEOS高清精品| 四虎影视APP IOS| 亚洲精品无码久久久久苍井空| 亚洲欧美中文日韩V在线观看| 亚洲欧美国产精品久久| 91人人妻人人澡人人爽超污| 成人精品一区二区久久久| 国产女人18毛片水真多| 老师办公室被吃奶好爽在线观看| 人人添人人妻人人爽频| 性做久久久久久久久| 又嫩又硬又黄又爽的视频| 部长的夫人的味道中字| 国产香港明星裸体XXXX视频| 美女内射在线观看| 手机在线看永久AV片免费| 亚洲欧洲日产V一个人免费观看视频WWW高清| 60老熟女多次高潮露脸视频| 国产成人精品无码专区 | 强开小娟嫩苞又嫩又紧| 香蕉久久夜色精品国产| 永久免费AV无码网站在线观看| WWW国产精品内射老熟女| 亚洲一区二区三区 无码| YY8840私人影院爱不停下载| 国产日产久久高清欧美一区| 蜜桃AV免费一区二区三区| 双腿张开被9个男人调教| 亚洲尤码不卡AV麻豆| 成人综合激情另类小说| 精品人妻无码区二区三区密桃| 狠狠色丁香久久婷婷综| 好吊视频一区二区三区| 欧美成人精品手机在线| 香蕉97超级碰碰碰视频| 99久久国产综合精品成人影院| 国产精品麻豆成人AV电影| 麻花传媒剧在线MV免费观看| 玩两个丰满老熟女| 2021少妇久久久久久久久久| 国产无套码AⅤ在线观看| 内射极品少妇一区二区av| 学生无码AV一区二区三区| CHINESEHD国产精品麻豆| 国内精品久久久久久久影视麻豆| 欧美最猛性XXXXX黑人巨| 亚洲精品色午夜无码专区日韩| 成人无码A区在线观看视频| 久久精品国产99国产精偷 | 91国语对白露脸自产拍不卡| 国产在线观看无遮挡无码AⅤ多人| 欧美一级内射黑人内射| 亚洲熟妇色XXXXX中国少妇Y| 国产99网站免在线观看| 女人被男人爽到呻吟的视频| 久久精品国产精品久久久| 八区精品色欲人妻综合网| 厨房人妻HD中文字幕69XX| 两个病娇男友轮流爱我资源| 性无码专区一色吊丝中文字幕 | 热99RE久久精品| 夜夜澡天天碰人人爱AV| 国产手机在线精品| 日韩欧美亚洲综合久久影院D3 | 无码AV岛国片在线播放| 111111少妇影院| 精品不卡一区二区| 真人荫道口图片100张| 中文字幕AV无码人妻| 国产在线清纯极品美女援交| 日日噜噜夜夜狠狠久久无码区| 中文字幕乱妇无码AV在线| 精品国产污污免费网站| 无码高清一区二区三区| 成人免费A级毛片久久| 男人的天堂在线视频| 亚洲熟妇AV日韩熟妇在线| 国产日产久久高清欧美一区| 少妇ASS浓PICSXXXXB| YW尤物AV无码| 男配每天都在体内成结节| 亚洲伊人成无码综合网 | 我朋友的妻子2018| 波多野AV一区二区无码| 欧美激情内射喷水高潮| 中国熟妇人妻性XXXXX在线看| 久久er99热精品一区二区| 亚洲AV无码AV制服另类专区| 国产精品国产亚洲精品看不卡| 日本精品一线二线三线区别在哪里| 97精品伊人久久久大香线蕉| 军人边走边吮她的花蒂| 亚洲夜夜性无码国产盗摄| 京东天美麻豆果冻传媒| 亚洲AV无码一级毛片少妇| 国产婷婷成人久久AV免费高清| 无码丰满少妇2在线观看| 国产成年无码久久久久毛片| 色一情一乱一伦一区二区三区| 成人精品天堂一区二区三区| 日本一卡二卡三卡四卡2021| 波多野结衣乳喷高潮视频| 日本XXXX洗澡ⅩXXX偷窥| 波多野结衣一二三区AV高清| 日本XXXX洗澡ⅩXXX偷窥| 成人精品一二三区| 色翁荡息又大又硬又粗又爽| 丰满老熟好大BBBXXX| 无码国产精成人午夜视频不卡| 被教官按在寝室狂到腿软视频| 人人妻人人澡人人爽| 成 人 网 站 在线 看 免费| 日韩欧美亚洲国产精品字幕久久久| 大爷你的太大了我| 特大巨黑吊性XXXX| 美女扒开屁股让男人桶GIF动态| 无码人妻精品中文字幕免费东京热| 丰满熟妇性ⅩXXOOO69| 天堂…在线最新版在线| 国产成人午夜性A一级毛片老女人| 无码中文AV有码中文AV| 国语自产偷拍精品视频| 亚洲一区二区三区成人片在线观看| METART极品人体| 欧美大屁股妞性潮喷ⅩXX| FIREEXⅩ性欧美HD护士| 青青草国产成人99久久| 波多野结衣中文字幕免费视频| 日本老熟妇毛茸茸| 爆乳2把你榨干哦在线观看| 日本体内SHE精高潮| 97久久久久人妻精品区一| 人人妻人人澡人人爽秒播| 一本无码人妻在中文字幕| 六十路七十路熟女乱码| 亚洲AV无码一区二区二三区下载 | av色欲无码人妻中文字幕| 蜜桃AV自慰久久久久免费网站| AV无码精品久久久久精品免费| 久久精品国产只有精品2020| 一本大道香蕉久97在线播放| 国产农村妇女毛片精品久久麻豆| 亚洲精品无码一区二区AⅤ污美国| 欧美又粗又大XXXXBBBB疯狂| 极品熟妇大蝴蝶20P| AV无码久久久精品免费| 无人区码一码二码三MBA| 久久欧美极品少妇XXXXⅩ| 吃瓜爆料网不打烊| 亚洲欧美色中文字幕在线| 欧洲精品不卡1卡2卡三卡| 国产精品久久久久久精品电影| 亚洲AV永久无码精品| 男女啪啪免费观看的网址| 国产精品香蕉成人网在线观看| 亚洲日韩欧美成人一区二区三区| 好男人好视频资源在线播放| 又大又粗欧美成人网站| 欧美黑人成人www在线观看| 被老外做的下身都肿了| 中国JAPANESEXXXX少| 亚洲精品成人无码中文毛片| 无码一区在线视频| 无码日韩人妻精品久久| 日日狠狠久久偷偷色综合96| 老熟妇BBWASS| 国内精品乱码卡一卡2卡三卡| A级黑粗大硬长爽 猛视频,| 亚洲精品无码日韩国产不卡AV | 久久午夜私人影院| JAPANESEXXXⅩHD乱| 亚洲AV色香蕉一区二区蜜桃| 国产成人亚洲影院在线 | 少妇久久久久久被弄高潮| 和岳每晚弄的高潮嗷嗷叫| 97人妻人人做人碰人人爽| 我一边做饭一边被躁了怎么回事| 久久精品无码一区二区软件| 成熟丰满熟妇强av无码区| 亚洲熟女综合色一区二区三区 | 第一次处破女01免费观看| 亚洲人亚洲精品成人网站| 日本一本2017国产|