mongo-2ds索引对超过半球范围的适用性测试

  以下测试均基于mongo v4.0 win10


一、GeoJSON

  GeoJSON是一种基于json的经纬度描述数据格式。在这里主要服务于2dsphere索引查询。

  基本格式  <type:"",coordinates:[]> ,type 对应的类型有Point、LineString(老版本有写Line的)、Polygon、MultiPoint、MultiLineString、MultiPolygon。coordinates对应格式可参照【表1】。

更详细的请自行百度。

二、2dsphere索引。

  基于地球的经纬度。举例如下

  存在点 【28,2】,则以下区域是否与该点存在交集($geoIntersects)的情况为

表1
  type coordinates 是否包含
1 Point [28,2]
2 LineString [[28,1],[28,3]]
3 LineString [[28,3],[28,1]]
4 LineString [[27,2],[29,2]]
5 LineString [[29,2],[27,2]]
6 Polygon [[[27,1],[27,3],[29,3],[29,1],[27,1]]]
7 Polygon [[[27,3],[27,1],[29,1],[29,3],[27,3]]]
8 Polygon [[[29,1],[29,3],[27,3],[27,1],[29,1]]]
9 Polygon [[[29,3],[29,1],[27,1],[27,3],[29,3]]]

  从LineString的四个例子中我们可以得出:getIntersects对LineString的支持性并不高,不过考虑到现实场景中的查询,都是以一个面积为参考的,所以LineString的测验只了解一个结果,不再深入研究。

  从Polygon的四个例子中我们可以暂时得出:GeoJSON的数组是不在乎顺序的,为了验证这个观点,我们再补做方向性的测试数据。

三、geoIntersects的方向性研究

表2
  type coordinates 是否包含
1 Polygon [[[27,1],[29,1],[29,3],[27,3],[27,1]]]
2 Polygon [[[27,3],[29,3],[29,1],[27,1],[27,3]]]
3 Polygon [[[29,3],[27,3],[27,1],[29,1],[29,3]]]
4 Polygon [[[29,1],[27,1],[27,3],[29,3],[29,1]]]
5 Polygon [[[29,1],[-27,3],[-27,3],[29,3],[29,1]]]
6      
7  Polygon [[[-179,1],[27,1],[27,3],[-179,3],[-179,1]]]
8 Polygon [[[0,90],[180,90],[180,-90],[0,-90],[0,90]]]
9 Polygon [[[0,90],[0,-90],[180,-90],[180,90],[0,90]]]
10 Polygon [[[0,-90],[0,90],[180,90],[180,-90],[0,-90]]]
11 Polygon [[[0,-90],[180,-90],[180,90],[0,90],[0,-90]]]
12 Polygon [[[180,-90],[0,-90],[0,90],[180,90],[180,-90]]]
13 Polygon [[[180,90],[0,90],[0,-90],[180,-90],[180,90]]]
14 Polygon [[[180,90],[180,-90],[0,-90],[0,90],[180,90]]]
16 Polygon [[[180,-90],[180,90],[0,90],[0,-90],[180,-90]]]

  根据【表2编号1-5】到验证了以上的猜想,GeoJSON数组代表的区域是 : 数组中的点连接成线,将经纬度网划分成两块,取面积小的那一块作为选定区域,进行筛选判定

  但是如果所选范围扩大到整个半球甚至更大,GeoJSON的数组该如何选择判定区域?从【表2编号7-16】中,我们什么也不能得出来,整个查询呈现出一种混乱的状态。又进行大量的对比实验,做了各种统计分析图后,结论依旧混乱,我甚至还去文具店买了一个地球仪。。。

  网上进行了大量查询,最后还是在官网找到了一些信息。3.0版本以后$within(表示包含)、$geoIntersects的Polygon查询支持新的参数:crs。可以指定特殊的索引范围划分方式。如EPSG:4326,判定区域时具有严格的逆时针顺序。更多更全的知识请移步 https://docs.mongodb.com/manual/reference/operator/query/geoIntersects/#geointersects-big-poly

  但是经过测验发现,4.0版本默认了EPSG:4326,加与不加,影响不大,测验如下($within与$geoIntersects结果一致):

