您的位置:首页 > 数据库 > Mongodb

基于PHP+MongoDB的LBS附近的人应用-初探

2017-06-20 10:35 531 查看
写这篇文章是基于兴趣,早之前好奇一些社交APP、O2O应用可能会带有“附近的人”类似的功能,到底他们是如何做的呢?下面我简单的分析下用到的技术,小学生的分析欢迎批评指正。在线体验:http://182.92.217.161/map/index.php (H5+PHP+Mongo 请使用 手机打开,最好是在非WIFI 环境下,那样定位更加准确)。

基于 GeoHash + (B Tree + R tree 储存,最好是 R tree)技术,详细关于GeoHash深度技术可阅读以下文章:

http://www.cnblogs.com/LBSer/p/3310455.html

http://iamzhongyong.iteye.com/blog/1399333

依旧沿用简单粗暴的解决问题的方案,直接使用空间索引的 DB,这里我就折中选择 MongoDB,提供空间索引的DB 很多,例如 Redis 3.2 以上,MongoDB 、PostgreSQL、MySQL,关于这几款的性能测评,详情参照: http://www.cnblogs.com/zhenbianshu/p/6817569.html.

上代码套餐:

<?php
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);
$mongo_config = [
'host'=>'127.0.0.1',
'port'=>27017,
'dbname'=>'my_app',
'user'=>'',
'pwd'=>''
];
$host_port = $mongo_config['host'] . ":" . $mongo_config['port'];
try {
$mongoDB = new MongoClient($host_port);
$mongo_model = $mongoDB->selectDB($mongo_config['dbname']);
} catch(\Exception $e) {
echo responseJson(0, 'MongoDB connection was fail.');
exit();
}
$lbs = new LBS();
$lbs->setKvDB($mongo_model);

$method = trim($_POST['method']);
switch($method) {
case 'join':
$longitude = $_POST['lng'];
$latitude = $_POST['lat'];
$uid = $_POST['uuid'];
$r = $lbs->geoAdd($longitude, $latitude, $uid);
if($r) {
$users = $lbs->geoSearch($longitude, $latitude);
if(!empty($users)) {
echo responseJson(1, '已经找到附近的小伙伴了.', $users);
} else {
echo responseJson(0, '你附近没有小伙伴.');
}
} else {
echo responseJson(0, '上报地理位置失败');
exit();
}
break;
case 'search':
echo georadiusbymember($redis);
break;
default:
echo responseJson(0,'未知操作');
break;
}

class LBS
{
private $kvDB;
private $index_type = '2dsphere';
private $table_name = 'user_lbs';

/**
* 设置储存媒介,限定 mongoDB,所有操作基于mongo
* @param object $mongoDB
*
*/
public function setKvDB(MongoDB $mongoDB) {
$this->kvDB = $mongoDB;
}

/**
* 设置 lbs 表名称
* @param double $longitude 经度
* @param double $latitude  维度
* @param string/int $uid   用户ID
* @param array $data  		其他数据,k v 形式, example: $data = ['username' => 'kevin','geo' => 'center'];
*/
public function geoAdd($longitude, $latitude, $uid, $data = []) {
$d = [
'loc' => [
'type' => 'Point',
'coordinates' => [doubleval($longitude), doubleval($latitude)]
],
'uid' => $uid
];
if($this->checkData($data)) {
$d = array_merge($d, $data);
}
$collection = $this->kvDB->selectCollection($this->table_name);
//查询 该uid 是否存在,存在则更新
//$collection->remove(['uid' => $uid], ['justOne' => true]);      // test
$exist = $collection->findOne(['uid' => $uid]);
$collection->ensureIndex(['loc' => $this->index_type]);
if($exist) {
$r = $collection->update(['uid' => $uid], ['$set' => $d]);
} else {
$r = $collection->insert($d);
}
return (isset($r['ok']) && !empty($r['ok'])) ? true : false;
}

/**
* 根据 经纬度查询附近人
* @param double $longitude 经度
* @param double $latitude  维度
* @param int    $maxdistance   默认 2000 Mi(米)
* @param int    $limit        默认拉取100
* @return array 附近的人集合
*/
public function geoSearch($longitude, $latitude, $maxdistance = 1000, $limit = 100) {
$coll = $this->kvDB->selectCollection($this->table_name);
$r = $this->kvDB->command(
[
'geoNear' => $this->table_name,
'near' => [ 'type' => 'Point','coordinates' =>[doubleval($longitude), doubleval($latitude)]],
'spherical' => true,
'maxDistance' => $maxdistance,
'num' => $limit,
]
);
if(isset($r['ok']) && !empty($r['ok'])) {
return $r['results'];
} else {
return false;
}
}

/**
* 安全监测 如需严格,则需要判断经纬度在范围
* @param array $data
* @return bool|array
*/
public function checkData($data) {

if(empty($data)) return false;
if(isset($data['loc'])) unset($data['loc']);
if(isset($data['uid'])) unset($data['uid']);
return $data;
}
/**
* 设置 lbs 表名称
* @param string $table_name default value "user_lbs"
*
*/
public function setTableName($table_name) {
$this->table_name = $table_name;
}
/**
* 获取 lbs 表名称
* @return string table name
*/
public function getTableName()
{
return $this->table_name;
}

/**
* 返回json
* @param int    $state    状态
* @param string $message   消息
* @param array  $data     数据
* @return json string      json 数据
*/
function responseJson($state = 0, $message = '', $data = null) {
$r['state'] = $state;
$r['message'] = $message;
if(!is_null($data)) {
$r['data'] = $data;
}
return json_encode($r);
}
}

/**
* 返回json
* @param int    $state    状态
* @param string $message   消息
* @param array  $data     数据
* @return json string      json 数据
*/
function responseJson($state = 0, $message = '', $data = null) {
$r['state'] = $state;
$r['message'] = $message;
if(!is_null($data)) {
$r['data'] = $data;
}
return json_encode($r);
}


效果图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: