4. 데이터 검색
엘라스틱서치는 인덱스에 저장된 문서를 검색할 수 있도록 다양한 검색 기능을 제공한다. 문서는 색인시 설정한 분석기에 의해 분석 과정을 거쳐 토큰으로 분리되는데, 이러한 분석기는 색인 시점에 사용할 수 있지만 검색 시점에 사용하는 것도 가능하다.
특정 문장이 검색어로 요청되면 분석기를 통해 분석된 토큰의 일치 여부를 판단해서 그 결과에 점수를 매긴다. 이를 기반으로 순서를 적용해 결과를 사용자에게 최종적으로 출력한다.
4.1 검색 API
* 엘라스틱 서치는 색인 시점에 Analyzer를 통해 분석된 텀을 Term, 출현빈도, 문서번호와 같이 역색인 구조로 만들어 내부적으로 저장한다.
검색 시점에는 keyword 타입과 같은 분석이 불가능한 데이터와 Text 타입과 같은 분석이 가능한 데이터를 구분해서 분석이 가능할 경우 분석기를 이용해 분석을 수행한다.
이를 통해 검색 시점에도 텀을 얻을 수 있으며, 해당 텀으로 역색인 구조를 이용해 문서를 찾고 이를 통해 스코어를 계산해서 결과로 제공한다.
이러한 동작 방식을 이해하고 이에 맞춰 목적에 맞게 검색쿼리를 사용해야한다.
4.1.1 검색 질의 표현 방식
엘라스틱서치에서 제공하는 검색 API는 기본적으로 질의(Query)를 기반으로 동작한다. 검색질의에는 검색하고자 하는 각종 조건들을 명시할 수 있으며 두가지 방법이 있다.
- URI 방식
ex.
GET movie_search/_search?q=prdtYear:2018
- Restful API 방식 (Request Body)
ex.
POST /movie_search/_search
{
"query":{
"term":{"prdtYear":"2018"}
}
}
엘라스틱서치가 제공하는 검색 API를 모두 활용하기 위해서는 반드시 Request Body 방식을 사용해야한다.
URI 검색은 검색 조건을 몇 가지만 추가해도 검색식이 복잡해져서 사용하기가 불편하다. 가능한 한 Request Body 방식의 검색을 사용하자. 이는 Query DSL이라 불리는 문법을 사용한다.
4.2 Query DSL 이해하기
{
"size" : [리턴받는 결과의 개수 지정]
"from" : [몇 번째 문서부터 가져올지 지정]
"timeout" : [검색을 요청해서 결과를 받는 데까지 걸리는 시간]
"_source" : {} [검색 시 필요한 필드만 출력하고 싶을 때]
"query" : {} [검색 조건문]
"aggs" : {} [통계 및 집계 데이터 사용할 때 사용]
"sort" : {} [문서 결과를 어떻게 출력할지에 대한 조건을 사용]
}
Query DSL을 이용해 검색 질의를 작성할 때 조금만 조건이 복잡해지더라도 여러 개의 작은 질의를 조합해서 사용해야한다.
두가지 형태로 나눠서 생각해볼 수 있다.
1. 실제 분석기에 의한 전문 분석이 필요한 경우 [쿼리 컨텍스트]
전문 검색 시 사용 ex. "Harry Potter" 같은 문장 분석
- 문서가 쿼리와 얼마나 유사한지를 스코어로 계산한다.
- 질의가 요청될 때마다 엘라스틱서치에서 내부의 루씬을 이용해 계산을 수행한다.
- 일반적으로 전문 검색에 많이 사용한다.
- 캐싱되지 않고 디스크 연산을 수행하기 때문에 상대적으로 느리다.
2. 단순히 YES/NO로 판단할 수 있는 조건 검색 [필터 컨텍스트]
"create_year" 필드의 값이 2018년인지 여부, "status" 필드에 'use' 라는 코드 포함 여부
- 쿼리의 조건과 문서가 일치하는지를 구분한다.
- 별도의 스코어를 계산하지 않고 단순 매칭 여부를 검사한다.
- 자주 사용되는 필터의 결과는 엘라스틱서치가 내부적으로 캐싱한다.
- 기본적으로 메모리 연산을 수행하기 때문에 상대적으로 빠르다.
4.2.3 Query DSL 의 주요 파라미터
1. Multi Index 검색
POST movie_search,movie_auto/_search
{
"query":{
"term":{
"repGenreNm": "다큐멘터리"
}
}
}
검색 요청 시 인덱스 이름을 지정할때 "*"를 와일드카드로 사용할 수 있다.
POST /log-2019-*/_search
페이징
from: 문서의 시작 나타냄
size: 문서의 개수
# 첫번째 페이지 요청
POST movie_search/_search
{
"from" : 0,
"size" : 5,
"query" : {
"term" : {
"repNationNm" : "한국"
}
}
}
# 두번째 페이지 요청
POST movie_search/_search
{
"from" : 5,
"size" : 5,
"qeury" : {
"term" : {
"repNationNm" : "한국"
}
}
}
주의: 설정된 페이지를 제공하기 위해서는 전체를 읽어서 사이즈만큼 필터링해서 제공하는 구조이다.
쿼리 결과 정렬
엘라스틱서치가 기본적으로 계산한 유사도에 의한 스코어 값으로 정렬하는 것이 아니라 필드의 이름이나 가격, 날짜 등을 기준으로 재정렬하고싶은 경우 사용한다.
POST movie_search/_search
{
"query" : {
"term" : {
"repNationNm" : "한국"
}
},
"sort" : {
"prdtYear" : {
"order" : "asc"
}
}
}
검색결과 필드 지정
_source 지정: 원하는 데이터만 출력하고자할 때 사용한다.
POST movie_search/_search
{
"_source" : [
"movieNm"
],
"query" : {
"term" : {
"repNationNm" : "한국"
}
}
}
범위 검색
문법 | 연산자 | 설명 |
lt | < | 피연산자보다 작음 |
gt | > | 피연산자보다 큼 |
lte | <= | 피연산자보다 작거나 같다 |
gte | >= | 피연산자보다 크거나 작다 |
POST movie_search/_search
{
"query":{
"range" : {
"prdtYear" : {
"gte" : "2016",
"lte" : "2017"
}
}
}
}
operator 설정
OR 연산이나 AND 연산의 사용
엘라스틱 서치는 검색 시 문장이 들어올 경우 기본적으로 OR 연산으로 동작한다. 하지만 operator 파라미터에 and 연산자를 명시해주면 and로 동작한다.
POST movie_search/_search
{
"query" : {
"match" : {
"movieNm" : {
"query" : "elastic search" ,
"operator" : "and"
}
}
}
}
operator 파라미터를 생략하면 or 연산으로 동작해서 "elastic" 단어 혹은 "search" 가 모두 들어있는 문서가 검색되지만 and로 명시해줬기 때문에 and가 작동한다.
4.3 Qeury DSL의 주요 쿼리
4.3.1 Match All Query
색인에 모든 문서를 검색하는 쿼리다.
POST movie_search/_search
{
"query" : {
"match_all" : {}
}
}
4.3.2 Match Query
match query는 텍스트, 숫자, 날짜 등이 포함된 문장을 형태소 분석을 통해 텀으로 분리한 후 이 텀들을 이용해 검색 질의를 수행한다.
POST movie_search/_search
{
"query" : {
"match" : {
"movieNm" : "그대 장미"
}
}
}
"그대 장미"라는 검색어를 Match Query로 요청했기 때문에 엘라스틱 서치는 해당 질의를 받으면 검색어에 대해 형태소 분석을 통해 " 그대" "장미" 라는 2개 텀으로 분리한다.operator 필드가 지정돼있지 않기 때문에 OR 연산으로 검색한다.
4.3.3 Multi Match Query
match Query와 기본적인 사용방법은 동일하나 단일 필드가 아닌 여러개의 필드를 대상으로 검색해야 할 때 사용한다.
POST movie_search/_search
{
"query": {
"multi_match" : {
"query" : "가족",
"fields" : ["movieNm","movieEm"]
}
}
}
4.3.3 Term Query
엘라스틱서치는 텍스트 형태에서는 두가지 매핑 유형을 지원한다.
Text 데이터 타입: 필드에 데이터가 저장되기 전에 데이터가 분석되어 역색인 구조로 저장된다.
keyword 데이터 타입: 데이터가 분석되지 않고 그대로 필드에 저장된다.
Term쿼리는 별도 분석작업이 없기 때문에 keyword 데이터 타입을 사용하는 필드를 검색한다. 텀 쿼리는 필드에 텀이 정확히 존재하지 않는 경우 검색이 되지 않기 때문에 주의해야한다.