1 > db.people.find({"add":{"$within":{"$geometry":{"type":"Polygon","coordinates":[[[27,1],[29,1],[29,3],[27,3],[27,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
2 { "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
3 > db.people.find({"add":{"$within":{"$geometry":{"type":"Polygon","coordinates":[[[29,1],[29,3],[27,3],[27,1],[29,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
4 { "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
5 > db.people.find({"add":{"$within":{"$geometry":{"type":"Polygon","coordinates":[[[29,3],[27,3],[27,1],[29,1],[29,3]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
6 { "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
7 > db.people.find({"add":{"$within":{"$geometry":{"type":"Polygon","coordinates":[[[27,3],[27,1],[29,1],[29,3],[27,3]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
8 { "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
9 > db.people.find({"add":{"$within":{"$geometry":{"type":"Polygon","coordinates":[[[27,1],[27,3],[29,3],[29,1],[27,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});

  甚至会出现这种莫名其妙的结果:

> db.people.find({"add":{"$geoIntersects":{"$geometry":{"type":"Polygon","coordinates":[[[0,1],[79,1],[79,3],[0,3],[0,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
{ "_id" : ObjectId("5bcafe07377b37ef8e160bc7"), "add" : { "type" : "Point", "coordinates" : [ 2, 2 ] } }
{ "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
{ "_id" : ObjectId("5bb4290d0c2287bbf737427d"), "name" : "ww wu", "age" : 40, "add" : { "type" : "Point", "coordinates" : [ 50, 2 ] } }
> db.people.find({"add":{"$geoIntersects":{"$geometry":{"type":"Polygon","coordinates":[[[0,1],[124,1],[124,3],[0,3],[0,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
{ "_id" : ObjectId("5bcafe07377b37ef8e160bc7"), "add" : { "type" : "Point", "coordinates" : [ 2, 2 ] } }
{ "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
> db.people.find({"add":{"$geoIntersects":{"$geometry":{"type":"Polygon","coordinates":[[[0,1],[120,1],[120,3],[0,3],[0,1]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
{ "_id" : ObjectId("5bcafe07377b37ef8e160bc7"), "add" : { "type" : "Point", "coordinates" : [ 2, 2 ] } }
{ "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
{ "_id" : ObjectId("5bb4290d0c2287bbf737427d"), "name" : "ww wu", "age" : 40, "add" : { "type" : "Point", "coordinates" : [ 50, 2 ] } }

  可以看出,mongo对于2ds索引的支持度并不高。那么我们完全按照官方文档的格式进行测试,看能不能得出一个有规律的结果。

  官方文档的格式:

  

db.places.find(
   {
     loc: {
       $geoIntersects: {
          $geometry: {
             type : "Polygon",
             coordinates: [
               [
                 [ -100, 60 ], [ -100, 0 ], [ -100, -60 ], [ 100, -60 ], [ 100, 60 ], [ -100, 60 ]
               ]
             ],
             crs: {
                type: "name",
                properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" }
             }
          }
       }
     }
   }
)

   格式定义如下:

  1、首尾相接(以前测试的数组都是满足的)

  2、逆时针方向书写

> db.people.find({"add":{"$geoIntersects":{"$geometry":{"type":"Polygon","coordinates":[[[0,3],[0,-1],[179,-1],[179,3],[0,3]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});
{ "_id" : ObjectId("5bcafe07377b37ef8e160bc7"), "add" : { "type" : "Point", "coordinates" : [ 2, 2 ] } }
{ "_id" : ObjectId("5bcb0145377b37ef8e160bcb"), "add" : { "type" : "Point", "coordinates" : [ 2, 4 ] } }
{ "_id" : ObjectId("5bb4c46d0c2287bbf737427e"), "name" : "王五", "age" : 26, "sex" : "", "add" : { "type" : "Point", "coordinates" : [ 28, 2 ] } }
{ "_id" : ObjectId("5bcb0158377b37ef8e160bcc"), "add" : { "type" : "Point", "coordinates" : [ 2, -2 ] } }
{ "_id" : ObjectId("5bb4290d0c2287bbf737427d"), "name" : "ww wu", "age" : 40, "add" : { "type" : "Point", "coordinates" : [ 50, 2 ] } }
> db.people.find({"add":{"$geoIntersects":{"$geometry":{"type":"Polygon","coordinates":[[[0,3],[0,1],[179,1],[179,3],[0,3]]],crs:{type:"name",properties:{name:"urn:x-mongodb:crs:strictwinding:EPSG:4326"}}}}}});

  讲道理,完全没有道理。


  总结,2ds对于小范围的within(包含),geoIntersects(相交)的支持是正常的,超过半球或者接近半球时,判定方式让人摸不着头脑。如果有懂的大神看见了。麻烦指教以下。

  

 

posted @ 2018-10-20 19:12  有营养的yyl  阅读(167)  评论(0编辑  收藏