tech · 2026-03-22

ElasticSearch

#elasticsearch#bm25

1. 개요

요약: Elasticsearch는 실시간 데이터 검색과 대규모 데이터 분석을 위해 설계된 강력한 분산 검색 엔진으로, 다양한 데이터 유형과 분산 아키텍처를 지원하여 비즈니스 전반에 걸쳐 폭넓게 활용될 수 있음. 뛰어난 확장성, 다양한 쿼리 옵션, RESTful API 지원을 통해 다양한 시스템과 손쉽게 통합될 수 있으며, Python과 같은 언어를 통해 프로그래밍 방식으로 제어할 수 있음.

1.1 Elasticsearch 개요

  • Elasticsearch는 오픈 소스 기반의 분산 검색 및 분석 엔진으로, 특히 대용량 데이터의 실시간 검색과 분석을 위한 솔루션으로 널리 사용됨.
  • Lucene 라이브러리를 기반으로 개발되었으며, RESTful API를 통해 다양한 플랫폼과 손쉽게 통합 가능함.
  • Lucene는 클러스터의 복제 및 생성같은 기능이 없는 라이브러리에 해당하고, ElasticSearch는 거기에 샤드와 레플리카의 관리같은 기능이 추가됨.
  • 전문 검색(Full-Text Search) 기능뿐만 아니라, 대규모 데이터의 실시간 검색분산 분석을 지원하여, 빠른 응답성과 유연한 확장성을 제공함.

1.2 Elasticsearch 사용 배경 및 필요성

  • 현대의 데이터는 빠르게 증가하고 있으며, 검색과 분석의 속도가 비즈니스 성과에 직접적인 영향을 미침.
  • 특히, 사용자에게 실시간으로 데이터를 제공해야 하는 서비스나 시스템에서는 대용량의 데이터를 효율적으로 검색할 수 있는 기능이 필수적임.
  • Elasticsearch는 대규모의 비정형 데이터에 대해 빠르고 유연한 검색을 제공하며, 클라우드 환경이나 분산 시스템과의 호환성이 뛰어남.
  • 이러한 이유로 데이터가 지속적으로 축적되고, 빠른 검색 및 분석이 필요한 다양한 비즈니스 도메인에서 Elasticsearch가 활용되고 있음.

1.3 주요 기능과 장점

  1. 빠른 검색 속도

    • Elasticsearch는 인덱싱된 데이터를 기반으로 빠른 검색을 지원함.
    • 검색 속도는 밀리초 단위로 제공되며, 특히 비정형 데이터 검색에서 뛰어난 성능을 보임.
    • BM25 알고리즘을 기반으로, 텍스트 검색 시 높은 정확도와 속도를 보장함.
  2. 분산 아키텍처

    • 데이터의 수평적 확장을 지원하는 분산형 아키텍처를 통해 대규모 데이터 검색에 최적화됨.
    • 데이터는 여러 **샤드(shard)**로 분할되며, 각 샤드는 개별 노드에 분산되어 저장됨. 이를 통해 시스템 부하를 분산하고, 고가용성을 보장함.
    • 샤드 복제를 통해, 단일 장애 지점(Single Point of Failure)을 방지하고, 데이터 안정성을 유지함.
  3. 다양한 데이터 유형 지원

    • Elasticsearch는 텍스트, 숫자, 날짜, 위치 정보, 벡터 등 다양한 데이터 유형을 지원함.
    • 이를 통해 정형 및 비정형 데이터를 모두 다룰 수 있으며, 벡터 검색을 통한 의미론적 검색에도 활용될 수 있음.
  4. 전문(full-text) 검색 지원

    • 텍스트 분석과 처리에 최적화된 전문 검색 기능을 제공하며, 여러 언어에 대한 분석기와 다양한 검색 옵션을 지원함.
    • match, term, range 등 다양한 쿼리 옵션을 통해 사용자는 필요한 조건에 따라 검색을 세밀하게 조정할 수 있음.
    • script_score를 통한 벡터 검색이나 의미론적 검색을 구현할 수 있어, 단순 키워드 검색을 넘어서는 고도화된 검색 기능을 제공함.
  5. RESTful API를 통한 확장성

    • RESTful API를 통해 Elasticsearch의 모든 기능을 호출할 수 있어, 다양한 언어 및 플랫폼과 통합이 용이함.
    • Python, Java, Node.js 등 여러 언어에서 클라이언트 라이브러리를 제공하여, 애플리케이션에 손쉽게 Elasticsearch 기능을 추가할 수 있음.
  6. 대량 데이터 처리 기능

    • bulk와 같은 대량 처리 기능을 통해, 여러 데이터를 한 번에 인덱싱할 수 있어, 대량의 데이터 삽입 시 효율성을 높임.
    • 스크롤(scroll) 및 스캔(scan) 기능을 통해 대규모 검색 결과를 효율적으로 가져올 수 있음.

1.4 Elasticsearch의 활용 분야

  1. 로그 및 메트릭스 분석

    • 대규모 서버 환경에서 생성되는 로그나 메트릭스 데이터를 실시간으로 분석하고, 모니터링하는 데 최적화됨.
    • Kibana와 연동하여 실시간 대시보드 생성 및 시각화가 가능함.
  2. 추천 시스템

    • 사용자 행동 데이터와 Elasticsearch의 벡터 검색 기능을 조합하여, 실시간으로 사용자에게 맞춤형 추천을 제공할 수 있음.
    • 예를 들어, 전자 상거래 플랫폼에서는 사용자가 선호하는 제품을 빠르게 검색하고 추천하는 데 활용됨.
  3. 의미론적 검색

    • 자연어 처리(NLP) 및 벡터 검색을 활용하여 단순 키워드 검색이 아닌 의미론적 유사도 기반 검색이 가능함.
    • 고객 문의, 문서 검색, QA 시스템 등에서 사용자가 원하는 정보를 더 정확하게 제공할 수 있음.
  4. 엔터프라이즈 데이터 검색

    • 회사 내부의 문서, 보고서, 메일 등 다양한 형식의 비정형 데이터를 검색하고, 인사이트를 도출하는 데 활용됨.
    • Elasticsearch는 여러 유형의 데이터를 통합하여 빠르게 검색할 수 있으므로, 기업의 데이터 분석과 검색에 매우 유용함.

