본문 바로가기

DevOps/Elastic Stack

[Elasticsearch] 성능 개선을 위한 코드 비교 및 분석 - 컴도리돌이

728x90

작심삼주 오블완 챌린지

오늘 블로그 완료! 21일 동안 매일 블로그에 글 쓰고 글력을 키워보세요.

www.tistory.com


Elasticsearch로 데이터 검색 속도를 높이는 일은 단순히 쿼리 작성만의 문제가 아니었어요. 때로는 작은 설정 하나하나  코드 스타일이 성능 차이를 만들기도 합니다.

불필요한 필드 설정 피하기

먼저, 많은 분들이 텍스트 데이터를 다룰 때 대부분의 필드를 text로 지정하는 실수를 합니다. 🤔 텍스트 필드가 많으면 리소스를 불필요하게 잡아먹습니다. 아래처럼 너무 많은 필드를 text로 설정하면 검색 속도가 느려질 수밖에 없어요. 

// 잘못된 인덱스 설정 예시
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "content": { "type": "text" },
      "author": { "type": "text" },
      "date": { "type": "text" },
      // ... 여러 필드를 text 타입으로 지정
    }
  }
}

 
이렇게 되면 Elasticsearch는 모든 필드를 full-text 분석해야 해서 검색에 불필요한 시간이 소요됩니다. 이를 개선하려면, author 같은 고유 키는 keyword 타입으로 지정하고, 날짜 데이터는 date 타입으로 설정하는 게 좋겠죠.

// 개선된 인덱스 설정
{
  "mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "standard" },
      "content": { "type": "text", "analyzer": "english" },
      "author": { "type": "keyword" },
      "date": { "type": "date" }
    }
  }
}

 
이렇게 설정하면 필드별로 최적화된 타입과 분석기를 사용하므로, 검색 속도와 메모리 사용이 대폭 개선될 것이에요. 


쿼리 구조 단순화하기

복잡한 쿼리 구조가 항상 좋은 성능을 보장하는 것은 아니겠죠? 때로는 단순화된 쿼리가 더 빠르고 효율적이에요. 아래와 같이 여러 must 절과 복잡한 bool 쿼리를 사용하는 대신, 쿼리를 간소화해 보았어요.

// 비효율적인 쿼리
GET /my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "elasticsearch" } },
        { "match": { "content": "tutorial" } },
        { "range": { "date": { "gte": "2023-01-01" } } }
      ],
      "filter": {
        "term": { "author": "kim" }
      }
    }
  }
}

 
위와 같은 쿼리는 문서 검색 성능을 떨어뜨릴 수 있어요. 물론 간단해서 성능에 미미하지만, 같은 결과를 낼 수 있는 보다 더 효율적인 쿼리를 작성할 수 있어요.

// 개선된 쿼리
GET /my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "elasticsearch tutorial" } },
        { "range": { "date": { "gte": "2023-01-01" } } }
      ],
      "filter": {
        "term": { "author": "kim" }
      }
    }
  }
}

 
간단하게, title 필드에서 불필요한 텍스트 분할을 줄여 match 쿼리를 합쳤어요. 덕분에 불필요한 연산이 줄어 응답 시간이 이전 코드보다 줄어들겠죠!! 😆


분할 필터 활용하기

Elasticsearch는 반복적인 필터 조건을 캐싱하여 성능을 높일 수 있어요. 자주 사용되는 필터 조건을 filter절에 두면 효과적입니다. 예를 들어, 특정 시간 범위나 범주별 필터링이 반복적으로 사용되는 경우, 이를 필터로 이동해 캐싱하여 검색속도를 높일 수 있죠 

GET /my_index/_search
{
  "query": {
    "bool": {
      "must": { "match": { "content": "search term" } },
      "filter": [
        { "term": { "status": "published" } },
        { "range": { "date": { "gte": "2023-01-01" } } }
      ]
    }
  }
}

스크립트 쿼리 지양하기

스크립트 쿼리는 유연하지만 성능을 저하시킬 수 있습니다. 특히, 필드에 대한 연산이나 복잡한 조건이 필요한 경우, 가급적 스크립트를 피하고 기본 쿼리나 필터로 대체하는 게 좋아요. 

{
  "query": {
    "script": {
      "script": {
        "source": "doc['field1'].value > doc['field2'].value"
      }
    }
  }
}

 
위와 같이 field1 값과 field2 값을 비교해서 field1의 값이 큰 것을 조회하는 쿼리가 있다면, field1와 field2의 차이를 diff_field 컬럼으로 새로 추가해서 아래와 같이 연산하여 사용하는 게 좋습니다. 

{
  "query": {
    "range": {
      "diff_field": {
        "gt": 0
      }
    }
  }
}

[Spring] Elasticsearch에서 스크립팅 언어로 조건 필터링 구현하기(feat. Java) - 컴도리돌이

Elasticsearch에서 데이터 조회 시 특정 조건에 따라 필드 값을 조정하고, 오늘 날짜와 비교해 필터링하는 작업은 종종 필요한 기능입니다. 단순한 필터링 쿼리만으로는 표현하기 어렵거나 우아하

comdolidol-i.tistory.com


doc_values 활성화로 메모리 사용 최적화하기

doc_values는 필드 데이터를 디스크에 저장하여 메모리 사용을 최적화합니다. 숫자형이나 날짜형 필드의 경우, doc_values를 활성화해 두면 검색과 집계 설능이 크게 개선돼요. 기본적으로 활성화되어 있지만, text 필드에서는 비활성화되어 있으니 필요한 필드에서만 사용하시는 게 좋아요. 🙂

{
  "mappings": {
    "properties": {
      "user_id": { "type": "keyword", "doc_values": true },
      "created_at": { "type": "date", "doc_values": true }
    }
  }
}