본문 바로가기
IT/Elasticsearch

Elasticsearch / Opensearch 에서 Like 검색하기

by 최고영회 2024. 10. 22.
728x90
반응형
SMALL

 

Opensearch 에서 SQL 의 LIKE 검색과 유사한 기능을 구현하려면

몇가지 접근 방식을 사용할 수 있다.

Opensearch 의 text 와 keyword 필드를 이용해 문자열 부분 검색을 수행 하는 방법과

관련된 설정, 그리고 실제 문제 해결 과정을 정리해 본다.

 

기본 개념 이해하기

OpenSearch에서 LIKE 검색을 구현하려면,

텍스트 필드의 매핑 설정과 쿼리 유형을 이해하는 것이 중요하다.

 

일반적으로 텍스트 필드의 매핑은 두 가지로 나뉜다:

text 타입: 텍스트를 단어 단위로 토큰화하여 저장한다.

검색할 때는 match나 match_phrase 쿼리와 같이 단어 단위로 검색이 이루어진다.

keyword 타입: 텍스트를 토큰화하지 않고 그대로 저장한다.

일반적으로 exact match 검색을 위해 사용되며,

부분 일치 검색을 하려면 wildcard 쿼리를 사용할 수 있다.

 

 

검색 문제

subjectInfo 필드의 매핑 정보는 아래와 같다.

"subjectInfo": {
  "type": "text",
  "fields": {
    "keyword": {
      "type": "keyword",
      "ignore_above": 256
    }
  }
}
 

subjectInfo 라는 필드에 긴 텍스트가 저장되어 있다고 가정해보자.

예를 들어, 다음과 같은 데이터가 있을 수 있다:

"subjectInfo": "select *, 441 from test.privacyInfo limit 50"
 

이 텍스트에서 "privacyInfo"라는 단어를 포함하는 데이터를 찾아 보자.

OpenSearch에서 이를 구현하기 위해 wildcard와 match_phrase 쿼리를 시도해 본다.

 

 

match_phrase 쿼리 사용하기

match_phrase 쿼리는 텍스트에서 정확한 구문을 찾는 데 유용하다.

예를 들어, "test.privacyInfo"라는 구문을 찾기 위해서는 다음과 같은 쿼리를 사용할 수 있다

{ "query": { "match_phrase": { "subjectInfo": "test.privacyInfo" } } }
 
 

하지만, 부분 문자열 "privacyInfo"만을 찾으려 할 때는 이 쿼리가 적합하지 않다.

match_phrase는 완전한 구문을 기준으로 검색하기 때문이다.

부분 문자열 검색이 필요할 경우, wildcard 쿼리나 ngram tokenizer를 사용하는 것이 더 적합하다.

 

 

wildcard 쿼리 사용하기

wildcard 쿼리는 부분 일치 검색을 위해 자주 사용된다.

그러나, subjectInfo 필드가 text와 keyword 타입으로 매핑되어 있을 때 각기 다른 동작을 보인다.

 

[문제 상황]

subjectInfo.keyword 필드를 대상으로 wildcard 쿼리를 사용하면 검색이 잘 되었다

{ "query": { "wildcard": { "subjectInfo.keyword": { "value": "*privacyInfo*" } } } }
 

같은 쿼리를 subjectInfo 필드에 사용하면 검색이 되지 않는다.

{ "query": { "wildcard": { "subjectInfo": { "value": "*privacyInfo*" } } } }
 

 

[원인 분석]

subjectInfo.keyword 필드는 텍스트를 토큰화하지 않고 그대로 저장하므로,

wildcard 쿼리에서 부분 문자열 검색이 가능했다.

subjectInfo 필드는 text 타입으로 설정되어 있어 텍스트가 단어 단위로 분리되기 때문에

wildcard 쿼리로 부분 검색이 불가능했다.

 

 

ignore_above 설정의 영향

keyword 필드에 적용할 수 있는 ignore_above 설정값이 문제 해결에 영향을 준다.

위 매핑정보를 보면 keyword 필드에 256자보다 긴 텍스트는 색인되지 않는다.

 

따라서, 데이터 길이가 256자를 초과하는 경우 subjectInfo.keyword 필드로는 검색할 수 없고, subjectInfo 필드를 사용해야 한다.

 

해결 방법

ignore_above 값보다 긴 데이터도 검색할 수 있도록 하기 위해,

text 필드와 keyword 필드를 모두 고려한 쿼리를 작성할 수 있다:

{ "query": 
  { "bool": 
    { "should": [ 
      { "wildcard": { "subjectInfo.keyword": { "value": "*privacyInfo*" } } }, 
      { "wildcard": { "subjectInfo": { "value": "*privacyInfo*" } } } ] 
    } 
  } 
}
 

이 쿼리는 subjectInfo.keyword와 subjectInfo 중 하나라도 일치하면 결과를 반환하므로,

텍스트의 길이에 관계없이 유연하게 검색할 수 있다.

 

 

성능 고려사항

ignore_above 값을 크게 설정하면 긴 텍스트도 keyword 필드로 검색할 수 있지만,

다음과 같은 성능 문제가 발생할 수 있다:

 

색인 크기 증가: 긴 텍스트가 keyword 필드에 포함되면 인덱스 크기가 커져 디스크 사용량이 증가할 수 있다.

검색 성능 저하: wildcard 쿼리는 전체 텍스트를 비교해야 하므로, 데이터가 많을수록 검색 속도가 느려질 수 있다.

메모리 사용량 증가: 색인 크기와 메모리 사용량이 함께 증가하여 시스템 자원을 많이 소모할 수 있다.

 

해결 방안

데이터의 특성과 검색 패턴에 따라 ignore_above 값을 조정하되, 성능 테스트를 통해 적절한 값을 결정하는 것이 중요하다.

wildcard 쿼리의 성능을 개선하려면 ngram tokenizer를 사용하거나, search_as_you_type 필드를 활용할 수도 있다.

 

 

최종 정리

OpenSearch에서 LIKE 검색과 유사한 기능을 구현하려면, 데이터의 특성에 맞는 쿼리 전략을 선택하는 것이 중요하다. keyword 필드와 text 필드를 적절히 사용하고, ignore_above 설정과 성능 최적화를 고려하여 적절한 검색 방법을 선택해야 한다.

 

[요약]

부분 문자열 검색: wildcard 쿼리와 keyword 필드 조합.

구문 검색: match_phrase와 text 필드 사용.

길이에 관계없는 검색: bool 쿼리로 should 절을 사용하여 keyword와 text 필드를 함께 활용

 

 

 

728x90
반응형
LIST