2. Elasticsearch 기본 개념

요약: Elasticsearch는 인덱스, 문서, 매핑이라는 개념을 통해 데이터를 구조화하여 저장하고, 이를 샤드와 복제본을 통해 분산 저장함으로써 대규모 데이터 처리와 고가용성을 지원함. 클러스터와 노드로 구성된 분산 구조는 확장성장애 허용성을 높이며, 데이터 모델을 최적화하여 빠른 검색과 안정성을 보장함.

2.1 인덱스(Index), 문서(Document), 매핑(Mapping)

  1. 인덱스 (Index)

    • Elasticsearch에서 데이터를 저장하는 기본 단위로, 데이터베이스에 해당함.
    • 각 인덱스는 **문서(Document)**들의 집합으로 구성되며, 유사한 구조의 데이터를 그룹화하여 저장함.
    • 인덱스는 데이터를 효율적으로 검색하고 관리하기 위해 매핑(Mapping) 설정을 통해 필드 타입을 정의함.
  2. 문서 (Document)

    • 인덱스 내에 저장된 개별 데이터 항목으로, JSON 형식으로 표현됨.
    • 문서는 각 인덱스에 정의된 매핑에 따라 필드필드 타입을 가짐.
    • 각 문서에는 _id로 불리는 고유 식별자가 있어 특정 문서를 쉽게 조회, 수정, 삭제할 수 있음.
  3. 매핑 (Mapping)

    • 인덱스 내의 필드와 데이터 타입을 정의하는 설정.
    • 필드 타입을 text, keyword, integer, date, dense_vector 등으로 정의해 데이터의 저장 방식과 검색 방식을 최적화할 수 있음.
    • 텍스트 분석에 최적화된 전문 검색 필드(text)와 정확한 값 일치에 최적화된 키워드 필드(keyword)를 구분하여 사용 가능.

2.2 샤드(Shard)와 복제본(Replica)의 역할

  1. 샤드 (Shard)

    • Elasticsearch는 데이터를 여러 개의 **샤드(Shard)**로 분할하여 저장하며, 수평적 확장을 가능하게 함.

    • 샤드는 **기본 샤드(Primary Shard)**와 **복제본 샤드(Replica Shard)**로 나뉘며, 기본 샤드는 데이터를 분산하여 저장하고, 복제본 샤드는 데이터를 복제하여 안정성을 확보함.

    • 샤드의 역할:

      • 데이터를 나누어 저장함으로써 병렬 검색 성능을 높임.
      • 데이터가 분산 저장되기 때문에 데이터 손실에 대한 내구성을 확보함.
  2. 복제본 (Replica)

    • 복제본 샤드는 기본 샤드의 사본으로, 클러스터 내 다른 노드에 분산 저장됨.
    • 복제본은 기본 샤드에 문제가 발생했을 때 데이터를 안전하게 유지하고, **장애 허용성(Fault Tolerance)**을 제공.
    • 검색 요청 시 복제본 샤드를 통해 부하 분산이 가능하므로, 검색 성능 향상에 기여함.
    • 복제본 샤드 수는 인덱스 생성 시 설정할 수 있으며, 필요에 따라 복제본 수를 조정하여 안정성과 성능을 최적화할 수 있음.

2.3 Elasticsearch의 데이터 모델

  1. 클러스터 (Cluster)

    • 여러 Elasticsearch 노드들이 모여 하나의 클러스터를 형성하며, 동일한 클러스터 이름을 공유하는 노드들이 함께 작동.
    • 각 노드는 클러스터 내에서 데이터를 분산 처리하여, 하나의 거대한 데이터베이스처럼 기능함.
    • 클러스터는 단일 노드로 구성될 수도 있지만, 여러 노드를 통해 확장성과 안정성을 높일 수 있음.
  2. 노드 (Node)

    • 클러스터 내에서 데이터 저장, 검색 처리, 복제 등의 작업을 수행하는 개별 서버 또는 프로세스.
    • 노드는 기본적으로 마스터 노드, 데이터 노드, 코디네이팅 노드로 역할이 나뉨.
    • 클러스터 내에서 각 노드는 독립적인 기능을 수행하며, 여러 노드가 결합하여 클러스터의 확장성과 성능을 높임.
  3. 필드 (Field)와 데이터 타입

    • 각 문서는 여러 필드로 구성되며, 각 필드는 **매핑(Mapping)**을 통해 데이터 타입이 정의됨.
    • 데이터 타입은 검색 및 정렬 성능에 영향을 미치며, 필요한 데이터 처리 방식에 따라 적절히 지정해야 함.
    • 예를 들어, dense_vector 필드는 벡터 형태의 데이터를 저장하여, 유사도 기반 검색에 사용됨.

3. 데이터 인덱싱과 저장 방식

요약: Elasticsearch는 인덱스 생성과 매핑 설정을 통해 데이터를 효율적으로 저장하고 검색할 수 있도록 함. 인덱싱은 문서를 인덱스에 저장하는 과정으로, 각 필드는 매핑에 정의된 데이터 타입과 설정을 따름. 대량의 데이터를 인덱싱할 때는 bulk와 같은 유틸리티를 사용하여 성능을 최적화할 수 있음.

