Skip to main content

OpenSearch 기초

OpenSearch는 문서 검색, 로그 검색, RAG 메타데이터 검색에 자주 사용됩니다. 정확도와 지연시간을 동시에 관리하려면 인덱스 구조를 먼저 이해해야 합니다.

학습 목표

  • 인덱스/매핑/샤드/리플리카 개념을 설명할 수 있습니다.
  • 검색 쿼리에서 점수 기반 검색과 필터 검색을 구분할 수 있습니다.
  • Bool Query를 활용한 복합 검색을 작성할 수 있습니다.
  • 운영 시 재색인과 라이프사이클 정책을 계획할 수 있습니다.

핵심 개념

개념설명RDBMS 비유
인덱스(index)문서를 저장하는 논리 단위테이블
문서(document)JSON 형태의 데이터 단위행(row)
필드(field)문서 내 개별 항목컬럼(column)
매핑(mapping)필드 타입과 분석 규칙 정의스키마
분석기(analyzer)텍스트를 토큰화/정규화-
샤드(shard)분산 저장 단위파티션
리플리카(replica)고가용성과 읽기 성능 보강복제본

인덱스 매핑 정의 예시

매핑은 인덱스 생성 시 필드 타입을 명시적으로 정의하는 것입니다. 매핑을 미리 잡지 않으면 OpenSearch가 자동 추론하는데, 이 결과가 의도와 다를 수 있습니다.
PUT /rag-documents
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "korean_analyzer": {
          "type": "custom",
          "tokenizer": "nori_tokenizer",
          "filter": ["lowercase", "nori_readingform"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title":      { "type": "text", "analyzer": "korean_analyzer" },
      "content":    { "type": "text", "analyzer": "korean_analyzer" },
      "embedding":  { "type": "knn_vector", "dimension": 1536 },
      "project":    { "type": "keyword" },
      "created_at": { "type": "date" },
      "chunk_id":   { "type": "integer" },
      "metadata":   { "type": "object", "enabled": true }
    }
  }
}
text 타입은 분석기를 통해 토큰화되어 전문 검색이 가능합니다. keyword 타입은 정확한 값 매칭(필터)에 사용됩니다. 검색과 필터 용도를 구분하여 타입을 선택하세요.

검색 쿼리 기본

  • must: 점수에 반영되는 필수 조건 (AND)
  • filter: 점수에 반영되지 않는 빠른 필터 (AND, 캐시됨)
  • should: 점수 가중 조건 (OR)
  • must_not: 제외 조건 (NOT)

기본 Bool Query

{
  "query": {
    "bool": {
      "must": [{ "match": { "content": "vector database" } }],
      "filter": [{ "term": { "project": "rag" } }]
    }
  }
}

복합 Bool Query (실무 패턴)

{
  "query": {
    "bool": {
      "must": [
        { "match": { "content": "임베딩 모델 성능 비교" } }
      ],
      "filter": [
        { "term": { "project": "rag-v2" } },
        { "range": { "created_at": { "gte": "2024-01-01" } } }
      ],
      "should": [
        { "match": { "title": "벤치마크" } }
      ],
      "must_not": [
        { "term": { "status": "draft" } }
      ],
      "minimum_should_match": 0
    }
  },
  "size": 10,
  "_source": ["title", "content", "project", "created_at"]
}
filter 절은 점수 계산을 건너뛰고 캐시를 활용하므로 성능이 훨씬 좋습니다. 정확한 값 매칭(프로젝트명, 날짜 범위 등)은 반드시 filter에 넣으세요.

RAG 연동 패턴

RAG(Retrieval-Augmented Generation)에서 OpenSearch는 문서 검색 단계를 담당합니다.
1

문서 색인

원본 문서를 청크로 분할하고, 각 청크에 임베딩 벡터와 메타데이터를 함께 저장합니다.
2

하이브리드 검색

벡터 유사도 검색(kNN)과 키워드 검색(BM25)을 결합하여 후보 문서를 추출합니다.
{
  "query": {
    "bool": {
      "must": [{ "match": { "content": "사용자 질문" } }],
      "filter": [{ "term": { "project": "my-rag" } }]
    }
  },
  "knn": {
    "embedding": {
      "vector": [0.1, 0.2, ...],
      "k": 10
    }
  }
}
3

메타데이터 필터링

문서 유형, 생성 시점, 접근 권한 등 메타데이터로 결과를 추가 필터링합니다.
4

리랭킹 및 LLM 전달

검색 결과를 Cross-Encoder 등으로 리랭킹한 뒤 LLM 프롬프트에 컨텍스트로 전달합니다.

운영 핵심 포인트

  1. 매핑을 먼저 고정하고 인덱싱을 시작합니다.
  2. 인덱스 템플릿으로 필드 정책을 표준화합니다.
  3. 데이터 증가에 맞춰 샤드 수를 조정합니다. (샤드당 10-50GB 권장)
  4. 보관 정책(ILM/ISM)으로 오래된 인덱스를 정리합니다.
  5. 매핑 변경이 필요하면 재색인(Reindex) 전략을 사용합니다.
운영 중 매핑 타입 변경은 불가능합니다. textkeyword로 바꾸려면 새 인덱스를 만들고 재색인해야 합니다. 초기 매핑 설계에 충분한 시간을 투자하세요.
잘못된 타입으로 색인하면 검색 정확도와 집계 결과가 함께 틀어집니다. 운영 중 타입 변경은 대부분 재색인이 필요하므로 초기 설계가 매우 중요합니다. 특히 한국어 검색은 nori_tokenizer 설정을 초기에 잡아야 합니다.
벡터 검색만으로 끝내지 말고 메타데이터 필터(문서 유형, 시점, 권한)를 함께 사용하세요. 검색 품질은 인덱스 구조 + 필터 정책 + 리랭킹 조합으로 개선됩니다. 청크 크기와 오버랩 설정도 검색 품질에 큰 영향을 줍니다.
  1. 쿼리 패턴 변경 확인 → 2) 샤드 불균형 확인 → 3) GC/메모리 압박 확인 → 4) 노드 리소스 포화 확인. _nodes/stats_cat/shards API로 클러스터 상태를 먼저 파악하세요.
OpenSearch의 ISM(Index State Management)을 사용하면 인덱스를 자동으로 관리할 수 있습니다. 예: 30일 후 warm 단계로 이동, 90일 후 삭제. 로그 인덱스처럼 시간 기반 데이터에 필수적인 정책입니다.

체크리스트

  • 매핑/분석기 정책이 문서화되어 있나요?
  • 검색 지표(p95, 실패율, hit quality)를 수집하나요?
  • 재색인 절차와 롤백 전략이 준비되어 있나요?
  • RAG 파이프라인에서 메타데이터 필터를 활용하고 있나요?
  • ISM 정책으로 오래된 인덱스를 자동 정리하고 있나요?

다음 문서