버즈니 이승학 서비스엔지니어링 팀장

 

▲ 이승학 버즈니 서비스엔지니어링 팀장

[컴퓨터월드] 많은 애플리케이션들은 서비스 사용성과 품질을 보장하기 위해 상당부분 ‘검색’ 기술에 의존하고 있다. 하지만 검색은 다양한 기술의 융·복합체로 쉽게 접근하기 어렵고 여러 가지 어려운 배경 지식을 필요로 한다.

이런 검색 기술의 접근성을 높이고 구현을 용이하게 해주는 솔루션들로는 아파치 루씬(Apache Lucene) 라이브러리에서 파생된 아파치 솔라(Apache Solr), 엘라스틱서치(Elasticsearch)등이 있다. 엘라스틱서치의 필수 구성 요소들을 통해 검색 엔진에 대한 이해도를 높이고 서비스로서의 활용 가능성과 효용 가치를 공유하고자 강좌(6회)를 신설했다. <편집자 주>

1. 엘라스틱서치 파이썬 클라이언트를 이용한 ‘검색’ 입문 (2018.9)
2. 엘라스틱서치로 검색엔진 전환하기 (이번호)
3. 엘라스틱서치 활용(1): 자동완성
4. 엘라스틱서치 활용(2): 로그 시스템
5. 엘라스틱서치 단계별 최적화
6. 검색엔진 관리 자동화


지난 글을 통해서 엘라스틱서치를 이용해 검색을 쉽고 빠르게 통해 입문하게 됐다. 이번 글을 통해서 기존에 검색엔진을 구축하고 운영하는 독자들을 위해 손쉽고 부담 없이 엘라스틱서치로 전환할 수 있는 포인트를 제시해보려 한다.

엘라스틱서치는 쉽고 빠르지만, 기존에 RDB나 다른 NoSQL제품을 기반으로 검색엔진을 구축하고 있다면 많은 양의 데이터를 이전하고 기존에 제공하던 검색 기능을 그대로 동일하게 제공하는 것은 녹록지 않다.

기존의 검색엔진에서 사용하던 데이터를 이전하는 것은 지난 글에서 다룬 bulk API를 통해서 손쉽게 수행할 수 있다. 하지만 검색 기능을 그대로 이전하는 것은 질의 구조나 지원하는 질의 기능을 제대로 파악하지 않으면 원하는 결과를 얻기 힘들다.

엘라스틱서치는 Query DSL이라는 전용 질의 언어를 제공한다. 이를 사용해 기존에 사용하던 검색 기능을 확보하고, 나아가 더 나은 성능과 기능으로서 제시 될 수 있는 부분을 확인 해보도록 하자.


# Hello, Query DSL!
Query DSL의 Context는 Query와 Filter로 나누거나 혼합하여 구성할 수 있다. Query는 검색하고자 하는 키워드와의 일치성이나 유사성을 스코어로 투영시키기 위한 수단으로 사용된다. 반면 Filter는 특정 영역을 검색하고자 하거나, 검색 키워드의 대상 영역을 한정시키는 역할을 한다.

▲ Query DSL의 구조

Query와 Filter의 사용은 각 영역별로 서로 다른 질의를 사용하지 않고 공통의 질의들을 할 수 있다. 엘라스틱서치는 이러한 공통의 질의에 대해 다양한 형태로 지원하고 있으며 질의들의 종류로는 Fulltext, Term, Compound, Joining, Geo, Specialized, Span등이 있다. 본 글을 통해서 주로 사용되는 Term, Fulltext, Compound에 관련된 질의에 대해서 짚어보겠다. 데이터는 지난 글에서 사용한 주소록 예제를 이용한다.


# 찾고 싶은것을 좁혀 보자: Term level queries
Term 질의들은 명확한 범위나 전제 등의 조건을 투영시키기 용이하기 때문에 앞서 언급한 Filter context를 확보하는 데에 주로 사용된다. Term 질의들은 매우 다양한 방식을 제공하고 있다. 본 글에서는 그 중 term, terms, range, prefix, wildcard, type 질의를 사용해보도록 하자.

term 질의는 형태소 분석기에 따라 분리된 토큰 단위를 기준으로 완벽히 일치하는 내용을 검색 결과로 제공한다. term과 terms는 단일영역이거나 다중영역을 투영 시키는 정도의 차이를 갖고 있다. terms를 사용시에는 배열 형식으로 값을 전달해야 해주면 된다.

▲ 소속 회사명 ‘buzzni’ 검색 결과
▲ 소속 회사명 ‘buzzni’ 또는 ‘fossiel’ 검색 결과

range는 수치 기반의 값의 범위에 해당하는 결과를 제공한다. 범위를 표현하는 방식은 4가지로 지원되며, gte(Greater-than or equal to), gt(Greater-than), lte(Less-than or equal to), lt(Less-than) 등의 부등호 처리 방식을 택하고 있다. 날짜나 시간의 범위를 제한하거나 나이제한 같은 단순한 부분을 처리할 때 유용하게 사용된다.

▲ 35세 이상 검색 결과