3.1 인덱스 생성과 매핑 설정

  1. 인덱스 생성:

    • 인덱스는 데이터를 저장하기 위해 반드시 생성해야 하며, 생성 시 매핑 설정을 함께 정의하는 것이 권장됨.

    • 인덱스 생성 시 index 이름을 지정하고, 필요한 경우 body에 매핑 설정을 추가함.

      es.indices.create(
          index="my_index",
          body={
              "settings": {
                  "number_of_shards": 3,
                  "number_of_replicas": 2
              },
              "mappings": {
                  "properties": {
                      "title": {"type": "text"},
                      "publish_date": {"type": "date"},
                      "embedding": {"type": "dense_vector", "dims": 768}
                  }
              }
          }
      )
      
    • 위 예시에서 title, publish_date, embedding 필드를 가진 인덱스를 생성하고 각 필드에 적절한 타입을 지정함.

  2. 매핑 설정:

    • 매핑은 인덱스 내 필드의 데이터 타입을 정의하고, 데이터가 효율적으로 저장 및 검색될 수 있도록 지원함.

    • 주요 데이터 타입:

      • text: 전문(full-text) 검색에 최적화된 필드 타입으로, 분석기를 통해 텍스트를 분해하여 저장함.
      • keyword: 정확한 값 일치를 위한 필드 타입으로, 보통 태그, 카테고리 등 정확히 일치하는 값을 검색할 때 사용.
      • integer, float: 숫자 필드 타입으로, 수치 연산이 필요한 데이터에 사용됨.
      • date: 날짜 필드 타입으로, 시간 필터링과 정렬을 위해 사용됨.
      • dense_vector: 벡터 형태의 데이터를 저장하는 필드 타입으로, 주로 유사도 검색을 위해 사용됨.
    • 각 필드는 analyzer, boost, index 등의 추가 설정을 통해 최적화할 수 있음.

3.2 데이터 인덱싱

  1. 인덱싱의 개념:

    • 인덱싱은 문서를 인덱스에 저장하는 과정으로, 저장된 데이터는 빠른 검색을 위해 인덱스 구조로 구성됨.
    • 각 문서는 매핑에 정의된 필드 타입에 따라 적절히 인덱싱되며, 필요한 경우 분석기를 통해 데이터가 처리됨.
  2. 문서 인덱싱 예시:

    • Python의 elasticsearch 클라이언트를 사용하여 문서를 인덱싱할 수 있음.

      es.index(index="my_index", id=1, body={"title": "Introduction to Elasticsearch", "publish_date": "2023-01-01"})
      
    • 위 예시는 my_index 인덱스에 새로운 문서를 추가하고, 해당 문서의 ID를 1로 설정함.

    • 인덱싱된 문서는 _source 필드를 통해 조회할 수 있음.

  3. 대량 인덱싱 - bulk 사용:

    • 다수의 문서를 인덱싱할 때는 bulk 기능을 사용하여 성능을 높일 수 있음.

    • bulk는 여러 개의 문서를 한 번의 요청으로 인덱싱하여, 네트워크 비용을 줄이고 처리 속도를 높임.

      from elasticsearch import helpers
      
      actions = [
          {"_index": "my_index", "_id": i, "_source": {"title": f"Document {i}", "views": i}}
          for i in range(1000)
      ]
      
      helpers.bulk(es, actions)
      
    • 위 예시는 1000개의 문서를 한 번에 my_index에 인덱싱하여 성능을 최적화함.

3.3 인덱싱 시 고려 사항

  1. 필드 타입 최적화:

    • 각 필드의 타입을 적절히 지정하여 검색 성능과 저장 공간을 최적화해야 함.
    • 예를 들어, 키워드 기반 필드는 keyword로 지정하고, 텍스트 분석이 필요한 필드는 text 타입으로 지정함.
  2. 대량 데이터 인덱싱 시 성능 관리:

    • bulk 사용 시 데이터 크기를 적절히 조절하고, 필요에 따라 parallel_bulk를 통해 병렬 인덱싱을 활용함.
    • 인덱싱 중에는 CPU와 메모리 사용량이 급격히 증가할 수 있으므로, 적절한 자원 모니터링이 필요함.
  3. 데이터 일관성:

    • 인덱싱하는 데이터가 설정된 매핑에 맞는지 확인하여, 저장 오류나 데이터 누락이 발생하지 않도록 주의함.
    • dense_vector와 같은 필드는 차원 수를 정확히 지정하고, 저장 시 리스트 형태로 변환하는 것이 중요함.

4. 검색 및 쿼리 작동 방식

요약: Elasticsearch는 다양한 쿼리 옵션을 제공하여 텍스트, 숫자, 날짜 등의 데이터에 대한 세밀한 검색이 가능함. 검색 쿼리로는 match, term, range, bool, script_score 등이 있으며, 각 쿼리는 전문 검색, 정확한 일치, 범위 검색, 복합 조건, 벡터 유사도 검색 등의 용도로 사용됨. 이러한 쿼리를 조합하여 복잡한 검색 요구 사항을 충족할 수 있음.

4.1 모든 문서 검색: match_all 쿼리

  • 개요: match_all은 인덱스 내의 모든 문서를 검색하는 가장 기본적인 쿼리.
  • 특징: 검색 점수와 관계없이 모든 문서를 반환하며, 주로 특정 필터 없이 전체 데이터를 조회할 때 사용됨.

4.2 전문(full-text) 검색: match 쿼리 vs term 쿼리

  1. match 쿼리:

    • 텍스트 필드에 대해 전문(full-text) 검색을 수행하는 쿼리로, 텍스트 분석기를 통해 단어가 분해된 후 검색됨.
    • 일부 단어만 일치해도 결과로 반환될 수 있어, 유연한 검색이 가능함.
    • 예를 들어, content 필드에서 Elasticsearchtutorial 단어가 포함된 문서를 검색하는 데 사용됨.
{
    "query": {
        "match": {
            "content": "Elasticsearch tutorial"
        }
    }
}

  1. term 쿼리:

    • 필드의 값이 정확히 일치하는 문서를 검색하는 쿼리로, 보통 keyword 타입에 사용됨.
    • 분석기를 사용하지 않고, 입력된 값과 일치하는 데이터만 검색되므로 정확한 값 검색에 적합함.
    • 예를 들어, status 필드가 정확히 published인 문서만 검색함.
{
    "query": {
        "term": {
            "status": "published"
        }
    }
}

  1. match vs term 비교:

    • match는 텍스트 분석기를 통해 단어가 분해되어 유연한 검색을 수행함.
    • term은 정확한 값 일치를 찾는 쿼리로, 분석기를 사용하지 않으며, 보통 keyword 타입 필드에 사용됨.

