팀에서 Elasticsearch로 구현된 부분에 이런 문의가 들어왔다,
/documents/common 을 검색했는데, /documents/suzie/common도 검색됐어요!
코드를 보니 Match Query가 and option으로 설정되어 있었다.
그럼.. 어떤 검색 쿼리를 써야 적당한 걸까?!
검색 방법을 정하기 위해서는 우선 Elasticsearch가 어떻게 저장되는지 알아야한다!
Elasticsearch는 저장하는 행위를 Indexing 한다고 하는데, 이건 저장하면서 (Inverted) Index를 생성하기 때문이다!
* 뭐가 달라??
기본적으로 RDBMS는 like 검색을 위해 데이터를 순차 검색 -> 속도 느림
ES는 데이터를 저장할 때 Inverted Index를 생성(색인) -> 빠른 검색 가능
아니 근데, 무슨 기준으로 text를 indexing 하는건데?!
텍스트를 Indexing하는 과정에서 Analyzer가 텍스트 분석을 하게된다.
입력된 원본의 텍스트를 분석에 필요한 형태로 변환(전처리)
입력 데이터를 설정된 기준에 따라 검색어 토큰으로 분리하는 역할
분리된 토큰들에 다시 필터를 적용해서 실제로 검색에 쓰이는 검색어들로 최종 변환하는 역할
어간 추출, 형태소 분석
그럼 이제 드디어 무슨 쿼리를 사용하면 되는지!!! 알아보자
ES는 저장할 때 들어온 Text를 Token으로 분리하고, 이를 Term에 대한 Document ID를 저장하는 구조라고 했었다.
그래서 Term Query는말 그대로 색인된 Term이 일치하는 것을 찾는 Query이다!!
ex) ES 저장 Text : '여러개의 물건들'
-> 색인된 Term : '여러', '개', '물건', '물건들'
이 때 Term Query로 검색할 수 있는 Term은 '여러', '개', '물건', '물건들'만 되는 것이다!
* ES에서 선언 가능한 문자열 타입
- text: Analyzer를 통해 Tokenize된 Term을 저장
- keyword: 입력된 문자열을 하나의 Token으로 저장(= text타입에 keyword analyzer 적용한 것과 같음)
ㄴ 주로 정렬, 필터링에 사용
ES Query 종류를 알아보고자 검색하다보면 아래 문장을 계속 마주치게 된다.
Match query 는 Term query와 달리 Analyzer를 거쳐 검색된다
아! 그러니까 Match 쿼리는 검색어도 Analyze해서 검색하는거구나?!
Match Query(and) + 순서가 일치해야 함
ㄴ 따라서 일치하는 문장을 찾을 때 주로 사용
Match Phrase Query + 마지막 단어 접두사로 취급해 부분 일치 검색 허용
도대체 이게 무슨말이냐고...?! -> 마지막 단어 자동 완성 느낌이라고 생각하면 될 것 같다!
하나의 쿼리로 여러 필드를 검색할 수 있게!(필드 별 가중치 줄 수 있음)
/documents/common 을 검색했는데, /documents/suzie/common도 검색됐어요!
기존 코드를 수정하는 것이기 때문에 검색 query만 바뀌길 원했다.
Match Query(And)-> Match Phrase Prefix Query로 변경하면 path 의 순서가 꼬이는 것을 방지하고 사용자가 like 과 비슷하게 기대하던 검색을 할 수 있을 것이라고 생각했다.
그런데 es에서 확인하고 프로젝트에 적용하니, 이러한 에러를 만났다 ㅜㅜ
[match_phrase_prefix] query does not support [zero_terms_query]
stackoverflow 에서 찾은 이유는 es client 버전과 es 버전이 맞지 않는 이유라고 했다.(match_phrase_prefix가 zero_terms_query를 지원하는 건 es 7.10 이후부터 가능하다고 한다.)
그래서 대안으로 Multi Match Query에 필드를 하나만 넣게 설정하고, phrase_prefix 옵션으로 설정해서 사용했다.
찾아보면서 Path Hierachy등 맞춤 옵션을 많이 찾았지만, 기존 사용하던 부분은 다른 검색에 전체적으로 사용되었던 모듈이기 때문에, 공통적으로 match_phrase_prefix로 변경하는 것이 더 낫겠다고 판단했다.
그럼 like 검색을 Elasticsearch에서는 어떻게 하면 될까?
like 검색!!을 하고 싶다면 field를 keyword로 저장하고 wildcard로 검색하는 방법이 있을 것이다.
하지만 이 방법은 Elasticsearch의 Indexing 장점을 활용하지 못하기 때문에 데이터가 많을 경우 지양하는 게 좋을 것이댜.
문장, 혹은 특수문자로 연결된 텍스트라면 match phrase prefix가 대안이 될 수 있다.
하지만 상황에 따라 적절하지 않은 케이스도 많을 것이기 때문에, 세밀한 검색은 field 별로 analyzer 설정을 해야할 것이다:)
https://esbook.kimjmin.net/06-text-analysis
https://findstar.pe.kr/2018/01/19/understanding-query-on-elasticsearch/
https://discuss.elastic.co/t/difference-between-analyzer-and-normalizer/205897/2
https://stackoverflow.com/questions/71839329/how-to-remove-zero-terms-query-in-match-phrase-prefix-in-elasticsearch-from-quer
오호.. 자세한 정리 감사합니다