下面我有一些Java代码来从集合中获取所有记录/文档
DBCollection collection = database.getCollection("collection");
BasicDBObject select = new BasicDBObject();
select.put("title", 1);
select.put("name", 1);
String random = JSON.serialize(collection.find(select));
现在我想从集合中随机说出10个文件。
我该怎么做?这可能吗?
我发现了很多其他人的问题但不是真正的解决方案。我在集合中有大约1500个文档。速度不是很重要。
感谢您的帮助!
答案 0 :(得分:1)
以下是给您的提示:使用随机数嵌入每个文档(例如,从0..1间隔开始)和使用范围查询来提取随机文档。
例如,假设我们有集合test
。
在shell中,您可以使用随机数以这种方式嵌入此集合中的每个文档(使用服务器端脚本):
db.eval(
function(){
db.test.find().forEach(
function(obj){
obj.rnd = Math.random();
db.test.save(obj);
})})
并提取随机文档(此查询可以简单地翻译为在java中使用):
db.test.findOne({"rnd" : {"$gte" : Math.random()}})
因此,如果您从代码中生成文档:在持久存储将具有随机值的字段添加到文档之前。否则,如果您只能访问集合 - 使用服务器端js将每个文档嵌入随机值字段。
使用简单循环,您可以根据需要提取如此多的随机文档,但当然,您必须处理同一文档多次提取的情况(或者如果没有文档与查询匹配)。
答案 1 :(得分:0)
我相信您要实现的目标称为 Systematic Sampling 。
以下是实现目标的一种方法:
//...
List<DBObject> result = new ArrayList<DBObject>();
DBCollection collection = database.getCollection("collection");
long count = collection.getCount();
int limit = 10; //or whatever you want
if (count <= limit) {
DBCursor cursor = collection.find(select);
while (cursor.hasNext()) {
result.add(cursor.next());
}
} else {
long skip = Math.round((double) count / limit);
DBCursor cursor = collection.find(select);
while (result.size() < limit) {
int offset = (int) ((skip * result.size() + (int) ((Math.random() * skip) % count)) % count);
System.out.println(offset);
DBObject next = cursor.skip(offset).next();
result.add(next);
cursor = collection.find(select);
}
}
如果计数小于期望的限制,它基本上会收集所有文件。如果不 它会计算一个等于N(总计数)/ n(您的限制)的跳过。 然后计算随机偏移量,该偏移量始终在0和跳跃之间,但是考虑迭代。
作为一个例子,如果你有100个文件,你想要10个随机样本 以下每个桶的一个随机样品:1-10,11-20,21-30,31-40,41-50,51-60,61-70,71-80,81-90,91-100。