更新时更新:
解决!看到这个: MongoDB: cannot iterate through all data with cursor (because data is corrupted)
它是由损坏的数据集引起的。不是MongoDB或驱动程序。
=============================================== ==========================
我正在使用MongoDB(2.4.6)的最新Java驱动程序(2.11.3)。我有一个包含约250M记录的集合,我想使用游标迭代所有这些记录。但是,在10分钟左右之后,我得到了一个假的cursor.hasNext(),或者说服务器上没有光标的异常。
之后我学会了游标超时并用try / catch包装了我的cursor.next()。如果在遍历所有记录之前任何异常或hasNext()返回false,程序将关闭游标并分配一个新游标,然后再跳回上下文。
但后来我读到了关于cursor.skip()的性能问题......程序刚刚达到~20M记录,而cursor.skip()之后的cursor.next()抛出了“java.util.NoSuchElementException”。我相信这是因为跳过操作已经超时,这使光标无效。
是的我已经阅读过有关skip()性能问题和游标超时问题的内容......但是现在我认为我处于一个两难境地,即修复一个会破坏另一个。
那么,有没有办法优雅地遍历庞大数据集中的所有数据?
有没有办法实现这个目标?
当通过获得分区边界键来实现第一次搜索时,我确实有一些想法。如果新光标再次超时,我可以简单地记录最新的tweetID并跳回新范围。但是,范围查询应该足够快,否则我仍然会超时。我对此并不自信......
更新
问题解决了!我没有意识到我不必以粗糙的方式分区数据。循环工作调度员会这样做。请参阅接受的答案中的评论。
答案 0 :(得分:1)
总的来说,是的。如果你有一个单调场,理想情况下是一个索引场,你可以简单地走。例如,如果您使用ObjectId
类型的字段作为主键,或者如果您有CreatedDate
或其他内容,则只需使用$lt
查询,即可获取固定数量的元素,然后使用您在上一批中遇到的最小$lt
或_id
的{{1}}再次查询。
注意严格的单调行为与非严格的单调行为:如果密钥不严格,则可能必须使用CreatedDate
,然后防止在欺骗中做两次。由于$lte
字段是唯一的,_id
始终是严格单调的。
如果你没有这样的钥匙,事情会有点棘手。您仍然可以沿着索引进行迭代(无论索引,无论是名称,哈希,UUID,Guid等)。这也很有效,但很难做快照,因为你永远不知道你刚刚开始遍历之前是否插入了刚刚找到的结果。此外,在遍历开始时插入文档时,将会遗漏这些文档。