不使用$ maxDistance

时间:2016-11-25 13:38:13

标签: mongodb

目前我们在$near中的MongoDB 3.2.9操作遇到了大麻烦。

问题是在创建游标时有无尽的负载 - 直到超时。这个问题只会导致我们不使用$maxDistance - 在我们的情况下,重要的是不要使用它。

这是我们的收藏:

地点

带有GeoJSON属性的大约2.000.000个文档" geometry"这也是索引。

除了几何外,还有另一个名为" category"。

的索引

在我们的特殊情况下,我们的查询现在看起来像这样:

Locations.find({
  category: 'ABC',
  geometry: { 
    '$near': { 
      $geometry: {
        type: "Point" ,
        coordinates: [ 13.357315063476564, 52.53167855932515 ]
      }
    } 
  } 
}, {
  limit: 10
});

此查询将导致超时

要解决此问题,我们需要添加$maxDistance操作,它会正常工作(如果$ maxDistance的值不是太高)但在我们的情况下,$maxDistance非常糟糕,因为它如果1个位置与另一个位置有很大距离并不重要。例如,当第一个找到的位置在挪威,第二个位于澳大利亚的某个地方时,它没问题。

其他信息:

LESS 然后是结果限制时,此问题才会导致。在上面的示例中,我们的数据库中有8个具有此类别的位置。如果我们在10个以上的位置进行相同的查询,则需要大约几毫秒。

总结一下:

// Does not work. Ends up in an timeout
Locations.find({
  category: 'ABC', // has 9 locations
  geometry: { 
    '$near': { 
      $geometry: {
        type: "Point" ,
        coordinates: [ 13.357315063476564, 52.53167855932515 ]
      }
    } 
  } 
}, {
  limit: 10
});

// Works fine because of the $maxDistance - but in our case a $maxDistance is very BAD and needed to be prevented!
Locations.find({
  category: 'ABC', // has 9 locations
  geometry: { 
    '$near': { 
      $geometry: {
        type: "Point" ,
        coordinates: [ 13.357315063476564, 52.53167855932515 ]
      }
    },
    '$maxDistance': 5000 // If this value is too high - like the maxDistance is "the whole world" the query would also end up in an timeout 
  } 
}, {
  limit: 10
});

// Works fine because >= 10 items
Locations.find({
  category: 'DEF', // has 10 locations
  geometry: { 
    '$near': { 
      $geometry: {
        type: "Point" ,
        coordinates: [ 13.357315063476564, 52.53167855932515 ]
      }
    } 
  } 
}, {
  limit: 10
});

我们正在使用 MongoDB 3.2.9

其他信息

这个问题与我们在nodeJS中使用MongoDB的事实无关。我们也在使用RoboMongo,在执行此查询时,同样的问题会导致:超时!

1 个答案:

答案 0 :(得分:1)

我创建了一个集合,因为您包含200万个包含随机数据的文档,为categorygeometry字段准备了索引。当我继续测试这个集合时,我遇到了和你一样的问题。

没有$maxDistance值花了大约50秒。起初它似乎是合理的,因为没有$maxDistance Mongo必须搜索“全世界”的结果。但后来我检查了查询的.explain()结果并意识到它根本没有使用索引,在查询中没有阶段IXSCAN(在旧版本的Mongo中这是BasicCursor) 。所以问题很明显,我错误地创建了索引,你也是。

您(我也是)创建的索引是Single Field Indexes,只有在按单个字段搜索时才有用。在这种情况下,您需要搜索两个字段,因此您需要使用Compound Indexes。使用此命令创建可在搜索中使用的复合索引:

db.collection({category: 1, geometry: '2dsphere'});

我做到了,效果惊人,时间从50秒减少到几百毫秒。