【发布时间】:2014-10-22 17:03:12
【问题描述】:
使用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 字段。
附录:我尝试对文本索引的不是一个字段,而是所有字段——因此是"$**"。作为实验,我在所有字段上手动执行了.ensureIndex(...),希望这对排序有所帮助。但请记住,我并不是要对文本字段进行排序——只是将其作为一种机制来获取与搜索条件匹配的 JSON 对象集合。一旦我拥有了该集合,并且确实获得了该集合,我将尝试按 rank 字段对其进行排序,该字段已经有一个索引并且可以在其他场景中使用。
【问题讨论】:
-
在上面的示例中,我并没有尝试获取文本搜索的排名,而只是使用文本搜索来选择记录(获取子集);记录本身具有与之关联的独立排名字段,因此目标是按该值对返回的子集进行排序——因此是上面的代码。
-
虽然两者都是索引,但文本索引和“普通”索引在它们的实际功能(以及底层数据结构)方面完全不同。文本索引无法像“普通”索引那样帮助您对文本字段的值进行排序。在文本字段上创建一个“正常”索引并使用它进行排序。但是,在您使用文本搜索的相同字段上进行排序似乎有点时髦,除非它们只是标题或其他东西。
-
@wdberkeley:(请参阅上面的附录。)它不是单个文本字段[在“文本字段”上方],而是所有字段“$**”[如文档所述]。虽然全文搜索正在工作,但它是返回的集合,我无法通过我预先存在的具有索引的“排名”字段进行排序,尽管我可以通过它对其他查询进行排序就好了。我希望我只是误解了你的建议,所以我有一条路可以尝试。你能描述一下'在文本字段上创建一个“正常”索引并使用它来排序'的意思吗?我有多个要在其中搜索的字段和一个要排序的字段。非常感谢。
-
好的。我明白发生了什么。文本索引阻止您使用排名索引进行排序。然后 MongoDB 尝试按等级对内存进行排序,但这样做会达到内存限制。我认为除了自己对其进行排序或将结果数限制为可排序数之外,没有其他方法可以解决此问题。如果我想到其他任何事情,我会告诉你的。