본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 6장: Elasticsearch AI 검색 통합
2026년 2월 13일·AI / ML·

6장: Elasticsearch AI 검색 통합

Elasticsearch의 kNN 검색, Inference API, semantic_text 필드, ELSER, Elastic Rerank, 하이브리드 검색(RRF)을 실습과 함께 다룹니다.

12분574자9개 섹션
searchai
공유
ai-search6 / 11
1234567891011
이전5장: 랭킹 모델 — Bi-encoder와 Cross-encoder다음7장: OpenSearch와 기타 검색 엔진

학습 목표

  • Elasticsearch의 kNN(벡터) 검색 구현 방법을 이해합니다.
  • Inference API를 활용한 내장 임베딩 생성을 학습합니다.
  • semantic_text 필드와 ELSER(희소 벡터)의 특징을 파악합니다.
  • RRF를 활용한 하이브리드 검색을 구현합니다.
  • Elastic Rerank를 검색 파이프라인에 통합합니다.

Elasticsearch의 AI 검색 진화

Elasticsearch는 전통적인 전문 검색(full-text search) 엔진에서 AI 검색 플랫폼으로 빠르게 진화하고 있습니다. 버전 8.0에서 kNN 검색이 도입된 이후, 매 릴리스마다 AI 검색 기능이 강화되어 왔습니다.

버전주요 AI 검색 기능
8.0kNN 검색 (dense vector)
8.8RRF(Reciprocal Rank Fusion)
8.11ELSER v2 (희소 벡터)
8.13Inference API, semantic_text 필드
8.14Elastic Rerank (Cross-encoder)
8.15+통합 retriever API

kNN 검색 — 밀집 벡터 검색

Elasticsearch의 kNN(k-Nearest Neighbors) 검색은 HNSW 알고리즘 기반의 벡터 검색을 제공합니다.

인덱스 매핑 설정

knn_index_mapping.json
json
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "nori"
      },
      "content": {
        "type": "text",
        "analyzer": "nori"
      },
      "content_vector": {
        "type": "dense_vector",
        "dims": 1024,
        "index": true,
        "similarity": "cosine"
      },
      "published_date": {
        "type": "date"
      },
      "category": {
        "type": "keyword"
      }
    }
  }
}
Info

한국어 문서에는 nori 분석기를 사용합니다. Elasticsearch에 analysis-nori 플러그인이 설치되어 있어야 합니다. nori 분석기는 한국어 형태소 분석을 수행하여 키워드 검색의 품질을 크게 향상시킵니다.

kNN 검색 쿼리

knn_search_query.json
json
{
  "knn": {
    "field": "content_vector",
    "query_vector": [0.12, -0.34, 0.56, "...1024개의 float 값..."],
    "k": 10,
    "num_candidates": 100
  },
  "_source": ["title", "content", "category"]
}

num_candidates는 HNSW 탐색 시 고려하는 후보 수입니다. 값이 클수록 정확하지만 느려집니다. 일반적으로 k의 5-10배를 설정합니다.

Python 클라이언트를 활용한 인덱싱과 검색

es_knn_search.py
python
from elasticsearch import Elasticsearch
from sentence_transformers import SentenceTransformer
 
es = Elasticsearch("http://localhost:9200")
model = SentenceTransformer("intfloat/multilingual-e5-large")
 
INDEX_NAME = "tech-articles"
 
def index_document(doc_id: str, title: str, content: str, category: str):
    """문서 인덱싱 (벡터 포함)"""
    embedding = model.encode(
        f"passage: {title} {content}",
        normalize_embeddings=True,
    )
 
    es.index(
        index=INDEX_NAME,
        id=doc_id,
        document={
            "title": title,
            "content": content,
            "content_vector": embedding.tolist(),
            "category": category,
        },
    )
 
def knn_search(query: str, k: int = 10, category_filter: str = None):
    """kNN 벡터 검색"""
    query_vector = model.encode(
        f"query: {query}", normalize_embeddings=True
    )
 
    knn_params = {
        "field": "content_vector",
        "query_vector": query_vector.tolist(),
        "k": k,
        "num_candidates": k * 10,
    }
 
    if category_filter:
        knn_params["filter"] = {"term": {"category": category_filter}}
 
    response = es.search(index=INDEX_NAME, knn=knn_params)
    return response["hits"]["hits"]

Inference API와 내장 임베딩

Elasticsearch 8.13부터 도입된 Inference API를 사용하면, 임베딩 생성을 Elasticsearch 내부에서 처리할 수 있습니다. 별도의 임베딩 서비스를 운영할 필요가 없어집니다.

추론 엔드포인트 생성

