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

来源:互联网 发布:网络畅销书排行榜 编辑:程序博客网 时间:2024/04/30 00:17

写这篇文章是基于兴趣,早之前好奇一些社交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.


上代码套餐:

<?phpini_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);}

效果图
H5+PHP+MongoDB

原创粉丝点击