web-dev-qa-db-ja.com

何百万ものJSONドキュメントをMongoDBにインポートする最速の方法

次の形式のJSONドキュメントが1,000万を超えています。

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

1つのファイルで。

Java Driver APIを使用したインポートには約3時間かかりましたが、次の関数を使用しました(一度に1つの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は人工キーを作成してドキュメントごとにインデックスを作成する必要がありません)、または挿入時にインデックスの作成をまったく無効にします。ありがとう。

13
rok

少し速い方法があります(現在、数百万を挿入しています)。単一のドキュメントの代わりにコレクションを挿入します。

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/ を参照してください。

パフォーマンスを向上させるもう1つの方法は、一括挿入後にインデックスを作成することです。ただし、これが1回限りのジョブを除いてオプションになることはめったにありません。

これが少し羊毛のように聞こえる場合はお詫びしますが、私はまだ自分でテストしています。良い質問。

3
tom

申し訳ありませんが、コアの問題ではなく、マイナーなパフォーマンスの問題を選択しています。ロジックをファイルの読み取りと挿入から分離することは、小さなメリットです。 (MMAPを介して)バイナリモードでファイルをロードすることは小さな利益です。モンゴのバルクインサートを使用することは大きな利益ですが、それでもサイコロはありません。

全体的なパフォーマンスのボトルネックは、BSON bson = JSON.parse(line)です。言い換えれば、Javaドライバーの問題は、jsonからbsonへの変換が必要であり、このコードが非常に遅いか、実装が不十分であるように見えることです。完全なJSON(エンコード+デコード) )JSON経由-単純または特別にJSON-smart経由は、JSON.parse()コマンドよりも100倍高速です。

Stack Overflowがこのボックスの真上で答えを出すべきだと言っているのは知っていますが、私はそうではありませんが、この問題の答えを探しているので安心してください。 Mongoのパフォーマンスに関するすべての話を信じることができず、この単純なサンプルコードは非常に惨めに失敗します。

8

約2億5000万レコードの複数行のjsonファイルのインポートを完了しました。 mongoimport <data.txtを使用するだけで、10時間かかりました。 10M対3時間と比較すると、これはかなり速いと思います。

また、私の経験から、独自のマルチスレッドパーサーを作成すると、処理速度が大幅に向上します。手順は簡単です。

  1. ファイルをBINARY(テキストではありません!)として開きます
  2. マーカー(オフセット)をファイル全体に均等に設定します。マーカーの数は、必要なスレッドの数によって異なります。
  3. マーカーの近くで「\ n」を検索し、マーカーが線に揃うように調整します。
  4. 各チャンクをスレッドで解析します。

リマインダー:

パフォーマンスが必要な場合は、ストリームリーダーや組み込みの行ベースの読み取りメソッドを使用しないでください。彼らは遅いです。バイナリバッファを使用し、「\ n」を検索して行を識別し、(最も好ましくは)文字列を作成せずにバッファ内でインプレース解析を実行します。そうでなければ、ガベージコレクターはこれにそれほど満足しません。

5
Yadli

ファイル全体を一度に解析し、json全体をmongoドキュメントに挿入できます。複数のループを回避します。ロジックを次のように分離する必要があります。

1)ファイルを解析し、jsonオブジェクトを取得します。

2)解析が終了したら、jsonオブジェクトをMongoドキュメントに保存します。

4
Jhanvi

一括操作の挿入/アップサートを使用します。 Mongo 2.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();
2
PUG

また、すべてのインデックス(もちろん、PKインデックスを除く)を削除して、インポート後に再構築することもできます。

1
evanchooly

一括挿入が可能

ドキュメントは mongo website で読むことができ、StackOverflowでこれを確認することもできます Javaの例

0
Sam Wolfand