inference_endpoint.json
json
{
  "service": "elasticsearch",
  "service_settings": {
    "num_allocations": 1,
    "num_threads": 1,
    "model_id": ".multilingual-e5-small"
  }
}
create_inference_endpoint.sh
bash
curl -X PUT "localhost:9200/_inference/text_embedding/my-e5-model" \
  -H "Content-Type: application/json" \
  -d '{
    "service": "elasticsearch",
    "service_settings": {
      "num_allocations": 1,
      "num_threads": 1,
      "model_id": ".multilingual-e5-small"
    }
  }'

semantic_text 필드

semantic_text는 Inference API와 결합되는 특별한 필드 타입입니다. 이 필드에 텍스트를 저장하면 Elasticsearch가 자동으로 임베딩을 생성하고 인덱싱합니다.

semantic_text_mapping.json
json
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "nori"
      },
      "content": {
        "type": "semantic_text",
        "inference_id": "my-e5-model"
      },
      "category": {
        "type": "keyword"
      }
    }
  }
}

semantic_text 필드를 사용하면 문서 인덱싱 시 별도의 임베딩 코드가 필요 없습니다.

index_with_semantic_text.json
json
{
  "title": "벡터 데이터베이스 비교 가이드",
  "content": "Pinecone, Weaviate, Qdrant 등 주요 벡터 데이터베이스의 성능과 특징을 비교합니다.",
  "category": "database"
}

검색도 간단합니다.

semantic_text_search.json
json
{
  "retriever": {
    "standard": {
      "query": {
        "semantic": {
          "field": "content",
          "query": "벡터 저장소 성능 비교"
        }
      }
    }
  }
}
Tip

semantic_text 필드는 임베딩 생성, 청킹, 인덱싱을 모두 자동화합니다. 빠른 프로토타이핑에 매우 유용하지만, 세밀한 청킹 제어가 필요한 경우에는 직접 임베딩을 관리하는 방식이 더 적합합니다.


ELSER — 희소 벡터 검색

**ELSER(Elastic Learned Sparse EncodeR)**는 Elasticsearch 전용의 희소 벡터 모델입니다. 밀집 벡터(dense vector)와 달리, 희소 벡터(sparse vector)는 대부분의 값이 0이고 일부 차원만 활성화됩니다.

밀집 벡터 vs 희소 벡터

밀집 벡터 (1024차원): [0.12, -0.34, 0.56, 0.01, -0.23, ...]
희소 벡터 (30000+차원): {"검색": 2.3, "시스템": 1.8, "벡터": 3.1, "데이터": 0.9, ...}

ELSER의 희소 벡터는 각 차원이 어휘(vocabulary)의 토큰에 대응합니다. 문서에 실제로 등장하지 않는 단어도 의미적으로 관련 있으면 활성화됩니다. 이는 BM25의 어휘 불일치 문제를 해결하면서도, 키워드 검색의 해석 가능성을 유지합니다.

ELSER 설정

elser_inference_endpoint.json
json
{
  "service": "elasticsearch",
  "service_settings": {
    "num_allocations": 1,
    "num_threads": 1,
    "model_id": ".elser_model_2"
  }
}
elser_mapping.json
json
{
  "mappings": {
    "properties": {
      "content": {
        "type": "semantic_text",
        "inference_id": "my-elser-endpoint"
      }
    }
  }
}
Warning

ELSER는 Elasticsearch ML 노드에서 실행되므로 충분한 메모리(최소 4GB)가 필요합니다. 프로덕션 환경에서는 전용 ML 노드를 구성하는 것을 권장합니다.


하이브리드 검색 — RRF 활용

Elasticsearch에서 BM25 키워드 검색과 벡터 검색을 결합하는 하이브리드 검색은 RRF retriever를 사용하여 구현합니다.

hybrid_search_rrf.json
json
{
  "retriever": {
    "rrf": {
      "retrievers": [
        {
          "standard": {
            "query": {
              "match": {
                "content": {
                  "query": "벡터 데이터베이스 성능 최적화",
                  "analyzer": "nori"
                }
              }
            }
          }
        },
        {
          "knn": {
            "field": "content_vector",
            "query_vector": [0.12, -0.34, "..."],
            "k": 50,
            "num_candidates": 200
          }
        }
      ],
      "rank_window_size": 100,
      "rank_constant": 60
    }
  },
  "size": 10
}

semantic_text + BM25 하이브리드

semantic_text 필드를 사용하면 더 간결하게 하이브리드 검색을 구성할 수 있습니다.

hybrid_semantic_text.json
json
{
  "retriever": {
    "rrf": {
      "retrievers": [
        {
          "standard": {
            "query": {
              "match": {
                "title": "벡터 데이터베이스"
              }
            }
          }
        },
        {
          "standard": {
            "query": {
              "semantic": {
                "field": "content",
                "query": "벡터 데이터베이스 성능 비교"
              }
            }
          }
        }
      ],
      "rank_window_size": 100
    }
  }
}

Elastic Rerank 통합

5장에서 소개한 Elastic Rerank를 Elasticsearch 검색 파이프라인에 통합하면, 하이브리드 검색 결과를 Cross-encoder로 정밀 재평가할 수 있습니다.

