NDJSON

Wat is een NDJSON-bestand?

Eén JSON-object per regel. Wat logpijplijnen en gegevensuitvoer opleveren.

Wat NDJSON is

NDJSON is een puur tekstformaat dat in elke editor opengaat. Het wordt gebruikt voor gegevens tussen programma’s verplaatsen en streamen.

De extensie is .ndjson en de volledige naam Newline-Delimited JSON. Allebei zeggen ze minder dan wat het bestand kan bevatten, en daar gaat de rest van deze pagina over.

Waar NDJSON vandaan komt

Het gaat terug tot 2013.

De leeftijd is om een praktische reden interessant: hoe ouder een formaat, hoe meer programma’s de tijd hebben gehad om het te leren.

De specificatie is openbaar

Ze is volledig gepubliceerd, dus wie het formaat wil uitvoeren kan dat uit het document doen in plaats van door te kijken hoe anderen het doen. Daarom duikt het in zo veel programma’s op, en daarom gaan bestanden van twintig jaar geleden nog steeds open. Openbaar is niet hetzelfde als royaltyvrij: waar een formaat een codec omhult, is de octrooilicentie een aparte vraag waarop de standaard geen antwoord geeft.

Er wordt niets weggegooid

NDJSON bewaart zijn inhoud precies. Opnieuw opslaan verandert niets, dus je kunt het zo vaak openen, bewerken en wegschrijven als je wilt zonder dat er schade opstapelt — en dat is wat er een werkformaat van maakt in plaats van een afleverformaat.

Wat het verder kan dragen

NDJSON kan een opbouw waarmee het kan beginnen af te spelen voordat het volledig is aangekomen bevatten.

Dat telt vooral bij het converteren: wat het doel niet kan bevatten valt weg, meestal zonder waarschuwing.

Er is nergens plaats voor een aantekening

NDJSON heeft geen commentaarsyntaxis. Alles wat toelicht moet buiten het bestand leven, en dat is goed om te weten voordat je het kiest voor iets dat een mens met de hand bijhoudt.

Wat NDJSON opent

jq en pandas lezen het, en de meeste programma’s van dezelfde soort ook.

Als een bestand niet opengaat ligt het zelden aan het formaat — vaker is het programma ouder dan het formaat. Converteren naar iets ouders is de betrouwbare weg eromheen, en daarvoor is de rest van deze site bedoeld.

Het in de browser openen

Geen enkele browser leest het.

Dat is veruit de meest voorkomende reden om het te converteren: niet dat het formaat slecht is, maar dat de plek waar je het bestand wilt tonen het niet kan lezen.

Het is een werkformaat

NDJSON is bedoeld om te openen en te wijzigen. Houd het bestand in dit formaat zolang het werk loopt, en exporteer eruit wanneer er een afgeronde versie nodig is.

Een JSON-array kan pas gelezen worden zodra hij eindigt

Dit is het probleem waar het formaat voor bestaat. Een JSON-document is pas geldig zodra het sluitende haakje aankomt, dus een parser die een array van tien gigabyte records krijgt moet alle tien gigabyte in het geheugen lezen voordat hij het eerste record kan teruggeven.

NDJSON verwijdert de array. Elke regel is een compleet, onafhankelijk JSON-object, afgesloten met een regeleinde en omringd door niets. Een lezer neemt één regel, parseert die, verwerkt hem en vergeet hem — zodat geheugengebruik de grootte van het grootste record is in plaats van de grootte van het bestand.

Toevoegen is de andere helft van het argument

Een record aan een JSON-array toevoegen betekent het bestand herschrijven: het sluitende haakje staat aan het eind, en er moet iets voor komen. Een record aan een NDJSON-bestand toevoegen betekent een regel schrijven.

Dat maakt het het natuurlijke formaat voor alles dat na verloop van tijd aangroeit — applicatielogboeken, gebeurtenisstromen, auditsporen. Het is ook wat het veilig maakt onder gelijktijdigheid op een manier die een JSON-array niet is: een enkele regelschrijving zal niet verweven raken met die van een andere schrijver.

Schade blijft beperkt tot één regel

