1

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

谢谢你的帮助!

4

2 回答 2

1

这是给您的提示:使用随机数嵌入每个文档(例如,从 0..1 间隔)并使用范围查询来提取随机文档

例如,假设我们有 collection 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 将每个文档嵌入随机值字段

使用简单的循环,您可以根据需要提取任意数量的随机文档,但是当然,您必须处理同一文档多次提取的情况(或者如果没有文档匹配查询)。

于 2012-10-16T13:14:28.257 回答
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。

于 2012-10-16T13:07:12.707 回答