MysqlorMongodbLBS快速實現方案

suboysugar發表於2015-03-03

http://www.wubiao.info/470

前兩篇文章:

查詢附近的xxx 球面距離以及Geohash方案探討 (http://www.wubiao.info/372

微信、陌陌 架構方案分析 (http://www.wubiao.info/401

探討了,LBS查詢附近的XXX;其中包括了,Mysql自定義儲存函式方案,以及通過GeoHash、redis自建索引方案。

===============================================================

今天分享兩種,利用GeoHash封裝成內建資料庫函式的簡易方案;

A:Mysql 內建函式方案,適合於已有業務,新增加LBS功能,增加經緯度欄位方可,避免資料遷移

B:Mongodb 內建函式方案,適合中小型應用,快速實現LBS功能,效能優於A(推薦)

===============================================================

方案A: (MySQL Spatial)

1、先簡歷一張表:(MySQL 5.0 以上 僅支援 MyISAM 引擎)

1
2
3
4
5
6
7
8
9
CREATE TABLE address (
 
    address CHAR(80) NOT NULL,
 
    address_loc POINT NOT NULL,
 
    PRIMARY KEY(address)
 
);

空間索引:

1
ALTER TABLE address ADD SPATIAL INDEX(address_loc);

插入資料:(注:此處Point(緯度,經度) 標準寫法)

1
2
3
INSERT INTO address VALUES(`Foobar street 12`, GeomFromText(`POINT(30.620076 104.067221)`));
 
INSERT INTO address VALUES(`Foobar street 13`, GeomFromText(`POINT(31.720076 105.167221)`));

查詢: 查詢(30.620076,104.067221)附近 10 公里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT  *
    FROM    address
    WHERE   MBRContains
                    (
                    LineString
                            (
                            Point
                                    (
                                    30.620076 + 10 / ( 111.1 / COS(RADIANS(104.067221))),
                                    104.067221 + 10 / 111.1
                                    ),
                            Point
                                    (
                                    30.620076 - 10 / ( 111.1 / COS(RADIANS(104.067221))),
                                    104.067221 - 10 / 111.1
                                    )
                            ),
                    address_loc
                    )

方案B:

1、先建立一張簡單的表user,兩條資料如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "_id": ObjectId("518b1f1a83ba88ca60000001"),
  "account": "simplephp1@163.com",
  "gps": [
    104.067221,
    30.620076
  ]
}
 
{
  "_id": ObjectId("518b1dae83ba88d660000000"),
  "account": "simplephp6@163.com",
  "gps": [
    104.07958,
    30.653936
  ]
}

其中,gps為二維陣列,分別為經度,緯度

(注:此處必須按照(經度,緯度)順序儲存。我們平時表示經緯度,都是(緯度,精度),此處這種方式有木有很親民)

2、使用之前,先建立二維索引

//建立索引 最大範圍在經度-180~180

1
db.user.ensureIndex({"gps":"2d"},{"min":-180,"max":180})

//刪除索引

1
db.user.dropIndex({"gps":"2d"})

3、Mongodb有兩中方式可以查詢附近的XXX;其中方案2)會返回距離(推薦)

1)標準查詢,為地球經緯度查詢內建;引數一為查詢條件利用$near查詢附近,引數二$maxDistance為經緯弧度(1° latitude = 111.12 kilometers)即 1/111.12,表示查詢附近一公里。

1
db.user.find({ gps :{ $near : [104.065847, 30.657554] , $maxDistance : 1/111.12} })

2)執行命名方式,模擬成一個圓球;引數一指定geoNear方式和表名;引數二座標,引數三是否為球形,引數四弧度(弧度=弧長/半徑 一千米的弧度1000/6378000),引數五指定球形半徑(地球半徑)

1
db.runCommand({geoNear:`user`, near:[104.065847, 30.657554], spherical:true, maxDistance:1000/6378000, distanceMultiplier:6378000});

本條目釋出於2013年05月28日。屬於DB架構演算法分類,被貼了 geohashLBSMongodbMysql 標籤。

如何聯絡我:【萬里虎】www.bravetiger.cn
【QQ】3396726884 (諮詢問題100元起,幫助解決問題500元起)
【部落格】http://www.cnblogs.com/kenshinobiy/


相關文章