【问题标题】:Fastest way to import millions of JSON documents to MongoDB将数百万个 JSON 文档导入 MongoDB 的最快方法
【发布时间】:2013-10-28 15:30:44
【问题描述】:

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

["key": "val2", "key1" : "val", "{\"key\":\"val", \"key2\":\"val2"}"]

在一个文件中。

使用 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.
    }


}

有没有更快的方法?也许,MongoDB 设置可能会影响插入速度? (例如,添加将用作索​​引的键:“_id”,以便 MongoDB 不必为每个文档创建人工键和索引)或在插入时完全禁用索引创建。 谢谢。

【问题讨论】:

  • 您是否尝试过一次解析不止一行?这可以减少初始化 JSON 解析器所花费的总开销。此外,您可以查看替代 BSON/JSON 解析器。 Jackson (jackson.codehaus.org) 以速度极快而闻名,我相信现在有原生的 BSON 支持。它也是可定制的,因此您可以删除/优化解析器的某些功能。
  • 另一件事:您可能希望将 json 的解析与解析结果的保存分开。也就是说,这似乎是一个简单的生产者/消费者问题,其中一个线程可能正在读取/解析 JSON 并添加到队列中,而另一个线程从队列中拉出并将 batch 插入到数据库中。我想“一次插入”的方法是你最慢的部分,但如果没有分析就很难知道。
  • 也许您应该尝试将实际解析放在不同的线程中。也许您可以使用Executors.newFixedThreadPool(n),其中n 是可以在给定时间1 运行的线程数。

标签: java json performance mongodb import


【解决方案1】:

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

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

我知道 Stack Overflow 在此框上方告诉我我应该回答答案,但我没有,但请放心,我仍在寻找此问题的答案。我不敢相信所有关于 Mongo 性能的讨论,然后这个简单的示例代码就失败了。

【讨论】:

  • 完全同意,JSON.parse 非常糟糕,从尝试并行转换的一些实验来看,它似乎不是线程安全的。
【解决方案2】:

我已经导入了一个包含约 2.5 亿条记录的多行 json 文件。我只是使用 mongoimport

根据我的经验,编写自己的多线程解析器也会大大加快速度。过程很简单:

  1. 以 BINARY(不是 TEXT!)形式打开文件
  2. 在文件中均匀设置标记(偏移)。标记的数量取决于您想要的线程数。
  3. 在标记附近搜索“\n”,校准标记,使其与线条对齐。
  4. 用一个线程解析每个块。

提醒:

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

【讨论】:

    【解决方案3】:

    你可以一次解析整个文件,然后将整个json插入mongo文档中,避免多次循环,你需要将逻辑分开如下:

    1)解析文件并检索json对象。

    2)一旦解析结束,将json对象保存到Mongo Document中。

    【讨论】:

      【解决方案4】:

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

      insert(List<DBObject> list)
      

      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/

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

      抱歉,如果这听起来有点毛骨悚然,我仍在自己测试。好问题。

      【讨论】:

        【解决方案5】:

        您也可以删除所有索引(当然,PK 索引除外)并在导入后重建它们。

        【讨论】:

          【解决方案6】:

          使用批量操作插入/更新插入。在Mongo 2.6 之后,您可以批量处理Updates/Upserts。下面的示例使用c# 驱动程序进行批量更新。

          MongoCollection<foo> collection = database.GetCollection<foo>(collectionName);
                var bulk = collection.InitializeUnorderedBulkOperation();
                foreach (FooDoc fooDoc in fooDocsList)
                {
                  var update = new UpdateDocument { {fooDoc.ToBsonDocument() } };
                  bulk.Find(Query.EQ("_id", fooDoc.Id)).Upsert().UpdateOne(update);
                }
                BulkWriteResult bwr =  bulk.Execute();
          

          【讨论】:

            【解决方案7】:

            您可以使用批量插入

            您可以阅读mongo website 的文档,也可以在 StackOverflow 上查看此java example

            【讨论】:

            • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
            猜你喜欢
            • 2023-03-09
            • 2023-03-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多