NDJSON

NDJSONファイルとは

1 行に 1 つの JSON オブジェクト。ログのパイプラインやデータ書き出しが出力する形です。

NDJSON とは何か

NDJSON はプレーンテキスト形式です。どのエディターでも開けます。 プログラム間のデータ受け渡しとストリーミングのために使われます。

拡張子は .ndjson、正式名称は Newline-Delimited JSON です。ただしどちらも、そのファイルが中に何を持てるかほどには多くを語りません。このページの残りは、その中身についての話です。

NDJSON はどこから来たのか

2013 年までさかのぼります。

古さが役に立つのは、ごく実務的な理由からです。形式が古いほど、それを覚える時間が多くのプログラムに与えられてきたということだからです。

仕様は公開されています

仕様書がそのまま公開されているので、中身を推し量るのではなく文書を読んで実装できます。この形式が数多くのプログラムに載っているのはそのためであり、20 年前に書かれたファイルが今も開けるのもそのためです。ただし「仕様が公開されている」ことと「使用料が要らない」ことは別の話です。中でコーデックを包んでいる形式では、特許のライセンスは仕様書が答えていない別の問題として残ります。

捨てられるものはありません

NDJSON ファイルは中身をそのまま保存します。保存し直しても何も変わらないので、開いて、直して、また保存する——それを何度繰り返しても劣化は積み上がりません。これが、渡すための形式ではなく作業のための形式である理由です。

ほかに何を運べるか

NDJSON ファイルは全部が届く前に再生を始められる構造を持てます。

これは変換のときにとくに効いてきます。変換先が持てないものは落とされ、たいてい警告もありません。

コメントを書く場所がありません

NDJSON ファイルにはコメントを書く方法がありません。説明にあたるものはすべてファイルの外に置くことになります。人が手で面倒を見る用途にこれを選ぶ前に、知っておくべきことです。

NDJSON を開けるのは何か

jqとpandasが読めますし、同じ種類のプログラムならたいてい読めます。

ファイルが開かないとき、形式が悪いことはめったにありません。たいていはプログラムのほうが形式より古いのです。もっと古い形式に変換してしまうのが確実な逃げ道で、このサイトの残りの部分はそのためにあります。

ブラウザーで開く

これを読めるブラウザーはありません。

これを変換するいちばんよくある理由がこれです。形式が悪いのではありません。ファイルを見せたい場所が、それを読めないというだけのことです。

作業のための形式です

NDJSON は、開いて手を入れるために作られています。作業が続いているあいだはこの形式でファイルを持ち、完成したものが必要になるたびに、ここから書き出してください。

JSON の配列は終わるまで読めません

これがこの形式が存在する問題です。JSON 文書は閉じる括弧が届いて初めて有効になります。だから十ギガバイトのレコードの配列を渡されたパーサーは、最初の一件を返す前に十ギガバイトすべてを読み込まなければなりません。終わりのないログストリームなら、何も返せないまま終わります。

NDJSON は配列を取り除きます。各行が完全で独立した JSON オブジェクトで、改行で終わり、周りには何もありません。読む側は一行を取り、解析し、処理し、忘れます。だからメモリ使用量はファイルのサイズではなく最大のレコードのサイズで決まり、プロセスは最初のレコードにすぐに取りかかれます。

追記のしやすさがもう半分の論拠です

JSON の配列にレコードを追加するにはファイルの書き直しが要ります。閉じる括弧は末尾にあり、何かがその前に入らなければなりません。NDJSON ファイルにレコードを追加するのは、一行を書くことです。

これが、時間とともに蓄積するもの ── アプリケーションのログ、イベントストリーム、監査証跡、スクレイピングしたデータ、テレメトリ ── にとって自然な形式になっている理由です。また、これが JSON の配列にはない形で並行性に対して安全である理由でもあります。システムのアトミックな書き込みサイズ以下の一行の書き込みは、別の書き手の行と混ざり合わないので、複数のプロセスが同じファイルに追記しても壊れません。

被害は一行に閉じ込められます

クラッシュやディスク満杯で途中で切れた JSON の配列は、全体として無効になります。括弧が一つ足りないだけで、パーサーは正しく届いた 99% を含めてファイル全体を拒否します。

書き込み途中で切れた NDJSON ファイルは、最後の一行だけを失い、それ以外は何も失いません。それより前のすべての行は解析でき、読む側は壊れた一行を飛ばして続けられます。何週間もかけて集められ、いずれ壊れるハードウェアに保存されるデータにとって、この違いは机上の空論ではありません。

どこで出会うか

