DFS Query Then Fetch
검색 정확도(Relevance)를 높이기 위해 사용하는 검색 수행 모드(Search Type) 중 하나이다.
성능을 조금 희생(Round-trip 추가)하는 대신, 분산된 샤드들의 통계를 합산하여 정확한 전역 스코어를 계산하는 방식이다.
1. 배경: 분산 환경에서의 스코어링 문제 (Scoring Bias)
OpenSearch의 기본 랭킹 알고리즘인 BM25는 TF-IDF 개념을 기반으로 동작한다
여기서 중요한 변수가 IDF (Inverse Document Frequency) 이다.
- IDF의 핵심: 전체 문서 중에서 해당 단어가 얼마나 희소한가? (희소할수록 가중치가 높음)
- 문제점: 기본 모드(
Query Then Fetch)에서는 **각 샤드가 자신만의 로컬 통계(Local Term Frequency)만으로 IDF를 계산한다.
시나리오: 데이터 편한 (Data Skew)
- Shard A: 문서 10개 보유. 'Apple'이라는 단어가 1개 문서에만 있음.
- 여기서 'Apple'은 매우 귀한 단어 -> 점수 높음
- Shard B: 문서 1,000개 보유. 'Apple'이 500개 문서에 있음
- 여기서 'Apple'은 흔한 단어 -> 점수 낮음
이 경우, 사용자가 'Apple'을 검색하면 Shard A에 있는 문서가 Shard B의 문서보다 내용이 부실함에도 불구하고,
단지 샤드 내에 데이터가 적다는 이유로 스커어가 뻥튀기되어 상위권에 노출되는 왜곡이 발생할 수 있다.
2. 해결책: DFS (Distributed Frequence Search) Query Then Fetch
이 모드는 검색 쿼리를 수행하기 전에 **사전 단계(Pre-query phase)**를 하나 더 거친다.
동작 3단계
- 1. DFS Phase (사전 조사):
- 코디네이팅 노드(요청을 받은 노드)가 모든 관련 샤드에게 **너네 'Apple'이라는 단어 몇 개나 가지고 있니?**를 물어본다.
- 각 샤드는 문서를 검색하지 안고, 용어 빈도(Term Frequency) 통계만 반환한다.
- 2. Query Phase (점수 계산):
- 코디네이팅 노드가 샤드들의 통계를 취합해 **전역 통계(Global Term Frequency)**를 만든다.
- 이 정확한 전역 통계를 다시 각 샤드에 전달하여 실제 검색을 요청한다.
- 각 샤드는 로컬 통계가 아닌, 전달받은 전역 통계를 기준으로 정확한 BM25 스코어를 계산하여 상위 문서 ID와 점수를 반환한다.
- 3. Fetch Phase (문서 인출):
- 코디네이팅 노드가 점수를 취합해 정렬한 뒤, 실제 문서 내용(
_source)을 각 샤드에서 가져온다.
궁금한 점
어느 정도 데이터가 모이고, 샤드 개수가 몇 개 이상일 떄 DFS Query Then Fetch 를 적용해서 정확도를 높여야 하는가?
결론부터 말하자면, 운영환경의 RAG 시스템에서 DFS Query Then Fetch를 켜는 것은 추천하지 않는다. 느리기 떄문이다.
대신 데이터가 어느 정도 모였을 떄 기본 모드(Query Then Fetch)만으로도 정확도가 충분해지는지에 대한 공학적인 기준점과, RAG 아키텍처에서 이 문제를 해결하는 더 세련된 방법을 제시해보겠다.
1. 기준점: "대수의 법칙"이 적용되는 시점
(1) 샤드 당 문서 수: 최소 10만 건 ~ 수십만 건 이상
BM25 알고리즘(TF-IDF)에서 IDF(희소성) 값이 왜곡되지 않으려면, 각 샤드가 전체 데이터의 축소판(Sample) 역할을 할 수 있을 만큼 충분한 모집단을 가져야 한다
- 위험 구간 : 샤드 당 문서가 수천 건 미만일 떄 (통계적 편향이 심함 -> 검색 품질 들쑥날쑥)
- 안전 구간 : 샤드 당 문서가 수십만 건 이상일 떄 (샤드 간 통꼐 차이가 평균에 수렴함)
(2) 샤드의 개수와 크기: 10GB ~ 30GB 룰
데이터 양에 비해 샤드를 너무 잘게 쪼개는 **오버샤딩(Over-sharding)**이 정확도 하락의 주범이다.
- Bad: 데이터 1GB 인데 샤드 5개 (각 200MB) -> 각 샤드의 통계가 너무 빈약함. 검색 품질 떨어짐
- Good: 데이터 30GB까지는 샤드 1개로 유지 -> 전역 통계 = 로컬 통계이므로 정확도 100%
- Scale-out: 데이터가 30GB ~ 50GB를 넘어가면 그때 샤드를 2개로 늘림. 이때는 데이터가 이미 충분히 많아서 통계적 오차가 미미함.
2. RAG 시스템에서의 특수성 (Keyword vs Vector)
RAG는 보통 **Hybrid Search (키워드 + 벡터)**를 사용한다.
여기서 중요한 점은 DFS Query Then Fetch 이슈는 오직 키워드 검색(BM25)에만 영향을 미친다는 것이다.
- 1. 벡터 검색 (k-NN/HNSW):
- 벡터 간의 '거리나 유사도'를 계산한다
- 통계(IDF)와 무관하므로 샤드가 몇 개든, 데이터가 적든 상관없이 정확하다.
- 2. 키워드 검색(Match Query):
- 문제이다. 하지만 앞서 말했듯 샤드 크기를 적절히 유지하면 해결된다.
3. "DFS Query Then Fetch" 대신 사용하는 현대적 RAG 패턴
훨씬 더 강력하고 표준적인 방법이 있다. 바로 Re-ranking(재순위화) 단계이다.
이 아키텍처를 쓰면 샤드 통계 불일치 문제를 완전히 무시할 수 있다.
- 1. Retrival(검색):
Query Then Fetch로 좀 넉넉하게 가져온다. (예: Top 50 ~ 100)
- 이떄 샤드 통계 오차로 인해 랭킹이 조금 섞여 있어도 상관없다. 중요 문서는 50위 안에는 들어올 것이다.
- 2. Re-ranking (정밀 순위):
- 가져온 50개를 Cross-Encoder 모델(BGE-Reranker, Cohere)에 태워서 정밀하게 다시 점수를 매긴다.
- 이 모델을 실제 문맥(Context)를 보고 점수를 준다.
- 3. Top K:
- 여기서 1등 ~ 5등을 뽑아 LLM에게 넘긴다.