JSONストリーミング

JSONストリーミングは、低レベルのストリーム指向プロトコル( TCPなど)上に構築されたJSONオブジェクトを区切るための通信プロトコルで構成されます。これにより、サーバーとクライアントが同じJSONオブジェクトを使用する場合(例えば、暗黙的にコーディングされている場合)、個々のJSONオブジェクトが認識されます。JSONは非連結プロトコルであるため(2つのJSONオブジェクトを連結しても有効なJSONオブジェクトは生成されない)、この仕組みが必要になります。

導入

JSONは、システム間でオブジェクトデータを交換するための一般的なフォーマットです。株価表示アプリケーションのログレコードなど、単一の接続を介してオブジェクトのストリームを送信する必要があることがよくあります。[ 1 ]このような場合、JSONでエンコードされたオブジェクトの終わりと次のオブジェクトの始まりを識別する必要があります。技術的には、これはフレーミングと呼ばれます。

これを実現する一般的な方法は 4 つあります。

  • 改行なしでフォーマットされたJSONオブジェクトを送信し、改行を区切り文字として使用します。[ 2 ]
  • レコード区切り制御文字を区切り文字として連結したJSONオブジェクトを送信します。[ 3 ]
  • 区切り文字なしで連結された JSON オブジェクトを送信し、ストリーミング パーサーを使用してそれらを抽出します。
  • 長さをプレフィックスとして JSON オブジェクトを送信し、ストリーミング パーサーを使用してそれらを抽出します。

比較

行区切りの JSON は、従来の行指向ツールで非常にうまく機能します。

連結JSONは整形されたJSONと連携しますが、解析にはより多くの労力と複雑さを伴います。従来の行指向ツールではうまく動作しません。連結JSONストリーミングは、行区切りのJSONストリーミングのスーパーセットです。

長さプレフィックス付きJSONは、整形されたJSONと連携して動作します。従来の行指向ツールとは相性が良くありませんが、行区切りや連結されたストリーミングよりもパフォーマンス上の利点がある場合があります。また、解析もよりシンプルになります。

アプローチ

改行区切りのJSON

行区切りの JSON の同等の形式を表す 2 つの用語は次のとおりです。

ストリーミングは、JSON形式ではプリミティブ値内にリターン文字と改行文字を使用できない(文字列ではそれぞれととしてエスケープする必要がある)という事実と、ほとんどのJSONフォーマッタがデフォルトでリターン文字と改行文字を含む空白文字を含まない設定になっているという事実を利用しています。これらの機能により、改行文字またはリターン文字と改行文字のシーケンスを区切り文字として使用できます。 \r\n

この例では、2 つの JSON オブジェクトを示します (各行の末尾の暗黙的な改行文字は表示されません)。

{ "some" : "thing\n" } { "may" :{ "include" : "nested" , "objects" :[ "and" , "arrays" ]}}

改行を区切り文字として使用することで、この形式は従来の行指向の Unix ツールで非常にうまく機能します。

たとえば、ログ ファイルは次のようになります。

{ "ts" : "2020-06-18T10:44:12" , "開始" :{ "pid" : 45678 }}{ "ts" : "2020-06-18T10:44:13" "logged_in" :{ "username" : "foo" }、"connection" :{ "addr" : "1.2.3.4" "port" : 5678 }}{ "ts" : "2020-06-18T10:44:15" "registered" :{ "username" : "bar" "email" : "[email protected]" }、"connection" :{ "addr" : "2.3.4.5" "port" : 6789 }}{ "ts" : "2020-06-18T10:44:16" "logged_out" :{ "username" : "foo" }、"connection" :{ "addr" : "1.2.3.4" "port" : 5678 }}

これにより、日付による並べ替え、ユーザー名、アクション、IP アドレスなどの grep検索が非常に簡単になります。

互換性

行区切りのJSONは、連結されたJSONを処理できるパーサーで読み取ることができます。JSONオブジェクト内に改行を含む連結されたJSONは、行区切りのJSONパーサーでは読み取ることができません。

「行区切りの JSON」と「改行区切りの JSON」という用語は、埋め込まれた改行がサポートされているかどうかを明確にせずによく使用されます。

かつての改行区切りJSON仕様[ 9 ]では、行の最初の2文字が「//」であればコメントを埋め込むことができました。しかし、コメントが含まれていると、標準のJSONパーサーでは使用できませんでした。現在の仕様(「NDJSON - 改行区切りJSON」)[ 10 ]ではコメントは含まれません。

連結されたJSONは、 jqなどの適切なJSONユーティリティを使用して行区切りのJSONに変換できます。例えば、

jq --compact-output . <連結された.json > lines.json 

レコード区切りのJSON

レコード区切りのJSONストリーミングでは、JSONフォーマッタが空白文字を除外する必要なく、JSONテキストシーケンスを区切ることができます。JSONテキストシーケンスには制御文字を含めることができないため、レコード区切り文字を使用してシーケンスを区切ることができます。さらに、自己区切りではないトップレベルのJSONオブジェクト(数値、true、false、null)を適切に処理できるように、各JSONテキストシーケンスの後に改行文字を挿入することをお勧めします

この形式は JSON テキスト シーケンスまたはMIME タイプ とも呼ばれapplication/json-seq、IETF RFC 7464で正式に説明されています。

以下の例は、レコード区切り制御文字を表す ␞ と改行文字を表す ␊ を持つ 2 つの JSON オブジェクトを示しています。

{ "some" : "thing\n" } { "may" : { "include" : "nested" , "objects" : [ "and" , "arrays" ] } } 

連結されたJSON