ログの配送と可観測性です。Elasticsearch の bulk API、Logstash、Fluentd、Vector、そしてたいていの構造化ロギングのライブラリはどれもこれを話します。一回のレスポンスに収まりきらない大量の行を返す API からのデータのエクスポート。機械学習のデータセットも、訓練データが一行一例で、ストリームのループで読み込まれます。

また、実行に時間のかかるリクエストのための送信形式としても使われます。サーバーが結果を得るたびに一行の JSON オブジェクトを書き、クライアントはレスポンス全体を待たずに届いた順に処理します。

この形式を機能させ続けるルール

一行に一つのオブジェクト、その中に改行を入れないこと。JSON の文字列はエスケープされた改行を正当に含められますが、リテラルな改行を含んではいけません。整形して複数行に広げられたオブジェクトはこの形式を完全に壊し、これが NDJSON ファイルが間違って生成される、圧倒的に多い原因です。

UTF-8、BOM なし、そして最終行の末尾に改行があること。改行が欠けたり、余分な空行があったりしてはいけません。行末は単純な種類にすべきです。改行の前に Windows 風の復帰文字を付けると、多くの読み手には許容されても一部には拒否され、まさに診断しがいのない間欠的な失敗を生みます。

NDJSON、JSON Lines、JSONL

同じものを指す三つの名前です。NDJSON はメディアタイプを持つ仕様、JSON Lines は別に書かれた同一形式の記述、JSONL は拡張子として使われる呼び方で、機械学習の分野でとくによく見かけます。

それぞれの仕様の違いは見た目だけです。ここでの改行の扱いについての注意書き、あちらでの許容される拡張子。実際にはどのツールもそれらを区別しません。どちらかの拡張子を持つファイルは、もう一方を想定するものに渡せます。

変換元・変換先として

一つの文書を求める相手には JSON へ。行を括弧でくるみ、カンマでつなげば済み、単純ですが、まさにこの形式が NDJSON だった理由であるメモリの問題を再び持ち込みます。

データが本当にフラットなレコードで、誰かがスプレッドシートを求めているときは CSV へ。落とし穴は JSON が入れ子で CSV がそうではないことです。入れ子のオブジェクトはドット区切りの列名にフラット化しなければならず、配列は落とすか結合しなければなりません。これは報告書には妥当な非可逆な工程で、アーカイブには適していません。

そして分析目的なら Parquet へ。列指向で圧縮され型を持つ形式は、イベントデータに対して人が実際に投げるクエリに対してはるかに速く読み込まれ、大きな NDJSON のアーカイブがたいてい最終的に行き着くべき場所です。

基本情報

NDJSONフォーマットの識別子と出自。
拡張子.ndjson, .jsonl
メディアタイプapplication/x-ndjson
初版2013

NDJSON ファイルについてよくある質問

NDJSON と JSON の違いは何ですか

JSON ファイルは一つの文書で、何かに使う前に丸ごと読まなければなりません。NDJSON ファイルは 1 行につき完全な JSON オブジェクトを一つ持つので、ストリームできます。メモリ使用量はファイルのサイズではなく一レコード分で済み、処理は最初の行からすぐに始められます。

NDJSON と JSONL、JSON Lines は同じものですか

はい。名前は三つ、仕様はほぼ同一の二つですが、実際にはどのツールもそれらを区別しません。どちらかの拡張子を持つファイルは、もう一方を想定するものに渡せます。

NDJSON ファイルはどう開けばいいですか

小さいものならどんなテキストエディタでも構いません。1 行 1 レコードのプレーンテキストだからです。大きなものにはストリームできるツール ── チャンクで読むコードエディタ、ページャー、行指向のデータ向けに作られたコマンドラインのユーティリティ ── を使ってください。

一つのレコードを複数行にまたがせられますか

できません。これがこの形式が間違って生成される、いちばんよくある原因です。整形されて複数行に広がった JSON オブジェクトは完全に壊れます。文字列の中の改行はエスケープしなければならず、リテラルな改行はレコードをそこで終わらせてしまいます。

NDJSON がログに向いているのはなぜですか

レコードを追加するのはファイルの書き直しではなく一行を書くことで、複数のプロセスが安全に追記でき、クラッシュで途中切れたファイルは最後の一行だけを失います。途中切れた JSON の配列は、正しく届いた部分を含めて全体が無効になります。

NDJSON を CSV に変換するには

レコードがフラットならうまくいきます。JSON は入れ子になり CSV はそうならないので、入れ子のオブジェクトはドット区切りの列名にフラット化し、配列は落とすか結合する必要があります。報告書には妥当ですが、アーカイブには非可逆です。分析用途なら Parquet のほうが良い行き先です。