본문 바로가기
C.W.K.
Stream
Lesson 03 of 08 · published

JSON Lines — 줄당 한 JSON 값

~10 min · json, jsonl, ndjson, streaming

Level 0평문
0 XP0/64 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

스트림, log, ML 데이터셋 포맷

JSON Lines 는, 사람에 따라 NDJSON 이라고도 부르는데 같은 거야, 줄 하나가 각각 독립된 JSON 값인 파일 포맷이야. 감싸는 배열도 없고, 레코드 사이 콤마도 없고, 최상위 구조라는 것도 없어. 확장자는 .jsonl 이나 .ndjson 을 써.

JSON 이 못 푸는 거 푸는 거

  • 스트리밍 — 줄 하나만 덧붙이면 레코드가 하나 추가돼. 평범한 JSON 배열이면 붙일 때마다 닫는 대괄호를 다시 써야 하잖아.
  • 부분 읽기 — 파일 전체를 안 올리고 레코드를 하나씩 처리할 수 있어. 로그 파일이나 큰 데이터셋에서는 이게 결정적이야.
  • 이어 붙이기와 쪼개기가 쉬워cat a.jsonl b.jsonl 이면 합쳐지고, split -l 1000 huge.jsonl 이면 나뉘어. 줄 하나하나가 그 자체로 완결이라 둘 다 그냥 돼.
  • grep 이 먹혀grep error events.jsonl 로 파싱 없이 원하는 줄을 바로 찾아.

JSON Lines 만나는 곳

  • 애플리케이션 log 파일 (papertrail, vector.dev, fluentd).
  • ML 학습 데이터 (HuggingFace 데이터셋, OpenAI fine-tuning, instruction tuning).
  • 데이터베이스 export (MongoDB mongoexport, Firestore export).
  • 라이브 event tail.
원칙: 데이터가 레코드가 줄줄이 이어지는 모양이면 (로그 이벤트, 학습 샘플, 시계열의 행) 최상위 배열 말고 JSONL 을 잡아. 뒤에 붙이는 비용이 거의 없고, 파싱은 한 번에 한 줄이면 되고, 파일이 GB 로 불어나도 파서가 안 무너져.

Code

JSON Lines — 파일 포맷·text
{"timestamp":"2026-05-04T01:30:11Z","level":"info","event":"server.start"}
{"timestamp":"2026-05-04T01:30:12Z","level":"info","event":"db.connected"}
{"timestamp":"2026-05-04T01:30:15Z","level":"warn","event":"slow_query","duration_ms":1240}
{"timestamp":"2026-05-04T01:30:18Z","level":"error","event":"http.5xx","path":"/api/chat"}
레코드 추가 (파싱 불필요)·bash
# Plain shell — 어떤 크기 파일에든 작동
echo '{"event":"deploy.start","timestamp":"2026-05-04T01:30:11Z"}' >> events.jsonl

# 또는 한 번에 여러 개 파이프
for i in 1 2 3; do
  echo "{\"i\":$i}"
done >> events.jsonl
Python 에서 JSON Lines 줄별 읽기·python
import json

# 한 번에 한 레코드 처리 — 전체 파일 절대 안 로드
with open('events.jsonl') as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        record = json.loads(line)
        if record.get('level') == 'error':
            print(record['event'], record.get('path'))
JSON Lines 와 jq·bash
# 에러만 필터
jq -c 'select(.level == "error")' events.jsonl

# 집계 — 단계별 카운트 (스트림 slurp)
jq -s 'group_by(.level) | map({level: .[0].level, count: length})' events.jsonl

# JSON 배열을 JSON Lines 로 변환
jq -c '.[]' big-array.json > records.jsonl

External links

Exercise

손에 닿는 로그를 하나 골라. 애플리케이션 로그든 감사 로그든 Stripe 이벤트든. 그중 한 덩어리를 JSONL 로 옮기고, jq -c 'select(...)' file.jsonl 로 특정 이벤트 하나만 걸러봐. 그 다음 같은 걸 최상위 JSON 배열로 했다고 상상해봐. JSONL 이 스트리밍에서 왜 이기는지 그때 몸으로 알게 돼.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.