使用Java从MongoDB获取随机文档/记录

时间:2012-10-16 10:12:38

标签: java mongodb random

下面我有一些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个文档。速度不是很重要。

感谢您的帮助!

2 个答案:

答案 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。