4.3 복합 검색: bool 쿼리

{
    "query": {
        "bool": {
            "must": [
                { "match": { "title": "Elasticsearch" }},
                { "term": { "status": "published" }}
            ],
            "should": [
                { "match": { "content": "search" }}
            ],
            "must_not": [
                { "term": { "category": "deprecated" }}
            ]
        }
    }
}
  • 개요: 여러 조건을 조합하여 논리적 연산을 수행하는 쿼리로, must, should, must_not, filter 조건을 조합하여 복합 검색을 구성함.

  • 구성 요소:

    • must: 조건에 반드시 부합해야 하는 필드.
    • should: 조건에 부합하는 것이 좋지만 필수는 아닌 필드.
    • must_not: 포함되지 말아야 하는 필드.
    • filter: 조건에 부합해야 하지만 점수에는 영향을 주지 않는 필드.
  • bool 쿼리는 복잡한 검색 요구 사항을 처리하는 데 유용하며, 다양한 조합을 통해 정밀한 검색이 가능함.

4.4 범위 검색: range 쿼리

{
    "query": {
        "range": {
            "publish_date": {
                "gte": "2023-01-01",
                "lte": "2023-12-31"
            }
        }
    }
}
  • 개요: 숫자나 날짜 필드에 대해 특정 범위 내의 값을 검색하는 쿼리로, gt, gte, lt, lte 조건을 사용하여 범위를 지정함.
  • 용도: 특정 기간 동안 생성된 문서를 찾거나 특정 가격 범위 내의 상품을 검색하는 데 유용함.

4.5 벡터 유사도 검색: script_score 쿼리

{
    "query": {
        "script_score": {
            "query": { "match_all": {} },
            "script": {
                "source": "cosineSimilarity(params.query_vector, 'embedding') + 1.0",
                "params": { "query_vector": [0.1, 0.2, 0.3] }
            }
        }
    }
}
  • 개요: 벡터 필드와의 유사도를 계산하여 검색 결과에 반영하는 쿼리로, dense_vector 필드에 대해 유사도 기반 검색을 수행함.
  • 특징: 코사인 유사도와 같은 벡터 간 유사도 계산을 통해, 문서와 쿼리 간의 의미적 유사성을 평가할 수 있음.
  • script_score는 주어진 쿼리 벡터와의 유사도를 계산하여, 유사성이 높은 문서를 점수가 높은 순서로 반환함.

5. Elasticsearch Response 구조 및 주요 항목

Elasticsearch의 response 객체는 쿼리에 대한 검색 결과를 포함하며, 검색된 문서 목록과 각 문서의 점수, 샤드 정보 등을 확인할 수 있음. 이를 통해 검색된 문서의 세부 정보뿐 아니라, 검색 성능과 관련된 지표도 함께 제공받아 분석이 가능함.

5.1 Response의 기본 구조

  • response는 검색 쿼리의 결과를 담고 있으며, hitsaggregations (옵션) 섹션으로 나뉘어 있음
  • hits 섹션은 검색된 문서 목록과 메타데이터를 포함하며, aggregations는 집계 결과를 포함함 (필요 시 사용)
  • response의 주요 항목을 통해 검색 성능과 결과를 모니터링할 수 있음
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "company_policies",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "title": "Remote Work Policy",
          "department": "Human Resources",
          "publish_date": "2021-03-01",
          "content": "The remote work policy allows employees to work from home under specific conditions..."
        }
      }
    ]
  }
}

5.2 주요 항목 설명

  • took: 쿼리를 처리하는 데 걸린 시간 (ms)

    • 검색 성능을 모니터링하는 데 유용한 지표
    • ex) 2ms가 걸렸다면 "took": 2
  • timed_out: 쿼리가 시간 초과 되었는지 여부 (false이면 시간 초과 없음)

    • 검색 시간이 길어질 때 참고할 수 있는 지표
    • ex) "timed_out": false
  • _shards: 쿼리에 사용된 샤드 정보

    • total: 총 샤드 수
    • successful: 성공한 샤드 수
    • failed: 실패한 샤드 수
    • 분산 검색 상태 및 샤드의 성공 여부를 모니터링할 수 있음
  • hits: 검색 결과와 관련된 정보가 포함된 주요 섹션

    • total: 검색된 전체 문서 수를 나타냄

      • value: 검색된 문서 개수
      • relation: eq는 정확한 값, gte는 최소값을 나타냄
    • max_score: 검색된 문서 중 가장 높은 점수

      • 검색된 문서의 최고 관련성 점수 확인 가능
    • hits: 검색된 각 문서에 대한 정보 리스트

      • _index: 문서가 속한 인덱스명
      • _id: 문서 ID
      • _score: 검색된 문서의 점수 (관련성)
      • _source: 실제 문서 데이터 (필드 값 포함)

5.3 Response의 hits 접근 및 예시 코드

  • hits 섹션에 접근하여 검색된 문서의 세부 정보를 확인할 수 있음
  • response_source 키를 통해 각 문서의 실제 내용을 추출하는 방식으로 활용 가능
# hits에서 _source만 추출하여 출력
for hit in response['hits']['hits']:
    print(hit['_source'])

6. Python 통합 및 elasticsearch-py 라이브러리 사용

