RAG 시스템을 위한 DB 구현 방안 및 쿼리 전략 논의

법령 문서를 다루는 하이브리드 RAG 시스템의 성능을 극대화하기 위해, 네 가지 데이터베이스 각각에 대한 구체적인 구현 방안과 쿼리 전략을 상세히 논의합니다.

사용 데이터베이스

용도 데이터베이스 역할
RDB PostgreSQL 구조화 및 메타데이터 관리
Vector DB Milvus 의미 검색 (Dense Retrieval)
전문 검색 Elasticsearch 키워드 검색 (Sparse Retrieval)
Graph DB Neo4j 관계형 맥락 제공

1. PostgreSQL 구현 및 쿼리 전략: 구조화 및 메타데이터 관리

PostgreSQL은 데이터의 정합성(Integrity)과 정확한 메타데이터 관리를 담당합니다.

구현 방안 (Schema)

law_documents 테이블

컬럼 데이터 타입 설명
doc_id (PK) INT / UUID 법령 문서 고유 ID
law_name VARCHAR 법령명 (예: 민법, 형법)
enactment_date DATE 시행일자
is_active BOOLEAN 현재 유효 여부

law_chunks 테이블

컬럼 데이터 타입 설명
chunk_id (PK) UUID 청크 고유 ID
doc_id (FK) INT / UUID 상위 법령 문서 ID
chapter VARCHAR 장(章) 제목/번호
article_num INT 조(條) 번호
paragraph_num INT 항(項) 번호
chunk_text TEXT 분할된 텍스트 내용

쿼리 전략

메타데이터 필터링: Vector DB나 Elasticsearch의 1차 검색 후, 최신 법령 또는 특정 법령 범위로 결과를 제한할 때 사용합니다.

예시 쿼리: 현재 유효한(is_active = TRUE) 민법 조항에서 검색

SELECT *
FROM law_chunks lc
JOIN law_documents ld ON lc.doc_id = ld.doc_id
WHERE ld.law_name = '민법'
  AND ld.is_active = TRUE
  AND lc.chunk_id IN ('검색된_청크_ID_리스트');

2. Milvus 구현 및 쿼리 전략: 의미 검색

Milvus는 질문과 청크 텍스트 간의 의미적 유사성을 기반으로 문서를 검색합니다.

구현 방안 (Collection)

필드 데이터 타입 설명
chunk_id (PK) VARCHAR / String PostgreSQL의 chunk_id와 동일 (Join Key)
embedding FLOAT_VECTOR LLM으로 생성된 텍스트 임베딩 벡터
article_num INT 조(條) 번호 (필터링을 위한 경량 메타데이터)
law_name VARCHAR 법령명 (필터링을 위한 경량 메타데이터)

쿼리 전략

Dense Retrieval (밀집 검색): 사용자의 질문을 임베딩 벡터로 변환하여 벡터 공간에서 가장 가까운 K개의 청크를 검색합니다.

예시 쿼리: 질문 벡터와 가장 유사한 K=10개의 청크 ID 검색

# Milvus Python SDK
from pymilvus import MilvusClient

# 질문을 벡터로 변환
query_vector = embedder.encode(user_question)

# 유사도 검색 수행
results = milvus_client.search(
    collection_name="law_chunks_collection",
    data=[query_vector],
    anns_field="embedding",
    param={"metric_type": "COSINE"},
    limit=10,
    output_fields=['chunk_id', 'law_name']
)

# 결과에서 chunk_id 추출
chunk_ids = [hit.id for hit in results[0]]

3. Elasticsearch 구현 및 쿼리 전략: 키워드 검색

Elasticsearch는 빠른 전문 검색 및 Sparse Retrieval (희소 검색)을 담당합니다.

구현 방안 (Index Mapping)

필드 설정 설명
chunk_id keyword 검색 결과의 조인 키
chunk_text text (korean analyzer) 한국어 분석기 적용된 텍스트
article_num integer 조(條) 번호
law_name keyword 법령명

Index 설정 예시:

{
  "mappings": {
    "properties": {
      "chunk_id": { "type": "keyword" },
      "chunk_text": {
        "type": "text",
        "analyzer": "korean"
      },
      "article_num": { "type": "integer" },
      "law_name": { "type": "keyword" }
    }
  }
}

쿼리 전략

BM25 (Sparse Retrieval): 키워드 일치에 기반하여 관련 문서를 찾습니다.

예시 쿼리 (DSL):

{
  "query": {
    "bool": {
      "must": [
        { "match": { "chunk_text": "특정_법적_용어 OR 관련_키워드" } }
      ],
      "filter": [
        { "term": { "article_num": 35 } }
      ]
    }
  },
  "_source": ["chunk_id", "chunk_text"]
}

