sy/dev
Paper Review
13 min read

[논문 리뷰] SEISMIC — Learned Sparse Retrieval을 마이크로초 단위로 끌어내리기

SPLADE 같은 Learned Sparse Retrieval은 좋지만 느렸다. 1차 검색에 100ms. SEISMIC은 'Concentration of Importance' 한 가지 관찰에서 출발해 같은 정확도를 0.3ms에 — 100배 이상 빠르게 만든다. SIGIR 2024 best paper 후보로 꼽힌 IR 인덱스 구조.

Efficient Inverted Indexes for Approximate Retrieval over Learned Sparse Representations (SEISMIC)

Sebastian Bruch, Franco Maria Nardini, Cosimo Rulli, Rossano Venturini (2024)- SIGIR 2024

한 줄 요약

SPLADE 같은 Learned Sparse Retrieval(LSR)은 BM25보다 정확하지만 100배 느리다. SEISMIC은 LSR 벡터의 Concentration of Importance 관찰을 이용해 인덱스 구조를 새로 짜고, 같은 정확도를 0.3ms에 달성한다.

배경 — 왜 LSR은 느린가

Dense vs Sparse 그리고 그 사이의 LSR

검색에는 크게 두 갈래가 있다.

  • Dense Retrieval: 텍스트를 768차원 실수 벡터로. 의미 매칭 강함, 해석 어려움. HNSW 같은 ANN 인덱스 필수.
  • Sparse Retrieval: 어휘 차원(약 30K)에서 대부분 0인 벡터. BM25가 대표. 해석 쉬움, vocabulary mismatch 문제.

LSR(Learned Sparse Representation) — 둘의 장점만 가져오려는 시도. SPLADE가 대표적이다.

쿼리 "How to code in python?" → BERT 임베딩을 어휘 공간(30K차원)에 projection → python: 2.4, code: 1.8은 원래 단어, program: 1.2, dev: 0.7 같은 확장 토큰을 모델이 자동 추가.

이게 vocabulary mismatch를 푼다. MS MARCO 기준 SPLADE의 MRR@10은 0.383 — BM25(0.187)의 두 배.

그런데 — 너무 느리다

문제는 검색 속도다. 기존 inverted index + WAND/MaxScore dynamic pruning이 BM25에는 잘 맞지만 LSR에는 안 맞는다.

조건BM25SPLADE
쿼리 토큰 수3–543
문서 토큰 수3–5119
가중치 분포Zipfian (소수 토큰이 압도)차원에 균일

WAND/MaxScore는 (1) 짧은 쿼리, (2) Zipfian 분포, (3) 비음수 가중치 — 이 셋을 가정하는데 LSR이 그중 둘을 깬다. 결과: Pisa(WAND 기반 exact search)로 SPLADE 검색 시 쿼리당 ~100ms. 실시간 RAG에선 재앙.

해결 시도들이 있었다:

  • E-SPLADE처럼 모델을 pruning-friendly하게 학습 → 정확도 손실
  • Graph 기반 ANN 적용 → sparse에 최적화 안 됨

핵심 관찰 — Concentration of Importance

논문의 모든 게 이 한 그림에서 나온다.

LSR 벡터의 중요도 집중 — Top 10 좌표가 전체 L1 norm의 75%를 차지
LSR 벡터에서 상위 좌표 몇 개만으로 전체 에너지의 대부분을 설명할 수 있다. 쿼리는 Top 10이 75%, Top 20이 90%, Top 50이 98%.

LSR 벡터의 119개 non-zero 좌표 중 실제로 중요한 건 극소수다. 정량적으로:

  • 쿼리 벡터: Top 10 좌표가 L1 norm의 75%
  • 문서 벡터: Top 50 좌표가 L1 norm의 75%
qd    qtop-kdtop-m\mathbf{q} \cdot \mathbf{d} \;\approx\; \mathbf{q}_{\text{top-}k} \cdot \mathbf{d}_{\text{top-}m}

논문에서 가장 충격적인 숫자: 쿼리 Top 9개 + 문서 Top 20개만으로 inner product의 85%를 보존. 전체 좌표의 10%로 검색 점수의 85%가 나온다.

α-mass Subvector

