文本搜索上的MongoDB溢出排序阶段

时间:2014-08-28 18:21:22

标签: mongodb sorting text

使用MongoDB v2.6,如果从大型结果集中对cursor进行排序以获得overflow,则情况并不鲜见。

cursor = db.collection.find( { "key" : "value" } )
cursor.sort( { "rank" : 1 } )  // This can blow up

错误看起来很像:

  

运行程序错误:溢出排序阶段缓冲数据使用量33598393字节超出内部限制33554432字节

在这种情况下,解决方案的解决方案是provide an index,而不仅仅是密钥。

db.collection.ensureIndex( { "rank" : 1 } )  // ascending

这很好用。


我在另一个地方遇到此问题,text index按照text index creation上的MongoDB手册中的说明,我已经正是这样做了:

db.collection.ensureIndex(
   { "$**": "text" },
   { name: "TextIndex" }
)

并且,这已经在集合中所有ExtendedJSON个对象的所有字段中创建了一个文本索引。

搜索效果很好。

cursor = db.collection.find( { "$text" : { "$search" : "NEEDLE" } } )
cursor.count()                      // w00t!  records that have NEEDLE in them

但是,尝试执行之前工作的相同排序,即使存在排序字段的索引:

db.collection.ensureIndex( { "rank" : 1 } )  
cursor = db.collection.find( { "$text" : { "$search" : "NEEDLE" } } )
cursor.sort( { "rank" : 1 } )      // This blows up with the same error message
  

运行程序错误:溢出排序阶段缓冲数据使用量33598393字节超出内部限制33554432字节


这是奇怪的部分。

迭代光标而不用执行排序工作正常,这就是我如何计算上面的数字。我甚至可以单步浏览光标并查看无序结果,因此文本搜索显然可以正常工作。

但是,省略文本搜索会导致排序正常工作;这让我觉得它不是基于数量的,虽然我知道它实际上只是使用了排序键的索引。

db.collection.ensureIndex( { "rank" : 1 } )  
cursor = db.collection.find( )     // Get absolutely everything
cursor.sort( { "rank" : 1 } )      // Well, sort now works again... hmm....

正如我必须"帮助" Mongo提供了一个索引,因此可以在不将所有记录带入内存的情况下进行排序,如何为文本索引实现此目的呢?

不幸的是,我无法获得explain plan,因为它也会产生同样的错误。如果我对.find() sans .sort()的结果执行此操作,则会显示明显的 - 对数据的完整扫描,没有IndexBounds字段。


ADDENDUM:它不是一个字段,而是所有字段,我试图将文本编入索引 - 因此"$**"。作为一个实验,我在所有字段上手动执行了.ensureIndex(...),希望这有助于排序。但请记住,我并没有尝试对文本字段进行排序 - 仅仅将其用作获取与搜索条件匹配的JSON对象集合的机制。一旦我拥有了该集合,并且我确实获得了该集合,我就会尝试按rank字段对其进行排序,该字段已经有索引并且可以在其他方案中使用。

2 个答案:

答案 0 :(得分:0)

也许这link会对你有帮助。

总结一下:你不应该在程序中间调用ensureIndex,而是让Mongoose为你调用它。只需将Schema中的标记index: true添加到要用于排序的字段即可。在你的情况下,将它添加到排名和名称应该没问题。至少这在我的项目中对我有用。

示例:

var schema = mongoose.Schema({
   ...
   normalText : String,
   rank : { type: Number, index: true},
   name : { type: String, index: true }
});

答案 1 :(得分:0)

希望这可以提供帮助。 尝试添加这样的代码。 这是为了排序排名。 $ cursor = $ cursor.sort({" rank":1})); 但你需要对$ text进行排序, 试试这个, $ cursor = $ cursor-> sort({" text":1});

感谢。