LBS的两种实现

2011-04-22 15:26

[LBS,MongoDB]

LBS的核心是地理位置信息的索引和检索。位置信息一般采用经纬度表示,不支持通用的比较、排序,所以导致系统实现难度很大。

地理位置信息计算需要解决的问题有
精度

一般表示为

40:26:46N,79:56:55W
40:26:46.302N 79:56:55.903W
40°26′47″N 79°58′36″W
40d 26′ 47″ N 79d 58′ 36″ W
40.446195N 79.948862W
40.446195, -79.948862
40° 26.7717, -79° 56.93172

用度分秒表示时,1度可能是41km,很大的一个单位。

距离

由于地球半径的影响,两个经纬度之间的距离计算非常的麻烦
PostGis >

PostGIS adds support for geographic objects to the PostgreSQL object-relational database.是一个非常专业的实现。支持众多的系统和数据格式,据称现在版本已经支持3D。

实现一个位置查询:With the population of the people in New York within 500 meters of a subway station:

> SELECT Sum(popn_total) FROM nyc_census_blocks census 
  JOIN nyc_subway_stations subway ON ST_DWithin(census.the_geom, subway.the_geom, 500);
10556898

其数据表示很是有意思

360610001009000 = 36 061 00100 9000
36     = State of New York
061    = New York County (Manhattan)
000100 = Census Tract
9      = Census Block Group
000    = Census Block

也可以做简单地理性质的计算

> SELECT ST_Distance(ST_GeographyFromText('POINT(-118.4079 33.9434)'), 
-- Los Angeles (LAX)ST_GeographyFromText('POINT(2.5559 49.0083)')     
-- Paris (CDG)); 

由于对 PostgreSQL 生态系统知之甚少,不太敢于使用。

MongoDB

相比PostgreSQL的实现简单、易懂很多。 其位置表示为:

{ loc : { long : 40.739037, lat: 73.992964 } }

创建索引

db.places.ensureIndex( { loc : "2d" } )

按矩形区域查找

> box = [[40.73083, -73.99756], [40.741404,  -73.988135]]
> db.places.find({"loc" : {"$within" : {"$box" : box}}})

按半径查找

> center = [50, 50]
> radius = 10
> db.places.find({"loc" : {"$within" : {"$center" : [center, radius]}}})

作为新兴的数据库系统,在使用过程中被爆了很多问题

  • FourSquare使用过程中散列不够均匀
  • 存储较为浪费
  • 使用了 mmap 可能导致数据丢失

我去年测试其集群功能时,在数据量达到1亿左右时也出现了问题,但是MongoDB绝对是最快、最合适的解决方案,当然要避免、解决很多问题。