MongoDB $near 查询准确性问题

Posted

技术标签:

【中文标题】MongoDB $near 查询准确性问题【英文标题】:MongoDB $near query accuracy issue 【发布时间】:2018-10-07 16:10:44 【问题描述】:

在我的应用程序中,我想查询坐标附近(例如 5 公里内)的项目,我尝试使用 $near 来实现这一点。快速浏览了一下,我认为它有效,但在我进一步测试后,查询似乎有些不准确。这是我的设置:

    我选择了两个相距不到 5 公里的坐标:

    61.4644750214197, 23.8426943813556 61.497133399999996, 23.778528100000003

(至少根据this、this 或 this 等工具,这些坐标之间的距离应该约为 ~4.99 公里)

    我将其中一个坐标添加到空的“项目”集合中:
db.items.insert(
    "geo" : 
        "type" : "Point",
        "coordinates" : [ 
            61.4644750214197, 
            23.8426943813556
        ]
    
);
    我在集合中添加了“2dsphere”索引,使地理空间查询成为可能:
db.items.createIndex(  geo : "2dsphere"  )
    最后,我使用 $near 查询的另一个坐标:
db.items.find(geo: 
    $near: 
        $geometry: 
            type: "Point" ,
            coordinates: [ 61.497133399999996, 23.778528100000003 ]
        ,
        $maxDistance: 5000 // according to docs with '2dsphere' index and GeoJSON this is is meters
    
).count()
    我预计结果为 1,但结果为 0。即使我将 $maxDistance 设置为 7000,结果仍为 0,但如果我将其设置为 8000,结果将为 1。

我做错了什么还是 MongoDB 地理空间查询(或只是 $near 查询?)不准确?如果是这样,有没有更好的方法来获得这种查询的准确结果?这是我第一次在 MongoDB 中处理地理空间查询,所以对于我的问题可能有一个简单的解释。

编辑: 基本上,我梦想有一种功能可以在距离用户当前位置 X 公里的地图中显示所有项目,并且 X 可以由用户确定。如果用户想要过滤 7 公里内的项目,5 公里内的项目将不可见,这将是很尴尬的。

我已经尝试了大多数用于执行此查询的选项,例如 $centerSphere、$nearSphere 和 geoNear,结果相似。他们似乎都声称我前面提到的坐标之间的距离在 7-8 公里之间。我开始考虑 1. 我缺少一些关于距离一般如何工作的关键信息,或者 2. 用mongodb 根本无法解决我的问题。以下是我对其他选项的查询:

$centerSphere(5、6 和 7 公里的结果为 0,但 8 公里的结果为 1):

db.items.find(  geo:  
        $geoWithin:  $centerSphere: [ [ 61.497133399999996, 23.778528100000003 ], 5/6378.1 ] 
    
).count()

geoNear(maxDistance 5000、6000 和 7000 的 0 个结果,但 8000 的 1 个结果):

db.runCommand(
   
     geoNear: "items",
     near:  type: "Point", coordinates: [ 61.497133399999996, 23.778528100000003 ] ,
     spherical: true,
     maxDistance: 5000
   
)

【问题讨论】:

$nearSphere 是实际考虑地球曲率的算子。我以为$near 运算符上有对它的引用,但似乎没有。 是的,地理空间查询的数学运算存在“内置错误”。地球不是“真的”一个球体,你必须期待错误。但应该在5米以内 @NeilLunn 在这种情况下,$nearSphere 我得到与$near 相同的结果。 在同一个坐标上,这并不奇怪。关键是如果你想要你使用的“真实”距离。但是“错误”仍然是任何地理空间计算所固有的。你有很多关于haversine和类似算法的阅读。 感谢@NeilLunn 的回复!我再次阅读了您的原始评论,现在我明白了您的意思。我仍然认为我在查询中得到 $maxDistance 值为 5000、6000 和 7000 的 0 结果的原因无法解释:在这种情况下,准确度“错误”远远超过 5m。 【参考方案1】:

我知道我迟到了,但对于所有面临类似问题的人

这里的问题是,当您将数据存储到“坐标”中时,它必须按 [longitude, latitude] 顺序,因为这就是 mongodb 的工作方式。 https://docs.mongodb.com/manual/geospatial-queries/#spherical 我刚刚以相反的坐标顺序运行了您的示例,它按预期工作。

db.items.insert(
    "geo" : 
        "type" : "Point",
        "coordinates" : [ 
            23.8426943813556,
            61.4644750214197
        ]
    
);

然后我跑了

db.items.find(geo: 
    $near: 
        $geometry: 
            type: "Point" ,
            coordinates: [  23.778528100000003 , 61.497133399999996]
        ,
        $maxDistance: 5000
    
).count()

这里的计数是1:

希望对你有帮助

【讨论】:

感谢 Ishaan,帮了大忙。

以上是关于MongoDB $near 查询准确性问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 mongoid dsl 中编写 mongodb $near 查询?

Mongodb $near 查询 120 万份文档耗时 6 秒

geoNear 在 MongoDB 中提取不准确的结果

使用 java 的 MongoDb $near 查询没有给出正确的位置

具有稀疏复合索引的 MongoDB $near 地理空间查询错误 13311

具有稀疏复合索引的 MongoDB $near 地理空间查询错误 13311