요약: Python의 elasticsearch-py 라이브러리는 Elasticsearch와의 상호작용을 위한 클라이언트를 제공하여, Python 환경에서 데이터 인덱싱, 검색, 대량 작업 등을 효율적으로 수행할 수 있도록 도움. 또한 helpers 모듈을 통해 bulk, scan, reindex 등의 유틸리티 기능으로 대규모 데이터를 효율적으로 다룰 수 있음.

6.1 elasticsearch 기본 사용법

  1. 설치:

    • elasticsearch-py 라이브러리는 Python 환경에서 Elasticsearch와 상호작용할 수 있는 클라이언트를 제공.
    • pip install elasticsearch 명령어로 설치할 수 있음.
  2. 기본 설정:

    • Elasticsearch 클라이언트를 설정하고 서버와의 연결을 생성함.

      from elasticsearch import Elasticsearch
      
      # 로컬 서버에서 Elasticsearch 클라이언트 연결 설정
      es = Elasticsearch("<http://localhost:9200>")
      
  3. 문서 인덱싱:

    • 인덱스에 문서를 추가하는 작업을 간단히 수행할 수 있음.

      es.index(index="my_index", id=1, body={"title": "Elasticsearch Basics", "views": 100})
      
  4. 문서 검색:

    • search 메서드를 통해 다양한 쿼리를 사용해 데이터를 검색할 수 있음.

      response = es.search(index="my_index", body={"query": {"match": {"title": "Elasticsearch"}}})
      for hit in response['hits']['hits']:
          print(hit['_source'])
      

6.2 helpers 모듈: 대량 작업을 위한 유틸리티

6.2.1 bulk: 대량 데이터 인덱싱

  • 다수의 문서를 한 번의 요청으로 인덱싱하여 성능을 최적화함.

    from elasticsearch import helpers
    
    actions = [
        {"_index": "my_index", "_id": i, "_source": {"title": f"Document {i}", "views": i}}
        for i in range(1000)
    ]
    
    helpers.bulk(es, actions)
    
  • bulk 함수를 사용하여 1000개의 문서를 한 번에 인덱싱하여 네트워크 비용을 절감하고 성능을 높임.

6.2.2 scan: 대량 검색 결과 처리

  • 대량의 검색 결과를 처리할 때 scan 함수는 검색 결과를 스크롤 방식으로 가져와 메모리 사용량을 줄이고 효율적으로 데이터를 다룸.

    from elasticsearch import helpers
    
    results = helpers.scan(
        es,
        index="my_index",
        query={"query": {"match_all": {}}}
    )
    
    for doc in results:
        print(doc["_source"])
    
  • scan 함수는 모든 문서를 한 번에 가져오는 대신 스크롤을 통해 일정량씩 가져와 메모리 부담을 줄임.

6.2.3 reindex: 인덱스 복사 및 데이터 마이그레이션

  • 기존 인덱스의 데이터를 새로운 인덱스로 복사하는 작업을 쉽게 수행할 수 있음.

    from elasticsearch import helpers
    
    helpers.reindex(
        es,
        source_index="old_index",
        target_index="new_index"
    )
    
  • reindex 함수는 데이터를 이동하거나 인덱스를 변경해야 할 때 유용하며, 데이터 마이그레이션에 효과적임.

6.2.4 parallel_bulk: 병렬 대량 인덱싱

  • 대량의 데이터를 병렬로 인덱싱하여 성능을 최적화함.

    actions = (
        {"_index": "my_index", "_id": i, "_source": {"title": f"Document {i}", "views": i}}
        for i in range(1000)
    )
    
    for success, info in helpers.parallel_bulk(es, actions):
        if not success:
            print("Failed:", info)
    
  • parallel_bulk는 여러 스레드로 작업을 나누어 대규모 데이터를 병렬 처리하며, 대량 인덱싱 시 속도를 극대화.


7. 효율적 사용을 위한 고려사항

요약: Elasticsearch의 성능과 안정성을 극대화하기 위해, 인덱스 매핑 설정, 샤드와 복제본 구성, 대량 인덱싱 시 최적화 방법 등 다양한 옵션을 고려해야 함. 이러한 설정들은 데이터 검색 및 저장 효율성에 직접적인 영향을 미치므로, 데이터를 효율적으로 관리하기 위해 적절한 구성과 사용법이 필요함.

7.1 인덱스 매핑 최적화

  1. 필드 타입 설정:

    • 데이터에 맞는 필드 타입을 지정하여 검색 성능을 최적화해야 함.
    • 예를 들어, 전문 검색이 필요한 필드는 text 타입, 정확한 일치 검색이 필요한 필드는 keyword 타입을 사용함.
    • 숫자 필드는 integer, float 등을 지정하여 정확도와 성능을 높일 수 있음.
  2. 필드 분석기 설정:

    • text 필드에 사용할 분석기를 설정하여 텍스트를 효과적으로 분해하고 검색 성능을 개선할 수 있음.
    • 기본 영어 분석기나 사용자 정의 분석기를 통해 불용어 제거, 어간 추출 등의 텍스트 처리를 자동화할 수 있음.
  3. 필드 인덱싱 제어:

    • 불필요한 필드는 index: false로 설정하여 인덱싱하지 않음으로써 저장 공간과 성능을 최적화함.
    • 예를 들어, 자주 검색되지 않는 메타데이터 필드의 경우 인덱싱을 비활성화하여 효율성을 높임.

7.2 샤드 및 복제본 관리

  1. 샤드 수 설정:

    • 샤드 수는 인덱스 생성 시 결정되며, 데이터 크기에 맞춰 샤드 수를 설정해야 함.
    • 너무 많은 샤드는 관리 비용을 증가시키고, 너무 적은 샤드는 성능을 저하시키므로, 최적의 샤드 수를 설정하는 것이 중요함.
  2. 복제본 수 설정:

    • 복제본 수를 적절히 설정하여 데이터 안정성과 검색 성능을 보장함.
    • 기본적으로 복제본은 1개 이상 설정하는 것이 좋으며, 복제본 수가 많을수록 검색 성능이 향상되지만 저장 공간이 추가로 필요함.
  3. 샤드 리밸런싱:

    • 클러스터의 모든 노드가 고르게 부하를 분산받을 수 있도록 샤드 리밸런싱 설정을 검토함.
    • 데이터 양이 불균형해지면 성능이 저하될 수 있으므로, 자동 리밸런싱 옵션을 활성화하는 것이 좋음.