이걸 형식화한 게 α-mass subvector다. 벡터의 좌표를 내림차순 정렬했을 때, 상위 좌표의 합이 전체 L1 norm × α를 넘는 최소 부분집합. 파레토 법칙의 IR 버전.

이 정의 하나로 SEISMIC의 세 가지 설계가 모두 정당화된다.

방법론 — 세 가지 설계

┌──────────────────────────────────────────────────────┐
│   ① Static Pruning                                   │
│   ② Geometric Blocking (K-Means)                     │
│   ③ Per-Block Summary Vectors                        │
└──────────────────────────────────────────────────────┘

① Static Pruning — 가중치 낮은 문서는 자른다

각 좌표(coordinate)의 posting list를 가중치 순으로 정렬, 상위 λ개만 유지. 논문 기본값 λ=6,000.

"잘린 문서는 어떡하지?" — Spilling 효과로 자연스럽게 보존된다. 한 문서는 보통 여러 좌표의 posting list에 등장하므로, 좌표 A에서 잘려도 좌표 B에는 살아있다.

② Geometric Blocking — 비슷한 문서끼리 묶기

Pruned posting list 안의 문서들을 β=400개 블록으로 K-Means 클러스터링.

논문이 영리한 점: Shallow K-Means를 쓴다. β개 랜덤 샘플을 대표값으로 잡고, 나머지를 1-pass로 배정. 반복 없이 끝. 빌드 속도 우선.

왜 이렇게 묶나? 다음 단계에서 만들 summary vectortight해진다. 비슷한 벡터끼리 모이면 max를 취해도 너무 부풀려지지 않는다.

③ Summary Vectors — 블록 단위 상한

이게 SEISMIC의 핵심 트릭이다.

각 블록 BB의 summary vector는 좌표별 최대값:

ϕ(B)i=maxxBxi\phi(B)_i = \max_{x \in B} x_i

이 정의에서 자동으로 conservative bound가 따라온다:

qϕ(B)    qx,xB\mathbf{q} \cdot \phi(B) \;\geq\; \mathbf{q} \cdot \mathbf{x}, \quad \forall \mathbf{x} \in B

즉, summary와의 내적이 threshold보다 낮으면 블록 전체를 안전하게 skip 가능. 놓칠 위험 없음.

Forward Index — 정밀 계산용

Inverted index 외에 Forward Index를 따로 둔다. 후보로 살아남은 문서의 정확한 벡터를 빠르게 조회하기 위해. float16(16-bit) 저장으로 메모리 절반 + 정확도 손실 무시 수준.

요약하면:

  • Inverted index = "어느 블록을 볼지" 결정 (pruning + blocking + summary)
  • Forward index = "선택된 블록의 문서를 정확히 채점"

Per-block 추가 최적화

  • α-mass Pruning: summary vector도 α-mass로만 압축 (α=0.4가 최적)
  • 8-bit 양자화: summary 좌표를 1바이트로. 메모리 4× 절감

검색 — 4단계 파이프라인

1. 쿼리 정렬 + Truncation       ← cut=5~20개 좌표만 유지
2. Inverted List 탐색            ← 그 좌표들의 posting block 순회
3. Summary 평가 → 블록 skip     ← summary inner product < threshold면 건너뜀
4. Forward Index 정밀 채점       ← 살아남은 블록만 정확한 inner product

튜닝 노브 두 개로 정확도-속도 자유 조절:

  • cut: 쿼리에서 몇 개 좌표를 쓸지
  • heap_factor: skip threshold의 여유 폭

RAG 상황에 따라 "빠르고 약간 부정확하게""정확하고 약간 느리게" 선택 가능.

실험 — 아예 다른 차원으로 빨라진다

SEISMIC vs 베이스라인의 정확도-지연시간 트레이드오프
SPLADE on MS MARCO. x축 정확도, y축 지연시간(μs). SEISMIC이 모든 정확도 구간에서 압도적으로 낮다. 95% 정확도 기준 — Pisa 100,000μs vs SEISMIC 303μs (331×).

95% Recall 기준 비교

방법LatencySEISMIC 대비
Pisa (brute-force exact)100,000μs331× 느림
Ioqp (JASS 기반)31,843μs105×
SparseIvf10,254μs34×
GrassRMA (graph, BigANN 우승)1,271μs4.2×
PyAnn (graph)1,016μs3.4×
SEISMIC303μs
⚠️