hybrid_with_rerank.json
json
{
  "retriever": {
    "text_similarity_reranker": {
      "retriever": {
        "rrf": {
          "retrievers": [
            {
              "standard": {
                "query": {
                  "match": {
                    "content": "AI 검색 시스템 아키텍처"
                  }
                }
              }
            },
            {
              "standard": {
                "query": {
                  "semantic": {
                    "field": "content",
                    "query": "AI 검색 시스템 아키텍처"
                  }
                }
              }
            }
          ],
          "rank_window_size": 200
        }
      },
      "field": "content",
      "inference_id": "my-rerank-model",
      "inference_text": "AI 검색 시스템 아키텍처",
      "rank_window_size": 100
    }
  },
  "size": 10
}

이 쿼리는 다음과 같은 3단계 파이프라인을 수행합니다.


Python 클라이언트로 전체 파이프라인 구현

es_full_pipeline.py
python
from elasticsearch import Elasticsearch
 
es = Elasticsearch("http://localhost:9200")
 
def full_hybrid_search(query: str, index: str, k: int = 10):
    """BM25 + 시맨틱 + Rerank 전체 파이프라인"""
    response = es.search(
        index=index,
        body={
            "retriever": {
                "text_similarity_reranker": {
                    "retriever": {
                        "rrf": {
                            "retrievers": [
                                {
                                    "standard": {
                                        "query": {
                                            "match": {
                                                "content": {
                                                    "query": query,
                                                    "analyzer": "nori",
                                                }
                                            }
                                        }
                                    }
                                },
                                {
                                    "standard": {
                                        "query": {
                                            "semantic": {
                                                "field": "content",
                                                "query": query,
                                            }
                                        }
                                    }
                                },
                            ],
                            "rank_window_size": 200,
                        }
                    },
                    "field": "content",
                    "inference_id": "my-rerank-model",
                    "inference_text": query,
                    "rank_window_size": 100,
                }
            },
            "size": k,
        },
    )
 
    return [
        {
            "title": hit["_source"]["title"],
            "score": hit["_score"],
            "content": hit["_source"]["content"][:200],
        }
        for hit in response["hits"]["hits"]
    ]

정리

이번 장에서는 Elasticsearch의 AI 검색 기능을 실습과 함께 살펴보았습니다. kNN 검색으로 밀집 벡터 기반 시맨틱 검색을 구현하고, Inference API와 semantic_text 필드로 임베딩 생성을 자동화하며, ELSER로 희소 벡터 검색을 수행하는 방법을 학습했습니다. RRF를 활용한 하이브리드 검색과 Elastic Rerank를 통합한 3단계 파이프라인도 구현했습니다.

다음 장에서는 Elasticsearch 외의 검색 엔진들을 살펴봅니다. OpenSearch의 신경 검색 플러그인, Algolia NeuralSearch, Meilisearch, Typesense 등을 비교하고, 프로젝트에 맞는 검색 엔진 선택 가이드를 제시하겠습니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#search#ai

관련 글

AI / ML

7장: OpenSearch와 기타 검색 엔진

OpenSearch 신경 검색, 재랭킹 파이프라인과 Algolia, Meilisearch, Typesense 등 주요 검색 엔진의 AI 검색 기능을 비교합니다.

2026년 2월 15일·12분
AI / ML

5장: 랭킹 모델 — Bi-encoder와 Cross-encoder

Bi-encoder와 Cross-encoder의 구조적 차이, Elastic Rerank의 DeBERTa v3 모델, 점수 퓨전(RRF), 학습 랭킹(LTR)을 심층적으로 다룹니다.

2026년 2월 11일·14분
AI / ML

8장: 하이브리드 검색과 리랭킹 파이프라인

BM25와 시맨틱 검색의 결합 전략, RRF/선형 보간, 리랭킹 캐스케이드, 다단계 검색 파이프라인 설계와 성능-품질 트레이드오프를 다룹니다.

2026년 2월 17일·13분
이전 글5장: 랭킹 모델 — Bi-encoder와 Cross-encoder
다음 글7장: OpenSearch와 기타 검색 엔진

댓글

목차

약 12분 남음
  • 학습 목표
  • Elasticsearch의 AI 검색 진화
  • kNN 검색 — 밀집 벡터 검색
    • 인덱스 매핑 설정
    • kNN 검색 쿼리
    • Python 클라이언트를 활용한 인덱싱과 검색
  • Inference API와 내장 임베딩
    • 추론 엔드포인트 생성
    • semantic_text 필드
  • ELSER — 희소 벡터 검색
    • 밀집 벡터 vs 희소 벡터
    • ELSER 설정
  • 하이브리드 검색 — RRF 활용
    • semantic_text + BM25 하이브리드
  • Elastic Rerank 통합
  • Python 클라이언트로 전체 파이프라인 구현
  • 정리