不使用$maxDistance的MongoDB中$附近的问题

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

问题是在创建游标时有无尽的负载 – 直到超时.这个问题只是在我们没有使用$maxDistance时 – 这在我们的情况下很重要,不能使用.

这是我们的收藏:

地点

带有GeoJSON属性“geometry”的大约2.000.000个文档,它也被索引.

除了几何之外,还有另一个名为“类别”的索引.

在我们的特殊情况下,我们的查询现在如下所示:

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,在执行此查询时,同样的问题会导致:超时!

最佳答案 我创建了一个集合,因为您包含200万个带有随机数据的文档,为类别和几何字段准备了索引.当我继续测试这个集合时,我遇到了和你一样的问题.

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

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

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

我做到了,结果令人惊讶,时间从50秒减少到几百毫秒.

点赞