生活随笔
收集整理的這篇文章主要介紹了
LBS解决方案
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
LBS解決方案
LBS(基于地理位置的服務)服務是現(xiàn)在移動互聯(lián)網(wǎng)中比較常用的功能,例如外賣中我附近的店鋪,通常是以客戶位置坐標為中心,查詢一定范圍內的店鋪信息,按照距離由近及原進行倒敘排序
方案一,直接mysql
經(jīng)緯度范圍計算就是弧度的計算,只要數(shù)學夠好,算出來分分鐘的事情,直接上mysql一個語句搞定:
CREATE TABLE ` places
` ( ` id
` INT ( 11 ) NOT NULL AUTO_INCREMENT , ` lat
` DOUBLE NOT NULL DEFAULT '0' , ` lng
` DOUBLE NOT NULL DEFAULT '0' , PRIMARY KEY ( ` Id
` ) , KEY ` lat
` ( ` lat
` ) , KEY ` lng
` ( ` lng
` )
) ENGINE = INNODB AUTO_INCREMENT = 9 DEFAULT CHARSET = utf8
;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 23.123123 , 123.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 21.123123 , 121.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 22.123123 , 122.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 24.123123 , 124.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 25.123123 , 125.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 26.123123 , 126.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 27.123123 , 127.123 ) ;
INSERT INTO ` zhenai_yewu
` . ` places
` ( ` lat
` , ` lng
` ) VALUES ( 28.123123 , 128.123 ) ;
SELECT id
, ( 6371 * acos
( cos
( radians
( 24.123123 ) ) * cos
( radians
( lat
) ) * cos
( radians
( lng
) - radians
( 124.123 ) ) + sin
( radians
( 24.123123 ) ) * sin
( radians
( lat
) ) ) ) AS distance
FROM places
HAVING distance
< 255555 ORDER BY distance
LIMIT 0 , 100 ;
12 0
13 150.27231636470339
9 150.80702908932616
14 299.9866451782974
11 302.12576883654754
15 449.11942176001054
10 453.93347262147796
16 597.6467747050862
sql 查詢的是lat,lng對應的坐標信息,中心點的信息是[124.123, 24.123123],明顯這個是通過弧度計算來算出適合范圍內的經(jīng)緯度范圍,然后搜索對應的id,如下sql語句分析 即使加上了索引這種查詢也必須掃全表信息,效率低下 優(yōu)化一下: 另外一種算法,可以根據(jù)圓心坐標計算正方形四個點的坐標,然后查詢正方形內的點。
SELECT * FROM places
WHERE ( ( lat
BETWEEN 20 AND 29 ) AND ( lng
BETWEEN 90 AND 170 ) ) ;
9 23.123123 123.123
10 21.123123 121.123
11 22.123123 122.123
12 24.123123 124.123
13 25.123123 125.123
14 26.123123 126.123
15 27.123123 127.123
16 28.123123 128.123
這樣優(yōu)化后,雖然數(shù)據(jù)不完全精確(圓形變正方形),但性能提升很明顯,并且可以通過給lat lng字段做索引的方式進一步加快這條SQL的查詢速度。對精度有要求的應用也可以在這個結果上再進行計算,排除那些在方塊范圍內但不在圓形范圍內的數(shù)據(jù),已達到對精度的要求。 但是沒有排序,沒有距離,除非做其他運算。
方案二,Redis
Redis3.2.0后開始支持LBS相關的命令,要實現(xiàn)以上功能,主要用到Redis geo相關的兩個命令 GEOADD, GETRADIOUS 命令描述,案例:
GEOADD key longitude latitude member
[ longitude latitude member
... ]
有效經(jīng)度值域[-180,180], 有效緯度值域[-85.05112878 , 85.05112878 ],單坐標超過上述指定范圍時候,會返回錯誤信息,可以一次添加多個位置地點,如下案例:
新docker
- redis
: 0 > GEOADD location
117 20 beijing
"1"
新docker
- redis
: 0 > GEOADD location
120 30 shenzheng
"1"
新docker
- redis
: 0 > GEOADD location
121 31 guangzhou
, 122 32 nanjing
"2"
GEORADIUS key longitude latitude radius m
| km
| ft
| mi
[ WITHCOORD ] [ WITHDIST ] [ WITHHASH ] [ COUNT count
]
命令以給定的經(jīng)緯度為中心,返回鍵值key包含的位置元素中,與中心距離不超過給定最大距離的所有位置的元素,并且可以指定單位,順序返回單位信息如下:
m:米
km:千米
mi:英里
ft:英尺
給定一下選項時候,命令會額外返回信息: WITHDIST:返回位置元素的同時,將位置元素與中心之間的距離也一并返回。距離的單位和用戶給定的范圍單位保持一致 如下:
新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHDIST
1 ) 1 ) "shenzheng" 2 ) "95.9992" 2 ) 1 ) "guangzhou," 2 ) "97.5090" 3 ) 1 ) "nanjing" 2 ) "229.9580"
WITHCOORD :將位置元素的進度和緯度也一起返回。
新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHCOORD
1 ) 1 ) "shenzheng" 2 ) 1 ) "120.00000089406967163" 2 ) "30.00000024997701331" 2 ) 1 ) "guangzhou," 2 ) 1 ) "120.99999815225601196" 2 ) "31.00000097648057817" 3 ) 1 ) "nanjing" 2 ) 1 ) "122.00000077486038208" 2 ) "31.99999916826298119"
WITHHASH 以52位有符號整形,返回位置元素經(jīng)過原始geohash編碼的有序集合分值
新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHHASH
1 ) 1 ) "shenzheng" 2 ) "4054115787372083" 2 ) 1 ) "guangzhou," 2 ) "4054742425916764" 3 ) 1 ) "nanjing" 2 ) "4066587848444692"
asc:更具中心位置按從近到遠的方式返回位置元素 desc:根據(jù)中心位置,從遠到近的方式返回位置元素 默認情況GEORADIUS命令會返回所有匹配的位置元素,用戶可以使用count 獲取前面N個
新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHHASH asc
1 ) 1 ) "shenzheng" 2 ) "4054115787372083" 2 ) 1 ) "guangzhou," 2 ) "4054742425916764" 3 ) 1 ) "nanjing" 2 ) "4066587848444692" 新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHHASH desc
1 ) 1 ) "nanjing" 2 ) "4066587848444692" 2 ) 1 ) "guangzhou," 2 ) "4054742425916764" 3 ) 1 ) "shenzheng" 2 ) "4054115787372083" 新docker
- redis
: 0 > GEORADIUS location
120.987 30.1234 500 km WITHHASH desc count
1 1 ) 1 ) "nanjing" 2 ) "4066587848444692"
方案三
mongodb 原生支持地理位置索引2dSpace,可以直接用于位置距離計算和查詢。 而且我們用的也比較多,能夠支持地理位置查詢的同事也有免息集合存儲,數(shù)據(jù)格式自由,查詢性能高等特點,對應我們需求只需要一個mongodb查詢語句:
db。moment
. find
( { location : { $geoWithin :{ $centerSphere :
[ [ 121.492183 , 31.247610 ] , 1000 / 3963.2 ] } } }
)
查詢結果默認由近及遠,并且geoWithin是mongodb支持的查詢函數(shù),已經(jīng)在性能上做了高度的優(yōu)化,完全可以生產用,現(xiàn)在moment的地理位置推薦用的這個
方案四
GeoHash是一種地址編碼,通過切分地圖區(qū)域變成小的方塊,只有切分的足夠小,精度就越高。
上一篇:Redis分布式鎖奧義 下一篇:Redis遍歷方式思考–字典擴容方式
總結
以上是生活随笔 為你收集整理的LBS解决方案 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內容還不錯,歡迎將生活随笔 推薦給好友。