以google.gson.JsonArray格式从MongoDB返回大型数据集的有效方法

时间:2017-06-20 06:57:53

标签: java json mongodb performance gson

我有一个mongo数据库查询,返回10000多条记录。对于商业服务,我想以GSON(谷歌JSON)格式返回记录。以下是代码段。

        String mongoClientURI = null;
        mongoClientURI = "mongodb://" + dbUser + ":" + pwd + "@" + host + ":" + port + "/" + databaseName;


        MongoClient client = new MongoClient(new MongoClientURI(mongoClientURI));
        MongoDatabase db = client.getDatabase(databaseName);

        // Find query returns more than 10K records
        FindIterable<Document> dbResult = db.getCollection("mycollection").find();  

        // This line takes too much time & CPU      
        List<Document> result = getDocumentArray(dbResult);

        // This line takes too much time & CPU
        JsonArray finalResult = getJSONArray(result);

    public static List<Document> getDocumentArray(FindIterable<Document> input) {
        List<Document> output = new ArrayList<Document>();
        for (Document doc : input) {
            output.add(doc);
        }
        return output;
    }

    public static JsonArray getJSONArray(Iterable<Document> docs) {
        JsonArray result = new JsonArray();
        if (docs == null) {
            return result;
        }

        for (Document doc : docs) {
            JsonObject jsonObject;
            JsonParser parser = new JsonParser();
            try {
                jsonObject = parser.parse(doc.toJson()).getAsJsonObject();
                result.add(jsonObject);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        return result;
    }

问题是从MongoDB获取数据到GSON数组时需要花费大量时间和CPU周期。有人可以告诉我从mongodb获取大数据集到gson格式的有效方法是什么?

通常我会获得大约10k到20K的记录,(最多50K)。我需要归还所有这些。我的UI组件需要一次性中的所有记录来呈现数据。通常人们使用带有分页的数据网格,因此一次性没有太多记录,但在我的情况下,我有地图组件,它取得所有记录和动态创建一组对象。

非常感谢任何帮助。

Atul Sureka

2 个答案:

答案 0 :(得分:1)

有效的方法是不要一次性返回所有文档,而是使用skip()limit()函数来实现分页。如果你的收藏品让我们说了一百万份文件,你最终会在内存中找到一个大的List,你甚至可能不需要一次性在UI上显示所有文件。

以下是如何实现分页:

1st Call : db.getCollection("mycollection").find().limit(10);
2nd Call : db.getCollection("mycollection").find().skip(10).limit(10);
3rd Call : db.getCollection("mycollection").find().skip(20).limit(10);

skip驱动页码,而limit驱动每页的项目。您也可以使用sort来定义排序(here's文档)。

另一种方法是使用排队机制或流式传输来滚动cursor中的所有文档并推送到队列/客户端。

<强>更新

您可以采取以下措施来加快现有实施的速度:

  • Iterable转换为parallelStream以更快地处理文档(请查看this以及如何将Iterable转换为stream的答案
  • 不要为每个文档创建JsonParser实例。创建一个实例并将其用于所有文档。
  • 为您的应用程序增加Xmx

答案 1 :(得分:0)

您是否在mongoDB中的列上添加了索引?它有助于更​​快地获取/读取查询。默认索引位于_id列。

另一种方法是根据特定标准找到,尝试将其拆分为2

db.getCollection("mycollection").find({ dept: "grocery", category: "chocolate"  }); 
db.getCollection("mycollection").find({ dept: "sales", category: "honey"  }); 

并稍后合并此结果