将数百万个JSON文档导入MongoDB的最快方法

rok*_*rok 13 java import performance json mongodb

我有超过1000万个JSON文档的形式:

["key": "val2", "key1" : "val", "{\"key\":\"val", \"key2\":\"val2"}"]
Run Code Online (Sandbox Code Playgroud)

在一个文件中.

使用JAVA Driver API导入大约需要3个小时,同时使用以下功能(一次导入一个BSON):

public static void importJSONFileToDBUsingJavaDriver(String pathToFile, DB db, String collectionName) {
    // open file
    FileInputStream fstream = null;
    try {
        fstream = new FileInputStream(pathToFile);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        System.out.println("file not exist, exiting");
        return;
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(fstream));

    // read it line by line
    String strLine;
    DBCollection newColl =   db.getCollection(collectionName);
    try {
        while ((strLine = br.readLine()) != null) {
            // convert line by line to BSON
            DBObject bson = (DBObject) JSON.parse(JSONstr);
            // insert BSONs to database
            try {
                newColl.insert(bson);
            }
            catch (MongoException e) {
              // duplicate key
              e.printStackTrace();
            }


        }
        br.close();
    } catch (IOException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }


}
Run Code Online (Sandbox Code Playgroud)

有更快的方法吗?也许,MongoDB设置可能会影响插入速度?(例如,添加键:"_ id"将作为索引,因此MongoDB不必创建人工密钥,因此不必为每个文档编制索引)或在插入时完全禁用索引创建.谢谢.

小智 8

对不起,你们都在挑选性能问题而不是核心问题.将逻辑与读取文件和插入分开是一个很小的收获.以二进制模式加载文件(通过MMAP)是一个很小的收获.使用mongo的批量插入是一个很大的收获,但仍然没有骰子.

整个性能瓶颈是BSON bson = JSON.parse(line).或者换句话说,Java驱动程序的问题是它们需要从json转换为bson,而且这段代码似乎非常缓慢或者执行得很糟糕.通过JSON-simple或特别是通过JSON-smart完整的JSON(编码+解码)比JSON.parse()命令快100倍.

我知道Stack Overflow正在告诉我,我应该回答这个答案,我不是,但请放心,我仍然在寻找这个问题的答案.我无法相信所有关于Mongo性能的讨论,然后这个简单的示例代码失败如此悲惨.


Yad*_*dli 5

我已经完成了导入一个包含约250M记录的多行json文件.我只使用mongoimport <data.txt,花了10个小时.与你的10M和3小时相比,我认为这要快得多.

另外,根据我编写自己的多线程解析器的经验,可以大大加快速度.程序很简单:

  1. 将文件打开为BINARY(不是TEXT!)
  2. 在文件中均匀设置标记(偏移).标记计数取决于您想要的线程数.
  3. 在标记附近搜索'\n',校准标记,使它们与线对齐.
  4. 用线程解析每个块.

提醒:

如果需要性能,请不要使用流阅读器或任何内置的基于行的读取方法.他们很慢.只需使用二进制缓冲区并搜索'\n'来标识一行,并且(最优选地)在缓冲区中进行就地解析而不创建字符串.否则垃圾收集器会对此不满意.


tom*_*tom 3

我有一个稍微快一点的方法(我现在也插入了数百万个),插入集合而不是单个文档

insert(List<DBObject> list)
Run Code Online (Sandbox Code Playgroud)

http://api.mongodb.org/java/current/com/mongodb/DBCollection.html#insert(java.util.List)

也就是说,速度并没有那么快。我即将尝试设置除 ACKNOWLEDGED(主要是 UNACKNOWLEDGED)之外的其他 WriteConcerns,看看是否可以加快速度。有关信息,请参阅http://docs.mongodb.org/manual/core/write-concern/

另一种提高性能的方法是在批量插入后创建索引。然而,除了一次性工作之外,这很少是一种选择。

如果这听起来有点毛茸茸的,我很抱歉,我仍在自己进行测试。好问题。