Een JSON-array afgebroken door een crash of een volle schijf is in zijn geheel ongeldig — één ontbrekend haakje en een parser wijst het hele bestand af, inclusief de 99 procent die perfect aankwam.

Een NDJSON-bestand afgebroken tijdens het schrijven verliest de laatste regel en niets anders. Elke complete regel ervoor blijft parseerbaar, en een lezer kan de gebroken regel overslaan en doorgaan.

Waar je het tegenkomt

Logverzending en observability: Elasticsearch’s bulk-API, Logstash, Fluentd, Vector en de meeste gestructureerde logbibliotheken spreken het allemaal. Data-exports van API’s die meer rijen teruggeven dan in één respons passen. Machine-learning-datasets, waar trainingsdata één voorbeeld per regel is.

Ook als draadformaat voor langlopende verzoeken, waar een server per regel een JSON-object schrijft naarmate resultaten beschikbaar komen en de client ze verwerkt zodra ze binnenkomen.

De regels die het werkend houden

Eén object per regel, en geen regeleindes erbinnen. Een JSON-string mag legaal een geëscapet regeleinde bevatten en mag nooit een letterlijke bevatten — een fraai opgemaakt object over meerdere regels breekt het formaat volledig, en dit is verreweg de meest voorkomende manier waarop een NDJSON-bestand verkeerd wordt gegenereerd.

UTF-8, geen byte-order mark, en een regeleinde aan het eind van de laatste regel. Regeleindes moeten het één-teken soort zijn: een Windows-carriage return voor elke newline wordt door de meeste lezers getolereerd en door sommige geweigerd.

NDJSON, JSON Lines en JSONL

Drie namen voor hetzelfde. NDJSON is de specificatie met een mediatype; JSON Lines is een apart geschreven beschrijving van hetzelfde formaat; JSONL is de extensie die mensen gebruiken, vooral in machine learning.

De verschillen tussen de specificaties zijn cosmetisch, en geen enkele tool in de praktijk maakt onderscheid. Een bestand met de ene extensie kan aan alles worden gegeven dat de andere verwacht.

Omzetten van en naar

Naar JSON, wanneer een consument één document wil: wikkel de regels in haakjes en voeg ze samen met komma’s. Triviaal, en het herintroduceert het geheugenprobleem, wat meestal precies waarom het bestand NDJSON was.

Naar CSV, wanneer de data echt platte records zijn en iemand een spreadsheet wil. De vangst is dat JSON genest is en CSV niet, dus geneste objecten moeten worden platgeslagen tot gepunte kolomnamen en arrays moeten worden weggelaten of samengevoegd. En naar Parquet voor alles analytisch, waar een grote NDJSON-archief meestal naartoe wil.

Comprimeren, en waarom dat de zelfbeschrijvende overhead niet wegneemt

Elke regel herhaalt zijn eigen sleutels, wat een reële kost is naast de data zelf. Gzip over een NDJSON-bestand comprimeert die herhaling echter uitstekend weg, want dezelfde veldnamen keer op keer zijn precies het soort herhaling waar Deflate goed in is.

Dat verklaart waarom een NDJSON-export vaak wordt uitgeleverd als `.ndjson.gz` in plaats van ongecomprimeerd: de omvang die de vorm kost, verdwijnt grotendeels bij het comprimeren, terwijl het regel-voor-regel lezen intact blijft zodra een decompressiestroom ervoor wordt gezet.

Wat er misgaat wanneer een generator het verkeerd doet

De meest voorkomende fout is een tool die JSON met inspringing schrijft — mooi leesbaar voor een mens, dodelijk voor het formaat, want elk record wordt dan over meerdere regels verspreid en de garantie van één regel per record verdwijnt.

De tweede is een script dat de laatste regel vergeet af te sluiten met een regeleinde. De meeste lezers zijn daar coulant in, maar niet allemaal, en een pijplijn die daarop struikelt geeft zelden een duidelijke foutmelding over de oorzaak.

De gegevens, op één plek

Kenmerken en herkomst van het formaat NDJSON.
Extensie.ndjson, .jsonl
Mediatypeapplication/x-ndjson
Voor het eerst gepubliceerd2013