更新: 故事偏离主题,标题误导性。问题是由损坏的数据集,而不是游标或MongoDB本身引起的。但我宁愿把这个帖子留在这里而不是删除它,因为它可能会帮助其他绝望的人。
===原创故事从这里开始===
一切都从这里开始:MongoDB: cannot use a cursor to iterate through all the data
我试图在Java中迭代游标,但它失败了,因为我的集合有太多记录(~250M)。我试图分配一个新的游标并使用cursor.skip在光标超时时跳回来但是cursor.skip本身超时。
所以我写了一个像这样的javascript:
db=connect("localhost/twitter");
db.jobScheduler.drop();
for(var i = 0;i<16;++i)
{
db.jobScheduler.save({_id:"s"+i,jobs:[]});
}
var c = db.tweets.find({},{_id:1}).sort({_id:1});
var totalCount = c.count();
var currentBatchSize = 0;
var currentNum = 0;
var currentShard = 0;
var startTid = 0;
var endTid = 0;
var currentTid = 0;
while(true)
{
while(c.hasNext())
{
var doc = c.next()
currentTid = doc._id;
if(currentBatchSize == 0)
{
startTid = doc._id;
}
++currentNum;
++currentBatchSize;
if(currentBatchSize == 50000)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
print(currentNum+"/"+totalCount+"("+currentNum*100/totalCount+"%)");
print("["+startTid+","+endTid+"]");
}
}
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
}
if(currentBatchSize != 0)
{
currentBatchSize = 0;
endTid = doc._id;
db.jobScheduler.update(
{_id:"s"+currentShard},
{$push:{jobs:[startTid,endTid]}});
currentShard = (currentShard+1)%16;
}
考虑到仅仅拉动_id仍然会导致超时,我添加了一个这样的警卫:
if(currentNum != totalCount){
var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
print("Cursor resetted....");
}else
break;
因为当光标超时时,我没有得到异常而是一个假的cursor.hasNext()。
由于我在迭代它时已经记录了currentTid,因此理论上使用范围查询var c = db.tweets.find({_id:{$gt:currentTid}},{_id:1}).sort({_id:1});
将使我回到原位。然而,可怜的小程序最终会像这样:
[337242463750201340,345999466677010400]
21800000/253531208(8.598546968624076%)
[345999469818544100,346244305876295700]
Cursor resetted....
Cursor resetted....
Cursor resetted....
它似乎永远停留在第一次出现的游标超时。范围查询并没有让我回头。
现在我真的很困惑。迭代不起作用。 cursor.skip()不起作用。范围查询不起作用。什么真的适用于MongoDB?或者有什么我做错了吗?
非常感谢任何帮助!
更新
我与@AsyaKamsky进行了一些讨论,他帮我发现了以下内容:
实验正在进行中。实时更新此主题: - )
更新:失败!我每次阅读50k记录后都尝试更新光标。它也被困在这个神奇的索引21800000!这非常接近我的cursor.skip()失败偏移!
更新
确认猜测:
c = db.tweets.find().skip(21800000); //works
c = db.tweets.find().skip(21850000); //doesn't work
我会尝试在这个范围内进行二元搜索以找到幻数。
更新
好的......找到了幻数。
db.tweets.find()。itcount() - &GT; 21837006
db.tweets.find()。COUNT() - &GT; 253531208
现在怎样?这真的很糟糕。