Java 将数百万JSON文档导入MongoDB的最快方式

Java 将数百万JSON文档导入MongoDB的最快方式,java,json,performance,mongodb,import,Java,Json,Performance,Mongodb,Import,我有1000多万个JSON文档,格式如下: ["key": "val2", "key1" : "val", "{\"key\":\"val", \"key2\":\"val2"}"] 在一个文件中 使用JAVA驱动程序API导入大约需要3个小时,同时使用以下函数(一次导入一个BSON): 有没有更快的办法?MongoDB设置可能会影响插入速度?(例如,添加键:“_id”,它将用作索引,这样MongoDB就不必为每个文档创建人工键和索引)或在插入时禁用索引创建。 谢谢。我有一个稍微快一点的方法(

我有1000多万个JSON文档,格式如下:

["key": "val2", "key1" : "val", "{\"key\":\"val", \"key2\":\"val2"}"]
在一个文件中

使用JAVA驱动程序API导入大约需要3个小时,同时使用以下函数(一次导入一个BSON):

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

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

insert(List<DBObject> list)
插入(列表)

也就是说,速度没有那么快。我将尝试设置除已确认(主要是未确认)之外的其他writeconcern,看看是否可以加快速度。有关信息,请参阅

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


抱歉,如果这听起来有点含糊不清,我自己还在测试。好问题。

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

您可以一次性解析整个文件,并在mongo文档中插入整个json,避免多个循环,您需要按如下方式分离逻辑:

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


2) 解析完成后,将json对象保存在Mongo文档中。

我已经导入了一个包含2.5亿条记录的多行json文件。我只是使用mongoimport 根据我的经验,编写自己的多线程解析器将大大加快速度。程序很简单:

  • 以二进制文件(而不是文本)打开文件
  • 在整个文件中均匀设置标记(偏移)。标记的计数取决于所需的线程数
  • 在标记附近搜索“\n”,校准标记,使其与直线对齐
  • 用线程解析每个块
  • 提醒:


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

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

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


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

    您可以使用批量插入


    您可以在上阅读文档,也可以在StackOverflow上检查该文档,使用批量操作插入/插入。在
    mongo2.6
    之后,您可以执行批量操作。下面的示例使用
    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();
    
    MongoCollection collection=database.GetCollection(collectionName);
    var bulk=collection.initializeUnderedBulkOperation();
    foreach(fooDocsList中的foodocfoodoc)
    {
    var update=newupdateDocument{{fooDoc.ToBsonDocument()};
    bulk.Find(Query.EQ(“_id”,fooDoc.id)).Upsert().UpdateOne(update);
    }
    BulkWriteResult bwr=bulk.Execute();
    
    您是否试图一次解析多行?这可以减少初始化JSON解析器的总开销。此外,您还可以研究其他BSON/JSON解析器。Jackson()以速度极快而闻名,我相信现在已经有了本地BSON支持。它也是可定制的,因此您可以删除/优化解析器的某些功能。另一件事:您可能希望将json的解析与解析结果的保存分开。也就是说,这似乎是一个简单的生产者/消费者问题,其中一个线程可以读取/解析JSON并添加到队列中,而另一个线程则从队列中提取并批量插入到db中。我想“一次插入一个”的方法是你最慢的部分,但是如果没有分析,很难知道。也许你应该尝试将实际的解析放在不同的线程中。也许您可以使用
    Executors.newFixedThreadPool(n)
    其中
    n
    是一个给定时间可以运行的线程数。虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,仅链接的答案可能会变得无效。完全同意,JSON.parse非常糟糕,在尝试并行转换的一些实验中,它似乎不是线程安全的。
    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();