LBS-查找附近的人-mongodb实现-基础知识

接下来我们开始介绍mongodb的解决方案。mongodb也是早些年“快的”的解决方案。

地理空间数据

在MongoDB中,可以将地理空间数据存储为 GeoJSON对象传统坐标对

GeoJSON对象

要计算类球体上的几何体,位置数据应存储为GeoJSON对象。

要指定GeoJSON数据,请使用嵌入式文档:

  • type:指定GeoJSON对象类型
  • coordinates:指定对象的坐标。
<field>: { type: <GeoJSON type> , coordinates: <coordinates> }

如:

location: {
      type: "Point",
      coordinates: [-73.856077, 40.848447]
}

GeoJSON对象在MongoDB地理空间查询在球体上计算,使用WGS84参考系统对GeoJSON对象进行地理空间查询。

传统坐标对

要计算欧几里得平面上的距离,位置数据应存储为传统坐标对,并使用2d索引。将数据转换为GeoJSON Point类型后,并通过2dsphere索引后传统坐标对也支持球面曲面计算。

要将数据指定为传统坐标对,也有两种数据格式可以使用,数组嵌入式文档 。 官方推荐首先使用 数组

数组方式(首选):

<field>:[<longitude>, <latitude>]

嵌入式文档方式:

<field>:{<field1>:<longitude>, <field2>:<latitude>}
  • 有效经度值介于-180和180。
  • 有效的纬度值介于-90和90。

注意:为什么要说这个经纬度的有效值呢,因为mongodb不仅仅是对地球的经纬系统支持,也支持其他的平面坐标系。如果使用纬度和经度坐标必须使用 longitude(经度)在前,latitude(纬度)在后的顺序。

地理空间索引

在MongoDB中,地理数据相关的索引有两种 2dsphere2d。地球状球体计算几何的查询应使用 2dsphere 索引。 2d 索引在二维平面上使用存储为点的数据的索引。该 2d 索引适用于MongoDB 2.2及更早版本中使用的传统坐标对。

当然通过将数据转换为GeoJSON Point类型,MongoDB通过2dsphere索引支持传统坐标对上的球面曲面计算。所以 GeoJSON对象传统坐标对 更加强大复杂,但是 传统坐标对 也是支持 2dsphere

两种索引的方式虽然不同,不过,只要坐标跨度不太大(比如几百几千公里),这两个索引计算出的距离相差几乎可以忽略不计。

  1. 2dsphere

2dsphere索引支持在地球球上计算几何的查询。

db.collection.createIndex({ <location field>: "2dsphere" })
  1. 2d

2d索引支持在二维平面上计算几何的查询 。尽管索引可以支持 $nearSphere 在球体上计算的查询,但如果可能的话,请使用 2dsphere 索引进行球形查询。

db.collection.createIndex({ <location field> : "2d" })

其中 <location field> 的值是 GeoJSON对象传统坐标对 的字段。

地理空间查询运算符

MongoDB提供了以下地理空间查询操作符:

名称 描述
$geoIntersects 选择与GeoJSON几何体相交的几何体,2dsphere索引支持
$geoWithin 选择边界GeoJSON几何内的几何,2dsphere和2D索引支持
$near 返回靠近点的地理空间对象。需要一个地理空间索引,2dsphere和2d索引支持
$nearSphere 返回球体上某个点附近的地理空间物体。需要一个地理空间索引,dsphere和2d索引支持

其中 $geoNear 包含 $match,$sort和$limit参数。输出文件包含一个额外的距离字段,并可包含位置标识符字段。

下表列出了每个地理空间操作使用的地理空间查询运算符:

方法 坐标 说明
$near(GeoJSON质心点在这一行和下面一行,2dsphere) 球形 另请参阅$nearSphere运算符,它在与GeoJSON和2dsphere索引一起使用时提供相同的功能。
$near(传统坐标,2d) 平面
$nearSphere(GeoJSON,2dsphere) 球形 提供与$near使用GeoJSON和2dsphere相同的功能。对于球形查询,最好使用 $nearSphere明确指定名称中的球形查询而不是$near
$nearSphere(传统坐标,2d) 球形 改为使用GeoJSON点。
$geoWithin:{ $geometry:...} 球形
$geoWithin:{ $box:...} 平面
$geoWithin:{ $polygon:...} 平面
$geoWithin:{ $center:...} 平面
$geoWithin:{ $centerSphere:...} 球形
$geoIntersects 球形
$geoNear(2dsphere) 球形
$geoNear(2d) 平面

示例

GeoJSON对象数据

创建集合-插入数据-建立索引

#创建集合
db.createCollection("places")
#插入数据
db.places.insert({
    name: "Central Park",
   location: { type: "Point", coordinates: [ -73.97, 40.77 ] },
   category: "Parks"
} );
db.places.insert({
   name: "Sara D. Roosevelt Park",
   location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },
   category: "Parks"
} );
db.places.insert({
   name: "Polo Grounds",
   location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },
   category: "Stadiums"
} );
#在location字段上创建索引
db.places.createIndex( { location: "2dsphere" } )

以下查询使用$near操作返回距离指定GeoJSON至少1000米且最远5000米的数据,并按从最近到最远的顺序排序:

db.places.find(
   {
     location:
       { $near:
          {
            $geometry: { type: "Point",  coordinates: [ -73.9667, 40.78 ] },
            $minDistance: 1000,
            $maxDistance: 5000
          }
       }
   }
)

以下查询使用$geoNear命令查询并过滤 { category: "Parks" } 相匹配的数据,按照距离指定的GeoJSON最近的顺序排序

db.runCommand(
   {
     geoNear: "places",
     near: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
     spherical: true,
     query: { category: "Parks" }
   }
)

传统坐标对数据

创建集合-插入数据-建立索引

db.createCollection("location")
db.location.save( {_id: "A", position: [0.1, -0.1]} )
db.location.save( {_id: "B", position: [1.0, 1.0]} )
db.location.save( {_id: "C", position: [0.5, 0.5]} )
db.location.save( {_id: "D", position: [-0.5, -0.5]} )
db.location.ensureIndex( {position: "2d"} )

查询point(0,0),半径0.7附近的点

db.location.find( {position: { $near: [0,0], $maxDistance: 0.7  } } )

查询[0.25, 0.25], [1.0,1.0]区域附近的点

db.location.find( {position: { $geoWithin: { $box: [ [0.25, 0.25], [1.0,1.0] ] } } } )

参考 mongodb官方文档

到此mongodb地理数据支持的基础知识已经介绍完,请看下篇实战篇,我们还是会生成600w调数据mongodb方案进行测试。

文章同步发布在博客,LBS-查找附近的人-mongodb实现-基础知识

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容