Milvus의 결과(Dense)와 Elasticsearch의 결과(Sparse)를 RRF(Reciprocal Rank Fusion) 등의 알고리즘으로 통합하여 최종 랭킹을 산출합니다.

def reciprocal_rank_fusion(dense_results, sparse_results, k=60):
    """RRF 알고리즘으로 두 검색 결과 통합"""
    scores = {}

    for rank, doc_id in enumerate(dense_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)

    for rank, doc_id in enumerate(sparse_results):
        scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)

    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

4. Neo4j 구현 및 쿼리 전략: 관계형 맥락 제공

Neo4j는 법령 간의 구조적 관계를 모델링하고, 검색된 청크에 대한 추가적인 맥락을 제공하여 Re-ranking을 지원합니다.

구현 방안 (Graph Model)

노드 (Nodes)

노드 타입 설명 예시
(:Law) 법령 문서 전체 ‘민법’, ‘형법’
(:Article) 특정 조항 ‘민법 제45조’
(:Concept) 법률 용어/핵심 개념 ‘손해배상’, ‘계약’

엣지 (Relationships)

관계 설명
(A)-[:REFERENCES]->(B) A 조항이 B 조항을 참조함
(LawA)-[:SUPERIOR_TO]->(LawB) LawA가 LawB의 상위 법령임
(Article)-[:CONTAINS_KEYWORD]->(Concept) 조항이 특정 개념을 포함함

쿼리 전략 (Re-ranking 및 맥락 확장)

Neo4j는 1차 검색 결과를 보완하고 순위를 재조정하는 데 사용됩니다.

맥락 탐색 (Cypher 쿼리)

시나리오: 1차 검색된 조항과 직접적으로 참조 관계에 있는 다른 조항들을 K=5개 탐색

// 참조 관계 탐색
MATCH (a:Article {article_num: $searched_article_num})
      -[:REFERENCES]->(ref_article:Article)
RETURN ref_article.article_num, ref_article.law_name
LIMIT 5

상위 법령 탐색

// 상위 법령 관계 탐색
MATCH (law:Law {name: $law_name})
      <-[:SUPERIOR_TO]-(superior:Law)
RETURN superior.name, superior.doc_id

관련 개념으로 확장 검색

// 특정 개념을 포함하는 모든 조항 탐색
MATCH (c:Concept {name: '손해배상'})
      <-[:CONTAINS_KEYWORD]-(article:Article)
RETURN article.article_num, article.law_name
LIMIT 10

Re-ranking 활용

1차 검색된 문서 리스트에 대해:

  1. Neo4j 쿼리를 실행하여 참조되는 횟수나 상위 법령과의 관계 점수를 부여
  2. 이 점수를 최종 랭킹에 반영
  3. LLM에 전달할 문서를 최종 확정

전체 아키텍처 흐름

┌─────────────────────────────────────────────────────────────────┐
│                        사용자 질문                               │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
        ┌───────────────────────┴───────────────────────┐
        │                                               │
        ▼                                               ▼
┌───────────────┐                             ┌───────────────┐
│    Milvus     │                             │ Elasticsearch │
│ (Dense Search)│                             │(Sparse Search)│
└───────────────┘                             └───────────────┘
        │                                               │
        └───────────────────┬───────────────────────────┘
                            │
                            ▼
                ┌───────────────────────┐
                │   Hybrid Fusion (RRF) │
                └───────────────────────┘
                            │
                            ▼
                ┌───────────────────────┐
                │       Neo4j           │
                │   (Re-ranking &       │
                │    Context Expansion) │
                └───────────────────────┘
                            │
                            ▼
                ┌───────────────────────┐
                │     PostgreSQL        │
                │  (Metadata Filter &   │
                │   Original Text)      │
                └───────────────────────┘
                            │
                            ▼
                ┌───────────────────────┐
                │         LLM           │
                │   (Answer Generation) │
                └───────────────────────┘

요약

DB 역할 주요 기능
PostgreSQL 메타데이터 관리 정합성 보장, 필터링, 원본 텍스트 저장
Milvus 의미 검색 벡터 유사도 기반 Dense Retrieval
Elasticsearch 키워드 검색 BM25 기반 Sparse Retrieval
Neo4j 관계 탐색 법령 간 참조 관계, Re-ranking

이러한 하이브리드 접근법을 통해, 법률 QnA 시스템은 키워드, 의미, 그리고 법률 구조라는 세 가지 차원에서 질문에 가장 정확한 답변 근거를 확보할 수 있습니다.