7.3 대량 데이터 인덱싱 시 최적화 방법

  1. bulkparallel_bulk 사용:

    • 대량 인덱싱 시 bulk 또는 parallel_bulk를 사용하여 여러 문서를 한 번에 인덱싱함으로써 네트워크 비용과 처리 시간을 줄임.
    • 데이터 크기가 클수록 parallel_bulk를 활용하여 병렬 처리를 통해 속도를 높일 수 있음.
  2. 일괄 처리 크기 조정:

    • bulk 요청의 데이터 크기를 적절히 조정하여 클러스터에 부하가 가지 않도록 함.
    • 너무 큰 일괄 처리 요청은 메모리 부족을 초래할 수 있으므로, 클러스터의 리소스에 맞춰 적절히 분할해야 함.
  3. 인덱싱 중 리프레시 간격 조정:

    • 대량 인덱싱 시 refresh_interval을 조정하여, 인덱싱 작업 중 불필요한 리프레시를 줄여 성능을 개선할 수 있음.
    • 예를 들어, refresh_interval-1로 설정하여 인덱싱 완료 후 한 번에 리프레시하는 방식으로 효율을 높일 수 있음.

7.4 쿼리 최적화

  1. 필터링 사용:

    • 점수가 필요 없는 단순한 필터링 조건은 filter를 사용하여 성능을 높일 수 있음.
    • bool 쿼리에서 filter 절을 사용하면 점수 계산이 생략되어 검색 속도가 향상됨.
  2. 정렬 및 페이징 최적화:

    • 정렬이 필요한 필드는 사전에 매핑에서 keyword나 숫자 필드로 설정하여 빠른 정렬이 가능하도록 최적화함.
    • 대량 데이터를 페이징하는 경우 search_after를 사용하여 성능 저하 없이 페이지를 넘길 수 있음.
  3. 스크립트 사용 최소화:

    • script_scorescript를 통한 계산은 계산 비용이 높으므로 필요한 경우에만 사용하고, 최대한 간결하게 작성함.
    • 필요시 스크립트를 사전 컴파일하여 성능 저하를 줄임.

8. Elasticsearch 보안 설정

요약: Elasticsearch는 기본적으로 보안 설정이 비활성화된 상태로 설치됨. 실무 환경에서는 보안을 강화하기 위해 인증 및 권한 부여, TLS 암호화 설정을 적용하는 것이 필요하며, Elastic Stack 보안 기능을 통해 데이터 접근을 제한하고 안전성을 높일 수 있음.

8.1 보안 설정의 필요성

  1. 기본 보안 경고:

    • Elasticsearch는 기본 설치 시 보안 기능이 비활성화된 상태로 제공되며, 이러한 상태로 사용 시 외부로부터의 접근이 가능해짐.
    • 보안이 비활성화된 상태에서는 누구나 클러스터와 데이터에 접근할 수 있기 때문에, 민감한 데이터가 유출될 위험이 존재함.
  2. 실제 서비스에서의 보안 강화 필요성:

    • 서비스 환경에서는 민감한 데이터 보호와 무단 접근을 방지하기 위해 보안 설정이 필수적임.
    • 보안 설정을 통해 허가되지 않은 접근을 차단하고, 클러스터를 보호할 수 있음.

8.2 인증 및 권한 설정

  1. 기본 사용자 및 역할 생성:

    • Elasticsearch는 기본 보안 설정으로 관리자 계정과 사용자 계정을 생성하여 각기 다른 접근 권한을 설정할 수 있음.
    • Elastic Stack 보안 기능에서 제공하는 사용자 및 역할 기반의 권한 제어를 통해 접근을 세부적으로 관리 가능함.
  2. 사용자 인증 및 역할 기반 접근 제어 (RBAC):

    • 역할 기반 접근 제어를 통해 각 사용자에게 인덱스 접근 권한, 읽기/쓰기 권한, 클러스터 관리 권한을 부여할 수 있음.
    • 사용자와 역할을 정의하여 민감한 인덱스나 시스템에 대한 접근을 제한함으로써 보안성을 높일 수 있음.
  3. API 키 생성:

    • 특정 API 사용을 위해 인증된 사용자의 권한을 API 호출에 부여할 수 있도록 API 키를 생성하여 사용함.
    • API 키는 세션을 유지하지 않고도 인증을 위한 간편한 방법을 제공하며, 외부 애플리케이션과의 통합 시 유용함.

8.3 TLS 암호화 설정

  1. TLS 설정을 통한 데이터 전송 보호:

    • TLS(Transport Layer Security)를 활성화하여 네트워크 상에서 전송되는 데이터를 암호화함으로써 중간자 공격 등의 위협을 방지함.
    • TLS 설정은 클라이언트와 노드 간, 그리고 노드 간의 통신을 보호할 수 있음.
  2. 클러스터 내 노드 간 암호화:

    • 클러스터 내의 각 노드 간 통신에서도 TLS 암호화를 적용하여, 네트워크 내부에서도 데이터 보안성을 유지함.
    • 노드 간 TLS 암호화는 중간자 공격으로부터 클러스터 데이터를 안전하게 보호함.
  3. 인증서 설정 및 관리:

    • TLS 설정 시 인증서를 발급받아 클라이언트와 서버 간의 신뢰 관계를 형성함.
    • 자체 서명 인증서 또는 신뢰할 수 있는 인증 기관(CA)에서 발급한 인증서를 사용해 인증서를 관리할 수 있음.

