---
title: "러스트용 JSON 쿼리 엔진 제트로, jq 느낌에 컴파일러·VM까지 얹었다"
published: 2026-05-08T23:12:30.000Z
canonical: https://jeff.news/article/2440
---
# 러스트용 JSON 쿼리 엔진 제트로, jq 느낌에 컴파일러·VM까지 얹었다

제트로는 러스트로 만든 JSON 쿼리 언어이자 처리 엔진으로, jq가 하던 필터링·변환·집계를 메서드 체인 스타일 DSL로 풀어낸다. 단순 파서가 아니라 수요 분석, 스트림 퓨전, 바이트코드 VM, 캐시된 실행 계획, NDJSON 스트리밍까지 넣어서 임베디드 데이터 처리 쪽을 꽤 진지하게 겨냥한다.

- 제트로는 러스트로 만든 JSON 쿼리 엔진임. 느낌은 jq인데, 문법은 러스트 개발자가 익숙한 메서드 체인에 더 가까움
  - 예를 들면 `$.orders.filter(status == "paid").map(total).sum()`처럼 JSON 경로를 따라가며 필터링, 매핑, 집계를 이어 붙이는 식임
  - 결과도 스칼라, 배열, 중첩 객체, 계산 필드, 요약 리포트처럼 원하는 모양으로 다시 빚을 수 있음

- 이 프로젝트가 흥미로운 건 “JSON용 작은 DSL”에서 멈추지 않고, 컴파일러와 데이터베이스 플래너 쪽 아이디어를 꽤 많이 가져왔다는 점임
  - 수요 분석으로 실제 필요한 데이터만 보려 하고, 가능한 경우 여러 파이프라인 단계를 하나의 루프로 합치는 스트림 퓨전을 적용함
  - 런타임 쪽은 바이트코드 VM, 캐시된 실행 계획, 캐시된 경로를 써서 반복 실행 비용을 줄이는 구조임
  - 깊은 탐색 쿼리에서는 파싱된 구조 위에 비트맵 인덱스를 만들 수 있는데, 재귀적으로 트리를 걷는 대신 depth와 key 기준 비트 연산으로 후보를 좁히는 방식임

> [!IMPORTANT]
> 제트로가 내세우는 핵심은 “표현력 있는 JSON 쿼리”가 아니라 “임베디드 환경에서 반복 실행해도 버틸 JSON 처리 엔진”에 가까움.

- 대상 사용처도 명확함. 카프카, NATS, 펄사, 플링크, 스파크 같은 스트리밍 파이프라인에서 JSON 메시지를 받아 필터링하고, 모양을 바꾸고, 값을 보강한 뒤 넘기는 작업을 노림
  - 컨슈머마다 오래 살아 있는 `JetroEngine`을 하나 두고, 레코드별로는 실행 비용만 내는 모델을 권장함
  - API 응답 가공, 로그 분석, ETL 변환, 관측성 파이프라인, 감사 이벤트 필터링 같은 곳이 직접적인 타깃임

- NDJSON 지원이 꽤 실전형임. 각 줄을 독립 JSON 문서로 평가하면서도 준비된 쿼리 계획은 스트림 전체에서 재사용함
  - `collect_*` 계열은 `serde_json::Value`를 돌려주고, `run_*` 계열은 결과를 출력 스트림에 바로 씀
  - 첫 N개 결과만 필요한 쿼리는 limit writer가 목표 개수를 채우는 순간 입력 읽기를 멈춤
  - 조건에 맞는 첫 N개 문서를 찾는 match-limited API는 매칭된 원본 NDJSON 라인을 가능하면 그대로 보존해서 재인코딩 비용도 피함

- 문법은 jq 사용자가 기대하는 기본기를 대부분 챙겼음
  - `$`는 루트 문서, `@`는 map/filter/lambda 내부의 현재 아이템을 가리킴
  - null-safe 필드 접근, 배열 인덱스와 슬라이스, 재귀 하강, 정렬, 상위 N개 추출, 그룹화, 인덱싱, count_by 같은 패턴을 지원함
  - `match` 표현식으로 JSON 구조 패턴 매칭도 가능하고, `set`, `delete`, `patch` 같은 문서 변경 작업도 DSL 안에서 처리함

- 벤치마크도 “라이브러리로 임베드했을 때”를 의식한 콜드 스타트 기준을 제시함
  - 입력은 8,000개 레코드, 약 3.9MB JSON이고, 파싱부터 실행, 직렬화까지 end-to-end로 비교함
  - 재현 명령도 `cargo run -p jetro-core --release --example bench_cold` 형태로 공개돼 있음
  - 다만 원문에 구체적인 숫자 표가 같이 들어 있진 않아서, 성능 주장은 직접 돌려보고 판단하는 게 맞음

- 생태계 확장도 이미 염두에 둔 상태임
  - 터미널용 제트로 CLI, 이맥스 플러그인, 파이썬 바인딩, 다트·플러터 바인딩을 언급함
  - 러스트 크레이트는 `jetro = "0.5.8"` 형태로 의존성에 추가해 쓸 수 있음

---

## 기술 맥락

- 제트로의 선택은 “JSON을 그냥 파싱해서 순회하자”가 아니라 “쿼리를 실행 계획으로 다루자”에 가까워요. 같은 조건을 수천, 수만 개 문서에 반복 적용하는 로그·이벤트 처리에서는 DSL 해석 비용보다 계획 재사용이 훨씬 중요해지거든요.

- 스트림 퓨전을 넣은 이유도 중간 결과 때문이에요. `filter -> map -> sum`을 단계별 배열로 만들면 코드가 보기엔 단순해도 대량 NDJSON에서는 메모리와 할당 비용이 바로 튀어요. 제트로는 가능한 경우 이 과정을 한 루프로 접어서 처리량을 챙기려는 쪽이에요.

- 바이트코드 VM은 동적 쿼리와 임베디드 사용 사이의 타협점이에요. 쿼리가 컴파일 타임에 고정돼 있지 않아도, 한 번 준비한 쿼리를 VM에서 반복 실행하면 매 레코드마다 문자열 파싱부터 다시 하는 구조를 피할 수 있어요.

- 비트맵 인덱스는 깊은 JSON 탐색에서 의미가 커요. `$..price` 같은 재귀 하강은 순진하게 구현하면 트리를 계속 걸어야 하는데, 구조 위치를 비트로 압축해두면 특정 depth나 key 후보를 비트 연산으로 빠르게 좁힐 수 있거든요.

## 핵심 포인트

- 메서드 체인 기반 DSL로 JSON 필터링, 정렬, 집계, 재구성, 문서 변경을 처리함
- SIMD 파싱, 수요 분석, 스트림 퓨전, 바이트코드 VM, 비트맵 인덱스로 성능을 끌어올리는 구조임
- NDJSON 스트림에서는 쿼리 계획을 재사용하고 첫 N개 결과를 찾으면 읽기를 멈추는 API를 제공함
- 카프카, NATS, 펄사, 플링크, 스파크 같은 이벤트 파이프라인에서 메시지 단위 변환기로 쓰는 사용 사례를 내세움

## 인사이트

jq는 강력하지만 팀 코드 안에 넣기엔 문법과 런타임 경계가 은근 부담스러운데, 제트로는 그 빈틈을 러스트 임베딩과 스트리밍 처리로 찌르는 프로젝트다. 특히 로그·이벤트·감사 레코드를 JSON으로 흘리는 백엔드라면 그냥 장난감 DSL로 넘기긴 아깝다.
