我有一个非常大的文档集合,比如:
{ loc: [10.32, 24.34], relevance: 0.434 }
并希望能够高效地执行如下查询:
{ "loc": {"$geoWithin":{"$box":[[-103,10.1],[-80.43,30.232]]}} }
使用任意框。
在loc
上添加一个2d索引可以让这一切变得非常快速和高效。然而,我现在只想获取最相关的文档:
.sort({ relevance: -1 })
这导致所有东西都被磨得像爬虫一样(在任何特定的框中都可能有大量的结果,我只需要前10个左右)。
非常感谢任何建议或帮助!
发布于 2013-09-03 17:16:43
您尝试过使用聚合框架吗?
两阶段管道可能会起作用:
下面是一个可能看起来像这样的示例:
db.foo.aggregate(
{$match: { "loc": {"$geoWithin":{"$box":[[-103,10.1],[-80.43,30.232]]}} }},
{$sort: {relevance: -1}}
);
我不确定它将如何表现。然而,即使它在MongoDB 2.4中表现不佳,在2.6/2.5中可能会有很大的不同,因为2.6将包括improved aggregation sort performance。
发布于 2013-09-03 05:22:31
当有一个巨大的结果匹配特定的框时,排序操作是非常昂贵的,所以你肯定想要避免它。尝试在相关性字段上创建单独的索引,并尝试使用它(根本没有2d索引):查询将以这种方式执行得更有效-文档(已按相关性排序)将逐个扫描符合给定地理框条件的文档。当前十名被找到时,你就是好的。
然而,如果地理框只匹配集合的一小部分,那么它可能不会那么快。在最坏的情况下,它将需要扫描整个集合。
我建议你创建2个索引(loc与相关性),并在你的应用中常见的查询上运行测试(使用mongo的提示强制使用所需的索引)。
根据您的测试结果,您甚至可能想要添加一些应用程序逻辑,以便如果您知道框很大,则可以使用相关性索引运行查询,否则使用loc 2d index。这只是个想法。
发布于 2013-09-03 16:53:53
当您尝试使用对复合键的部分进行排序时,不能将scan和order值设置为0。不幸的是,目前还没有解决您的问题的解决方案,这与您正在使用2d索引或其他现象无关。
当您在查询上运行explain命令时,"scanAndOrder“的值将显示收集结果后是否需要进行排序阶段,或者not.If是否需要在查询后进行排序,如果为假,则不需要排序。
为了测试这种情况,我在示例数据库中创建了一个名为t2的集合,如下所示:
db.createCollection('t2')
db.t2.ensureIndex({a:1})
db.t2.ensureIndex({b:1})
db.t2.ensureIndex({a:1,b:1})
db.t2.ensureIndex({b:1,a:1})
for(var i=0;i++<200;){db.t2.insert({a:i,b:i+2})}
虽然您只能使用一个索引来支持查询,但我进行了以下测试,并包含了以下结果:
mongos> db.t2.find({a:{$gt:50}}).sort({b:1}).hint("b_1").explain()
{
"cursor" : "BtreeCursor b_1",
"isMultiKey" : false,
"n" : 150,
"nscannedObjects" : 200,
"nscanned" : 200,
"nscannedObjectsAllPlans" : 200,
"nscannedAllPlans" : 200,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"b" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "localhost:27418",
"millis" : 0
}
mongos> db.t2.find({a:{$gt:50}}).sort({b:1}).hint("a_1_b_1").explain()
{
"cursor" : "BtreeCursor a_1_b_1",
"isMultiKey" : false,
"n" : 150,
"nscannedObjects" : 150,
"nscanned" : 150,
"nscannedObjectsAllPlans" : 150,
"nscannedAllPlans" : 150,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 1,
"indexBounds" : {
"a" : [
[
50,
1.7976931348623157e+308
]
],
"b" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "localhost:27418",
"millis" : 1
}
mongos> db.t2.find({a:{$gt:50}}).sort({b:1}).hint("a_1").explain()
{
"cursor" : "BtreeCursor a_1",
"isMultiKey" : false,
"n" : 150,
"nscannedObjects" : 150,
"nscanned" : 150,
"nscannedObjectsAllPlans" : 150,
"nscannedAllPlans" : 150,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 1,
"indexBounds" : {
"a" : [
[
50,
1.7976931348623157e+308
]
]
},
"server" : "localhost:27418",
"millis" : 1
}
mongos> db.t2.find({a:{$gt:50}}).sort({b:1}).hint("b_1_a_1").explain()
{
"cursor" : "BtreeCursor b_1_a_1",
"isMultiKey" : false,
"n" : 150,
"nscannedObjects" : 150,
"nscanned" : 198,
"nscannedObjectsAllPlans" : 150,
"nscannedAllPlans" : 198,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"b" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
],
"a" : [
[
50,
1.7976931348623157e+308
]
]
},
"server" : "localhost:27418",
"millis" : 0
}
单个字段上的索引没有多大帮助,因此a_1 (不支持排序)和b_1 (不支持查询输入)被排除在外。a_1_b_1上的索引也不走运,虽然它的性能会比单个a_1差,但mongoDB引擎不会利用与一个'a‘值相关的部分以这种方式存储的情况。值得一试的是一个复合索引b_1_a_1,在你的例子中是relevance_1_loc_1,而它将以有序的方式返回结果,所以scanAndOrder将是false,我没有测试过2d索引,但我假设它将排除扫描一些仅基于索引值的文档(这就是为什么在这种情况下,nscanned比nscannedObjects更高)。不幸的是,索引将会很大,但仍然比文档要小。
https://stackoverflow.com/questions/18493698
复制相似问题