8.4 감사 로그 활성화

  1. 감사 로그의 필요성:

    • Elasticsearch의 보안 설정을 통한 접근 제어와 암호화 외에도, 클러스터 내에서 발생하는 주요 작업을 기록하는 감사 로그 기능이 필요함.
    • 감사 로그를 통해 비정상적인 접근이나 권한 변경 등의 보안 이벤트를 기록하고 추적할 수 있음.
  2. 로그 기록 항목 설정:

    • 감사 로그를 통해 생성할 이벤트의 종류, 사용자, 역할 등의 필터를 설정할 수 있음.
    • 예를 들어, 로그인 시도, 데이터 접근, 설정 변경 등의 주요 이벤트를 기록할 수 있음.
  3. 감사 로그의 모니터링과 분석:

    • 기록된 감사 로그는 주기적으로 모니터링하여 비정상적이거나 의심스러운 활동이 있는지 확인함.
    • Elasticsearch와 Kibana의 통합을 통해 시각적으로 감사 로그를 모니터링하고 분석할 수 있음.

9. 결론

9.1 Elastic Search 활용

  1. 실시간 검색 및 분석:

    • Elasticsearch는 대규모 데이터에 대해 실시간 검색이 가능하여, 데이터 분석과 실시간 데이터 서비스가 필요한 다양한 비즈니스에서 필수적인 도구로 자리잡고 있음.
    • 예를 들어, 로그 분석, 보안 모니터링, 전자 상거래 사이트의 상품 검색 등에서 폭넓게 사용될 수 있음.
  2. 유연한 데이터 구조:

    • 다양한 데이터 타입을 지원하며, JSON 기반의 유연한 데이터 구조를 제공하여 비정형 데이터에도 강점을 가짐.
    • 이러한 유연성 덕분에 비정형 데이터를 다루는 시스템, 특히 텍스트 분석 및 의미론적 검색 기능을 필요로 하는 시스템에 적합함.
  3. 확장성과 안정성:

    • 분산형 아키텍처를 통해 데이터가 증가하더라도 시스템을 수평적으로 확장할 수 있어, 클러스터 성능 저하 없이 데이터를 관리할 수 있음.
    • 샤드와 복제본 기능을 통해 데이터의 내구성과 장애 허용성이 보장되어, 안정적인 서비스 운영이 가능함.

9.2 Elastic Search 응용

  1. 성능 최적화:

    • 인덱싱 최적화: 데이터 양이 증가함에 따라 효율적인 인덱싱이 필요하며, 대량 데이터 인덱싱 시 bulk와 같은 방법을 활용해 성능을 더욱 개선할 수 있음.
    • 쿼리 성능 개선: 쿼리 최적화를 통해 복잡한 검색 요구 사항을 처리하는 방법을 연구하고, 점수 계산이 필요 없는 필터링 등을 적절히 활용해 쿼리 비용을 최소화할 수 있음.
  2. 데이터 보안 강화:

    • Elastic Stack 보안 기능을 활용하여 사용자가 관리하는 시스템에 맞는 사용자 인증과 권한 부여를 강화하는 방안.
    • 민감 데이터의 전송을 보호하기 위해 TLS 암호화 설정을 더욱 최적화하고, 클러스터 환경에 맞는 보안 정책을 지속적으로 업데이트하여 안전성을 유지해야 함.
  3. 모니터링 및 로깅 개선:

    • Elasticsearch는 클러스터와 노드 상태를 모니터링할 수 있는 도구들을 제공하며, 이를 효과적으로 활용해 리소스 사용량을 실시간으로 파악하는 것이 중요함.
    • Kibana와의 통합을 통해 Elasticsearch 내 주요 이벤트와 감사 로그를 시각화하여, 비정상적인 동작을 신속히 감지하고 대응할 수 있는 시스템을 마련할 수 있음.
  4. 최신 기능 도입 및 테스트:

    • Elasticsearch는 지속적으로 새로운 기능과 성능 향상을 제공하고 있으며, 이를 적극적으로 테스트하고 도입하여 시스템 성능을 향상시킬 수 있음.
    • 예를 들어, 벡터 검색과 AI 기반의 의미론적 검색 기능을 강화하는 최신 기능을 실무에 적용함으로써 검색 품질을 높이고 있음.

10. Appendix: Elasticsearch 인덱스 생성 및 검색 옵션

10.1 인덱스 생성 시 주요 옵션 (Settings 및 Mappings)

10.1.1 인덱스 설정 (settings)

  • number_of_shards: 인덱스의 샤드 개수를 설정함.

    • default: 1
    • 데이터 분할을 통해 검색 성능을 최적화하며, 필요에 따라 늘릴 수 있으나 이후 변경 불가.
    • ex) "number_of_shards": 3
  • number_of_replicas: 각 샤드의 복제본 수를 설정함.

    • default: 1
    • 장애 허용성과 가용성을 높이기 위해 복제본을 설정함. 복제본은 클러스터의 여유 노드에 분산 배치됨.
    • ex) "number_of_replicas": 2
  • refresh_interval: 인덱싱된 문서가 검색 가능해지기까지의 간격을 설정함.

    • default: 1s
    • 인덱싱 성능 향상을 위해 대량 인덱싱 중에는 -1로 설정할 수 있음.
    • ex) "refresh_interval": "30s"
  • index.mapping.total_fields.limit: 허용되는 최대 필드 수를 지정함.

    • default: 1000
    • 필드가 많은 문서에서 필드 수 제한을 늘려야 함.
    • ex) "index.mapping.total_fields.limit": 2000
  • max_result_window: from + size의 최대 값을 지정함.

    • default: 10,000
    • 검색 결과 페이징 시 반환 가능한 최대 문서 수를 제한하여 메모리 사용을 제어함.
    • ex) "max_result_window": 50000
  • index.analysis: 분석기 설정을 통해 사용자 정의 분석기와 필터를 지정함.

    • analyzer: 사용자 정의 분석기 정의

      • ex) "my_custom_analyzer": {"type": "custom", "tokenizer": "whitespace", "filter": ["lowercase", "stop"]}
    • tokenizer: 텍스트를 토큰으로 분할하는 방식을 정의

      • default: standard, whitespace, keyword
      • ex) "tokenizer": {"my_tokenizer": {"type": "standard"}}
    • filter: 분석 시 텍스트를 변환하는 필터를 설정함.

      • ex) "filter": {"my_filter": {"type": "stop", "stopwords": "_english_"}}