**단위가 마이크로초(μs)**다. 밀리초 아님. 303μs = 0.3ms. RAG 파이프라인에서 retrieval이 embedding 생성보다 빠르다.

정확도 97%로 올라가면 격차가 더 벌어진다. Graph 기반은 2,000μs 가까이 치솟는데 SEISMIC은 531μs.

빌드 시간 + 인덱스 크기

성능만 빠르고 빌드가 느리면 운영 불가. 그쪽도 좋다:

방법빌드 시간인덱스 크기
GrassRMA267분10.5GB
PyAnn137분
SEISMIC5분6.4GB

Rust 구현 + 64-core 병렬. 5분 빌드는 CI/CD에 넣을 수 있는 수준이다. "새 문서 100만 건 추가됐어요" → 5분 후 검색 가능.

직접 실험 — Apple Silicon에서 재현

논문 결과를 신뢰하더라도 우리 환경에서 안 돌면 의미 없다. 직접 돌려봤다.

환경: Apple Silicon Mac, Python 3.11 + Rust nightly로 빌드한 pyseismic-lsr. 8.8M 문서에 SPLADE 임베딩, MS MARCO Dev 쿼리 6,980개.

설정LatencyRecallMRR@10
cut=5, heap=0.823μs95.4%0.377
cut=10, heap=0.960μs97.8%0.380
cut=40, heap=1.02,175μs99.9%0.381

논문 표 기준값(303μs @ 95%) 대비 13배 빠름 — Apple Silicon의 멀티코어 병렬화 덕분으로 추정. 그리고 MRR@10 0.377 vs Exact SPLADE 0.383 — 1.6% 손실로 13× 빠르다는 의미.

SEISMIC vs 다양한 베이스라인 비교
다양한 베이스라인과의 직접 비교. 정확도가 같은 조건에서 SEISMIC이 일관되게 빠르고, 정확도가 올라갈수록 격차가 커진다.

한계와 비판적 검토

저자들이 명시한 한계:

  1. Static index — 동적 삽입/삭제 미지원. 블록 수를 β로 고정하기 때문에 문서가 계속 추가되면 블록이 커지며 효율 저하. 다만 5분 재빌드라 주기적 빌드도 충분히 운영 가능.
  2. Single-vector sparse 모델 한정 — ColBERT 같은 multi-vector late interaction엔 직접 적용 불가. SPLADE/uniCOIL/E-SPLADE는 OK.
  3. 파라미터 튜닝 — λ, β, α, cut, heap_factor 등 노브가 많다. 다만 MS MARCO 기준 grid search 결과를 제공.

내가 추가로 신경 쓰는 점:

  • 메모리 vs 정확도: forward index가 정확도를 살리지만 인덱스 크기가 커진다(6.4GB). 작은 머신/edge에선 부담.
  • Geometric blocking의 K-Means 의존성: shallow K-Means라도 분포가 매우 비대칭이면 cluster quality가 떨어질 수 있음. 도메인별 검증 필요.
  • 빌드 후 분포 변화: production 시 쿼리 분포가 학습 분포와 달라지면 cut/heap_factor를 다시 튜닝해야 할 수 있음.

우리 RAG 팀에 주는 시사점

1. "Sparse는 느리니까 못 써" 핑계 종료 — 0.3ms면 어떤 RAG에도 부담 없음.
2. Hybrid 파이프라인 sparse쪽 교체 — Dense + Sparse 조합에서 sparse를 SEISMIC으로.
3. 빠른 인덱스 갱신 — 5분 빌드는 신선도 관리에 결정적.
4. 디버깅 투명성 — sparse 벡터는 어떤 단어가 매칭됐는지 보인다. dense는 안 보인다. 장애 분석에 결정적 차이.

다음 편 예고

같은 RAG 영역에서 retrieval 효율성은 SEISMIC이 풀었다. 그럼 평가는? 다음 편은 사내 지식에 특화된 RAG 벤치마크 — EnterpriseRAG-Bench.

다음 편: EnterpriseRAG-Bench 리뷰

참고 자료

Comments