zoukankan      html  css  js  c++  java
  • 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(相交)的支持是正常的,超过半球或者接近半球时,判定方式让人摸不着头脑。如果有懂的大神看见了。麻烦指教以下。

      

  • 相关阅读:
    神经网络
    机器学习英语
    机器学习常用函数解析
    机器学习(二)
    机器学习(三)
    Python文本数据分析与处理
    数据分析
    sklearn
    「Poetize9」升降梯口
    「Poetize9」礼物运送
  • 原文地址:https://www.cnblogs.com/ttjsndx/p/9750694.html
Copyright © 2011-2022 走看看