엘라스틱서치 검색과 쿼리 활용
컨텍스트 유형, 쿼리 종류와 문법, 스코어링과 부스팅 전략
엘라스틱서치 검색과 쿼리 활용
1. 쿼리 컨텍스트와 필터 컨텍스트
- 쿼리 컨텍스트
- 질의에 대한 유사도를 계산해 이를 기준으로 더 정확한 결과를 먼저 보여준다
- 연관성에 따른 스코어 결과를 제공
- 필터 컨텍스트
- 유사도를 계산하지 않고 일치 여부에 따른 결과만을 반환
- “예/아니요”의 결과를 제공
- 스코어 계산을 하지 않아 결과에 대한 업데이트를 수행할 필요가 없기 때문에 캐시를 이용할 수 있다
- 엘라스틱서치는 기본적으로 힙 메모리의 10%를 캐시에 이용하고 있는데, 캐시를 이용한 빠른 검색을 하려면 필터 컨텍스트를 이용해야 한다
2. 쿼리 스트링과 쿼리 DSL
- 퀴리 스트링
- REST API의 URI 주소에 쿼리문을 작성하는 방식으로 실행 가능
1
curl -H "Content-Type: application/x-ndjson" -XGET localhost:9200/kibana_sample_data_ecommerce/_search?q=customer_fullname:Mary
- 쿼리 DSL
- REST API의 요청 본문 안에 JSON 형태로 쿼리를 작성
1 2 3 4 5 6 7 8
curl -H "Content-Type: application/x-ndjson" -XGET localhost:9200/kibana_sample_data_ecommerce/_search { "query" : { "match" : { "customer_full_name" : "Mary" } } }
3. 유사도 스코어
- 쿼리 컨텍스트는 기본적으로 BM25 알고리즘을 이용해 유사도 스코어를 계산
- 유사도 스코어는 질의문과 도큐먼트의 유사도를 표현하는 값으로, 스코어가 높을수록 찾고자 하는 도큐먼트에 가깝다는 사실을 의미
- 검색 시 explain: true를 추가하면 쿼리 내부적인 최적화 방법과 어떤 경로를 통해 검색되었으며 어떤 기준으로 스코어가 계산되었는지 알 수 있다
3-1. 스코어 알고리즘(BM25)
- BM25 알고리즘은 검색, 추천에 많이 사용되는 알고리즘으로 TF(Term Frequency), IDF(Inverse Document Frequency) 개념에 문서 길이를 고려한 알고리즘
- 검색어가 문서에서 얼마나 자주 나타나는지, 검색어가 문서 내에서 중요한 용어인지 등을 판단하는 근거를 제공
3-2. IDF 계산
- 문서 빈도(Document Frequency)는 특정 용어가 ‘전체 도큐먼트’에서 얼마나 자주 등장했는지를 의미하는 지표
- IDF(Inverse Document Frequency)는 문서 빈도의 역수로 전체 문서에서 자주 발생하는 단어일수록 중요하지 않은 단어로 인식하고 가중치를 낮추는 것
3-3. TF 계산
- 용어 빈도(Term Frequency)는 특정 용어가 ‘하나의 도큐먼트’에서 얼마나 많이 등장했는지를 의미하는 지표
- 일반적으로 특정 용어가 도큐먼트에서 많이 반복되었다면 그 용어는 도큐먼트의 주제와 연관되어 있을 확률이 높다
- 최종 스코어는 IDF와 TF 그리고 boost 변수(2.2)를 곱하면 된다
4. 쿼리
4-1. 전문 쿼리와 용어 수준 쿼리
- 전문 쿼리는 전문 검색을 하기 위해 사용되며, 전문 검색을 할 필드는 인덱스 매핑 시 텍스트 타입으로 매핑해야 한다
- match 쿼리, match phrase 쿼리, multi match 쿼리, query string 쿼리
- 용어 수준 쿼리는 정확히 일치하는 용어를 찾기 위해 사용되며, 인덱스 매핑 시 필드를 키워드 타입으로 매핑해야 한다
- 일반적으로 숫자, 날짜, 범주형 데이터를 정확하게 검색할 때 사용
- term 쿼리, terms 쿼리, fuzzy 쿼리
4-2. match 쿼리
- 전문 쿼리의 가장 기본이 되는 쿼리
- 전체 텍스트 중에서 특정 용어나 용어들을 검색할 때 사용
- 전문 쿼리의 경우 검색어도 토큰화된다
- match 쿼리에서 용어들 간의 공백은 OR로 인식한다
4-3. match phrase 쿼리
- match phrase 쿼리는 구(phrase)를 검색할 때 사용
- 검색어에 사용된 용어들이 모두 포함되면서 용어의 순서까지 맞아야 한다
- 검색 시 많은 리소스를 요구하기 때문에 자주 사용하는 것은 좋지 않다
4-4. term 쿼리
- term 쿼리는 용어 수준 쿼리의 대표적 쿼리로 정확한 용어가 있는 경우만 매칭이 된다
- 예를 들어 “Mary Bailey”를 검색하면 토큰화되지 않으며 분석기를 거치지 않았기 때문에 대소문자도 정확히 맞아야 한다
- term 쿼리를 포함한 용어 수준 쿼리는 키워드 타입으로 매핑된 필드를 대상으로 주로 키워드 검색이나 범주형 데이터를 검색하는 용도로 사용
- match 쿼리를 포함한 전문 쿼리는 텍스트 타입으로 매핑된 필드를 대상으로 전문 검색에 사용해야 한다
4-5. terms 쿼리
- 용어 수준 쿼리의 일종이며 여러 용어들을 검색
- 키워드 타입으로 매핑된 필드에서 사용해야 하며, 분석기를 거치지 않았기 때문에 대소문자도 신경써야 한다
4-6. multi match 쿼리
- 검색하고자 하는 용어나 구절이 정확히 어떤 필드에 있는지 모르는 경우 사용
- 여러 개의 필드에서 검색하기 위한 multi match 쿼리는 전문 검색 쿼리의 일종으로, 텍스트 타입으로 매핑된 필드에서 사용
- 1개 이상의 필드에 쿼리를 요청하면 각 필드에서 개별 스코어를 구한 다음 그중 가장 큰 값을 대표 스코어로 구한다
- 대표 스코어 선택 방식은 사용자가 결정할 수 있지만, 특별한 설정을 하지 않으면 기본으로 가장 큰 스코어를 대표 스코어로 사용
- explain 파라미터를 true로 설정하면 개별 필드의 스코어가 어떻게 계산되었는지 알 수 있고 대표 스코어가 어떻게 선정되는지도 알 수 있다
- 검색하려는 필드가 많은 경우에는 필드명에 와일드카드를 사용해 이름이 유사한 복수의 필드를 선택할 수도 있음
- boosting 기법
- 여러 개의 필드 중 특정 필드에 가중치를 두는 방법
- multi match 쿼리에서 자주 사용된다
- 가중치를 부여하고자 하는 특정 필드에 ^ 기호와 숫자를 적어주면 된다
1 2 3 4 5 6 7 8 9 10 11 12
{ "query" : { "multi_match" : { "query" : "mary", "fields" : [ "customer_full_name^2", "customer_first_name", "customer_last_name" ] } } }
4-7. range 쿼리
- 특정 날짜나 숫자의 범위를 지정해 범위 안에 포함된 데이터들을 검색할 때 사용
- 날짜/숫자/IP 타입의 데이터는 범위 쿼리가 가능하지만 문자형, 키워드 타입의 데이터에는 범위 쿼리를 사용할 수 없다
- 검색 범위를 지정하는 파라미터
- gte, gt, lte, lt
날짜/시간 관련 범위 표현식
expression description now 현재 시각(2024-02-29T15:20:33) now+1d 현재 시각 + 1일(2024-02-30T15:20:33) now+1h+30m+10s 현재시각 + 1시간 30분 10초(2024-02-30T16:50:43) 2024-02-29+1M 2024-02-29 + 1달(2024-03-29T00:00:00) - 범위 데이터 타입
- integer_range, float_range, long_range, date_range, ip_range
- 범위 타입은 gte, lt 같은 파라미터를 이용해 범위를 지정해서 인덱싱해야 한다
1 2 3 4 5 6
{ "test_date" : { "gte" : "2024-01-01", "lt" : "2024-02-29" } }
- range 쿼리는 relation이라는 파라미터를 이용해 어떤 범위를 포함할지 결정할 수 있다
relation에 들어갈 수 있는 값들
value description intersects(기본값) 쿼리 범위 값이 도큐먼트의 범위 데이터를 일부라도 포함하기만 하면 된다 contains 도큐먼트의 범위 데이터가 쿼리 범위 값을 모두 포함해야 한다 within 도큐먼트의 범위 데이터가 쿼리 범위 값 내에 전부 속해야 한다
4-8. 논리 쿼리
- 논리 쿼리는 복합 쿼리로 위 쿼리들을 조합할 수 있다
- ‘2024년 2월 29일’에 생성된 로그 중에서 ‘상태가 불량’인 것들을 검색하거나 ‘서울’에서 발생한 데이터이면서 ‘제주도’에서 발생하지 않은 데이터를 검색해야 하는 경우 쿼리 조합이 필요
- 논리 쿼리 타입
- must, must_not, should, filter
- must 타입
- 쿼리를 실행하여 참인 도큐먼트를 찾는다
- must 타입에 복수 개의 쿼리를 실행하면 AND 효과를 얻을 수 있다
1 2 3 4 5 6 7 8
"query" : { "bool" : { "must" : [ { "term" : { "day_of_week" : "Sunday" } }, { "match" : { "customer_full_name" : "mary" } } ] } }
- must_not 타입
- 쿼리를 실행하여 거짓인 도큐먼트를 찾는다.
- 다른 타입과 같이 사용할 경우 도큐먼트에서 제외한다
1 2 3 4 5 6 7 8
"query" { "bool" : { "must" : { "match" : { "customer_first_name" : "mary" } }, "must_not" : { "customer_last_name" : "bailey" } } }
- should 타입
- 단독으로 사용 시 쿼리를 실행하여 참인 도큐먼트를 찾는다 (must타입과 같은 결과)
- 복수 개의 쿼리를 실행하면 OR 연산을 한다
- 다른 타입과 같이 사용할 경우 검색 결과에 영향을 주지 않고 스코어에만 활용된다
- filter 타입
- must와 같은 동작을 하지만 필터 컨텍스트로 동작하기 때문에 유사도 스코어에 영향을 미치지 않는다
- 예/아니요 두 가지 결과만 제공할 뿐 유사도를 고려하지 않는다
4-9. 패턴 검색
- 검색하려는 검색어가 길거나 검색어를 정확히 알지 못하는 경우 대략적인 키워드나 몇 개의 알파벳만 가지고 패턴을 이용해 검색
- 용어 수준 쿼리에 해당하므로 SQL의 LIKE 검색처럼 원문에서 특정 문자열을 검색하는 용도로는 적합하지 않다
- 패턴 검색은 많은 리소스를 사용하기 때문에 권장하지 않지만, 필요할 때 효율적으로 사용
- 와일드카드 쿼리
- * : 공백까지 포함하여 글자 수에 상관없이 모든 문자를 매칭할 수 있다
- ? : 한 문자만 매칭할 수 있다
- 검색하려는 용어의 맨 앞에 *와 ?를 사용하면 속도가 매우 느려지기 때문에 검색어 앞에는 사용하지 않아야 한다
정규식 쿼리
1 2 3 4 5 6 7
{ "query" : { "regexp" : { "customer_first_name.keyword" : "Mar." } } }
This post is licensed under CC BY 4.0 by the author.