형태소 분석을 사용하지 않는 term 질의 기반에서 접두어나 임의 문자를 사용해야 하는 경우, prefix 와 wildcard 질의를 사용하면 된다. 일부 유효한 예상 검색 결과에 대한 사전정보를 갖고 있는 경우가 이에 해당한다. 한 글자 또는 다수의 글자로 시작되거나 사이 글자로 접근하는 경우에 활용이 가능하다. 또한 wildcard는 ‘*’, ‘?’ 사용에 따라 글자 수를 조정이 가능하다.

▲ 이름이 ‘l’로 시작해서 ‘e’ 로 끝나는 단어 검색 결과

# 찾고 싶은 것을 순서대로: Full text queries
Term 질의들로 검색의 범위를 설정 했다면 형태소 분석기를 기반으로 동작하는 Full text 질의를 사용해 순위를 부여한 검색 결과를 만들어 보자. 검색 대상 문서와 검색 키워드간의 유사성 분석을 통해 점수로 나타내고 원하는 결과에 근접한 순서로 제공할 수 있도록 도와준다.

match 질의는 형태소 분석을 거친 검색 대상 문서와 검색 키워드 간에 일치하는 부분이 있는 경우 검색결과로 제공한다. operator를 통해 and나 or 로직의 일치 방식을 선택하거나, 형태소 분석기를 지정할 수 있도록 analyzer 옵션을 사용할 수 있다. 또한 불필요한 롱테일 성격의 검색 결과를 예방할 수 있도록 minimum_should_match를 통해 최소 일치 범위를 설정하는 것도 가능하다.

▲ 이름에 일부가 ‘lee’와 유사한 조건으로 검색 결과

일부 영역에 대해 일치하는 검색결과가 아닌 구문 전체가 일치해야 검색이 가능하도록 하기 위해서는 match_phrase 질의를 사용하면 된다. 다만 모든 검색 키워드에 대해 띄어쓰기를 포함해 정확한 위치를 요청해야 검색 결과로 도출되는 까다로운 질의다. 동일한 단어 구성이지만 단어의 위치가 도치된 형태에 대해서는 slop 옵션을 통해 완전 일치의 허용 정도를 조절 할 수 있다.

▲ 단어의 위치가 도치된 검색 키워드가 유사 조건에 부합하는 경우 검색 결과

match 질의는 단일 필드만을 대상으로 검색을 지원하기 때문에, 다중 필드를 검색 대상으로 사용하려면 multi_match 활용해야 한다. multi_match는 기본적으로 best_fields, most_fields, cross_fields, phrase, phrase_prefix 타입을 지원한다. 다중 필드를 대상으로 하기 때문에 검색 정책에 따라 필요한 타입을 선택해야 한다.

▲ 이름과 회사명을 대상으로 ‘seunghak’ 단어에 대한 유사 조건에 부합하는 검색 결과


# 최선을 위한 조합: Compound queries
Compund 질의들은 검색을 위한 다양한 질의를 모으고 모아서 공통 목적을 가진 질의 형태로 만드는 것을 지원한다. Constant Score, Bool, Dis Max, Function Score, Boosting 등이 이에 해당된다. 필수는 아니지만 검색 성능을 끌어올리는 데 유용하다. 그 중에 가장 보편적이고 많이 쓰이는 Bool 질의를 사용해보도록 하자.

Bool 질의는 must, filter, should, must_not으로 구성되며, filter의 경우 앞서 사용했던 Filter Context의 역할을 해주는 영역이다. 각 영역은 이름에서 주는 의미 그대로 직관적으로 인지하면 된다. must는 영역 내에서 해당되는 조건들을 모두 만족해야 함을, must_not는 must와 반대로 절대로 사용하지 않을 조건을, should는 부분 조건에 만족하는 경우를 정의 한다.

▲ 성별에 필터를 적용하고, 이름으로 유사 조건에 부합하는 검색 결과

필터 조건은 특정한 영역에 한정하는 경우를 제외하고는 느슨하게 처리 할 수밖에 없기 때문에 형태소 분석이 전제가 되는 질의를 적절히 사용해야 한다. 특히 검색결과에 점수를 나열하여 유사성이 높은 순서로 검색결과가 투영돼야 하는 경우 필터만으로는 목적성을 흐리기 쉽다.

▲ 성별 필터와 연령 제외를 적용하고, 이름이 유사 조건으로 스코어로 표현한 검색 결과


# 마치며
query DSL은 엘라스틱서치의 ‘꽃’이라 할 수 있다. 찾고자 하는 것을 잘 찾아주는 것이 검색의 궁극적인 목적이라면, 이것이 가능하도록 해주는 것이 바로 엘라스틱서치가 query DSL에게 부여한 역할이다.

query DSL은 엘라스틱서치 검색기능의 모든 것을 담고 있다. 때문에 query DSL에 대해 잘 알고 있는 것은 새로운 검색엔진을 만들 때도, 기존에 구축된 검색엔진을 엘라스틱서치로 전환하기 위해서도 가장 중요한 내용이다.

기존에 다른 검색 엔진에서 주로 사용하던 기능이나 부족했던 기능에 대해 query DSL을 통해 직접 구현 해보기를 권한다. 엘라스틱서치는 시스템 측면의 엔진 구축에 소요되는 리소스가 매우 작기 때문에 검색 기능의 본연에 더 많은 시간을 할애 할 수 있을 것이고, 궁극적으로 검색 성능 자체에 변화를 가져다 줄 것이다.

저작권자 © 컴퓨터월드 무단전재 및 재배포 금지