連結JSONストリーミングでは、送信側は各JSONオブジェクトを区切り文字なしでストリームに書き込むだけで済みます。受信側は、終端文字を解析しながら各JSONオブジェクトを認識し、出力できるパーサーを使用する必要があります。連結JSONは新しいフォーマットではなく、複数のJSONオブジェクトを区切り文字なしでストリーミングする単なる名称です。

この形式の利点は、改行文字が埋め込まれたフォーマット(例えば、人間が読みやすいように整形されたフォーマット)のJSONオブジェクトを処理できることです。例えば、次の2つの入力はどちらも有効であり、同じ出力を生成します。

{ "some" : "thing\n" }{ "may" :{ "include" : "nested" , "objects" :[ "and" , "arrays" ]}}
{ "some" : "thing\n" } { "may" : { "include" : "nested" , "objects" : [ "and" , "arrays" ] } }

行ベースの入力に依存する実装では、パーサーがオブジェクトをタイムリーに出力するために、各JSONオブジェクトの後に改行文字が必要になる場合があります。(改行文字がない場合、行はパーサーに渡されずに入力バッファ内に残る可能性があります。)JSONオブジェクトを改行文字で終了することは非常に一般的であるため、これが問題として認識されることはほとんどありません。

長さプレフィックス付きJSON

長さプレフィックス付きまたはフレーム付きのJSONストリーミングでは、送信者が各メッセージの長さを明示的に指定できます。受信側は、各長さnを認識し、それに続くnバイトを読み取ってJSONとして解析できるパーサーを使用する必要があります。

この形式の利点は、各メッセージの正確な長さが明示的に指定されているため、パーサーに区切り文字の検索を強制する必要がなく、解析を高速化できることです。長さプレフィックス付きJSONは、単一の「メッセージ」を任意のチャンクに分割できるTCPアプリケーションにも適しています。プレフィックス付きの長さによって、パーサーはJSON文字列を解析する前に、想定されるバイト数を正確に知ることができるためです。

この例では、長さプレフィックスが付いた 2 つの JSON オブジェクトを示します (それぞれの長さは、次の JSON 文字列のバイト長です)。

18 { "some" : "thing\n" } 55 { "may" :{ "include" : "nested" , "objects" :[ "and" , "arrays" ]}}

アプリケーションとツール

改行区切りのJSON

レコード区切りのJSON

  • jq は、レコード区切りで区切られた JSON テキストの作成と読み取りの両方が可能です。
  • json-stream-es は、レコード区切りで区切られた JSON ドキュメントを作成および読み取ることができる JavaScript/TypeScript ライブラリ (フロントエンドおよびバックエンド) です。

連結されたJSON

  • concatjson は、 Node.js用の連結 JSON ストリーミング パーサー/シリアライザー モジュールです。
  • json-stream-es は、連結された JSON ドキュメントを作成および読み取ることができる JavaScript/TypeScript ライブラリ (フロントエンドおよびバックエンド) です。
  • Jackson (API)は連結された JSON コンテンツを読み書きできます。
  • jq軽量で柔軟なコマンドライン JSON プロセッサ
  • Noggit Solr の Java 用ストリーミング JSON パーサー
  • Yajl – Yet Another JSON Library。YAJLは、 ANSI Cで書かれた小規模なイベント駆動型(SAXスタイル)JSONパーサーであり、検証機能を備えた小規模なJSONジェネレーターです。
  • ArduinoJson は連結された JSON をサポートする C++ ライブラリです。
  • GSON JsonStreamParser.java は連結された JSON を読み取ることができます。
  • json-stream は、Python 用のストリーミング JSON パーサーです。

長さプレフィックス付きJSON

  • missiveストリーム上で長さプレフィックス付き JSON メッセージをエンコードおよびデコードするための高速で軽量なライブラリ
  • ネイティブメッセージングWebExtensions ネイティブメッセージング

参考文献

  1. ^ Ryan, Film Grain. 「Filmgrainの開発過程、パート2/2」 filmgrainapp.com. 2013年7月5日時点のオリジナルよりアーカイブ。 2013年7月4日閲覧
  2. ^ 「JSON 行」
  3. ^ Williams, N. (2015). 「RFC 7464」 .コメント募集. doi : 10.17487/RFC7464 .
  4. ^ 「ndjson - 改行区切りのJSON - 構造化データのフォーマット」ndjson.org . 2023年12月18日時点のオリジナルよりアーカイブ。 2025年10月22日閲覧
  5. ^ ndjson/ndjson-spec , ndjson, 2025-10-18 , 2025-10-22取得
  6. ^ ndjson. "Update specification_draft2.md · ndjson/ndjson-spec@c658c26" . GitHub . 2025年10月22日閲覧
  7. ^ 「JSON Lines」 . jsonlines.org . 2025年10月22日閲覧
  8. ^ 「JSON Lines |On The Web」 . jsonlines.org . 2025年10月22日閲覧
  9. ^ 「改行区切りのJSON」。Jimbo JW 。2015年12月22日時点のオリジナルよりアーカイブ
  10. ^ 「NDJSON - 改行区切りのJSON」 . GitHub . 2021年6月2日.
  11. ^ 「Monolog、Logstash、Elasticsearch を使用した集中ログ記録」
  12. ^ 「パッケージ org.eclipse.rdf4j.rio.ndjsonld」 . Eclipse Foundation . 2023年5月1日閲覧
  13. ^ 「改行区切りJSON-LD形式向けのRDFParserとRDFWriter実装の導入」 rdf4j Githubリポジトリ2021年2月2023年5月1日閲覧