10.1.2 매핑 설정 (mappings)

  • properties: 각 필드의 데이터 타입과 속성을 정의함.

    "properties": {
      "title": {"type": "text", "analyzer": "english"},
      "publish_date": {"type": "date"},
      "views": {"type": "integer"}
    }
    
  • 데이터 타입:

    • text: 전문 검색용 텍스트 필드

      • analyzer: 텍스트를 분석하는 방법 설정. 예) "analyzer": "standard"
    • keyword: 정확한 값 일치 검색에 사용

      • ignore_above: 특정 길이 이상의 값은 무시. 예) "ignore_above": 256
    • date: 날짜 필드

      • format: 날짜 형식 지정. 예) "format": "yyyy-MM-dd"
    • dense_vector: 벡터 유사도 계산 필드

      • dims: 벡터 차원 수 지정. 예) "dims": 3
  • dynamic: 매핑되지 않은 필드가 추가될 때 처리 방법 지정

    • "true": 새 필드를 자동으로 추가
    • "false": 새 필드를 무시
    • "strict": 새 필드가 있으면 오류 발생
    • 예: "dynamic": "strict"

10.2 검색 쿼리 시 주요 옵션

검색 시 문서 매칭, 필터링, 범위 조건, 유사도 계산 등의 다양한 옵션을 활용하여 원하는 문서를 검색.

10.2.1 검색 쿼리 옵션 (query)

  • match: 텍스트 필드에서 분석기를 사용하여 키워드와 일치하는 문서를 검색함.

    • operator: "and" 또는 "or"를 지정하여 모든 키워드와 일치하거나 하나의 키워드와 일치하도록 설정.

      "query": {
        "match": {
          "title": {
            "query": "Elasticsearch tutorial",
            "operator": "and"
          }
        }
      }
      
  • term: 키워드 필드에서 정확히 일치하는 값을 검색함.

    "query": {
      "term": {
        "status": "published"
      }
    }
    
  • bool: 다중 조건을 조합하여 복합적인 검색을 수행함.

    • must: 반드시 일치해야 하는 조건

    • should: 일치하면 가산점을 부여하는 조건

    • must_not: 일치하지 않아야 하는 조건

    • filter: 점수 계산 없이 조건에 맞는 문서만 반환

      "query": {
        "bool": {
          "must": [
            {"match": {"title": "Elasticsearch"}},
            {"term": {"status": "active"}}
          ],
          "filter": [
            {"range": {"publish_date": {"gte": "2022-01-01"}}}
          ]
        }
      }
      
  • range: 숫자나 날짜 필드에서 범위를 지정하여 검색함.

    • gte, lte, gt, lt: 크거나 같은, 작거나 같은, 큰, 작은 조건을 설정

      "query": {
        "range": {
          "publish_date": {
            "gte": "2023-01-01",
            "lte": "2023-12-31"
          }
        }
      }
      
  • script_score: 사용자 정의 스크립트를 사용해 점수를 계산하여 검색 순위를 결정함. 주로 벡터 유사도 계산에 사용됨.

    • params: 점수 계산에 필요한 매개변수 전달

      "query": {
        "script_score": {
          "query": {"match_all": {}},
          "script": {
            "source": "cosineSimilarity(params.query_vector, 'embedding') + 1.0",
            "params": {"query_vector": [0.1, 0.2, 0.3]}
          }
        }
      }
      

10.2.2 검색 결과 옵션

  • _source: 반환할 필드를 선택하여 검색 결과의 크기를 줄임.

    • ex) " _source": ["title", "author"]
  • size: 반환할 문서의 개수를 제한함.

    • default: 10
    • ex) "size": 5
  • from: 검색 결과에서 특정 위치부터 결과를 반환함. 페이징에 사용됨.

    • ex) "from": 10, "size": 10
  • sort: 검색 결과를 정렬함. 필드명과 정렬 방향을 지정할 수 있음.

    "sort": [
      {"publish_date": "desc"}
    ]
    
  • highlight: 검색어와 일치하는 부분에 하이라이트 표시를 추가하여 검색 결과에서 강조 표시함.

    "highlight": {
      "fields": {
        "content": {}
      }
    }
    

10.3 기타 설정 옵션

10.3.1 색인 제어 옵션

  • index: 필드의 인덱싱 여부를 설정함.

    • "true": 해당 필드를 인덱싱하여 검색 가능하게 함.
    • "false": 검색에 포함하지 않음.
    • ex) "index": false
  • store: 검색 결과에 필드 값을 포함할지 여부를 설정함.

    • "true": 검색 결과에 필드 값이 포함됨.
    • "false": 필드 값이 포함되지 않음.
    • ex) "store": true

10.3.2 텍스트 필드 분석기 설정 옵션

  • search_analyzer: 검색 시에 사용할 분석기를 지정함.

    • ex) "search_analyzer": "english"
  • search_quote_analyzer: 검색어가 따옴표로 감싸진 경우 사용할 분석기를 지정함.

    • ex) "search_quote_analyzer": "keyword"

10.3.3 필터 및 조건 설정 옵션

  • boost: 특정 필드에 가중치를 부여하여 검색 결과의 순위를 높임.

    • ex) {"match": {"title": {"query": "Elasticsearch", "boost": 2.0}}}
  • ignore_unmapped: 존재하지 않는 필드를 무시함.

    • ex) {"sort": {"nonexistent_field": {"ignore_unmapped": true}}}