Elasticsearch Query DSL
정확값 쿼리 - Exact Value Query
bool : filter
Elasticsearch는 정확도를 고려하는 풀 텍스트 외에도 검색 조건의 참/거짓 여부만 판별해서 결과를 가져오는 것이 가능하다. 풀 텍스트와 상반되는 이 특성을 정확값이라고 하는데 정확히 일치 하는지 여부 만을 따지는 검색이다.
Exact Value 에는 term, range 와 같은 쿼리들이 속한다.
스코어를 계산하지 않기 때문에 보통 bool 쿼리의 filter 내부에서 사용하게 된다.
테스트 데이터
POST sport_5/_bulk
{"index":{"_id":1}}
{"message":"The quick brown fox"}
{"index":{"_id":2}}
{"message":"The quick brown fox jumps over the lazy dog"}
{"index":{"_id":3}}
{"message":"The quick brown fox jumps over the quick dog"}
{"index":{"_id":4}}
{"message":"Brown fox brown dog"}
{"index":{"_id":5}}
{"message":"Lazy jumping dog"}
명령어
GET sport_5/_search
{
"query" : {
"match": {
"message": "fox"
}
}
}
결과
명령어
GET sport_5/_search
{
"query" : {
"bool" : {
"must": [
{
"match" : {
"message" : "fox"
}
}
],
"filter": [
{
"match":{
"message": "quick"
}
}
]
}
}
}
결과
첫번째 match 쿼리로 fox를 검색했을때는
가장 높은 스코어가 _score : 0.32951736 이다.
첫번째의 검섹에 filter 구문 안에 quick을 추가했는데 가장 높은 스코어는 첫번째 쿼리와 같은 _score : 0.32951736 이다.
filter는 검색에 조건은 추가하지만 스코어에는 영향을 주지 않도록 제어할때 사용한다.
keyword
keyword에 대해서는 문자열과, 공백, 대소문자까지 정확히 일치하는 데이터만을 결과로 리턴한다.
명령어
GET sport_5/_search
{
"query" : {
"bool" : {
"filter": [
{
"match":{
"message.keyword": "The quick brown fox"
}
}
]
}
}
}
결과
keyword 타입으로 저장된 필드는 스코어를 계산하지 않고 정확값의 일치 여부만을 따지기 때문에 스코어가 0.0으로 나오게 된다. 스코어를 계산하지 않기 때문에 keyword 값을 검색 할 때는 filter 구문 안에 넣는다.
역 인덱스 - Inverted Index
ID | Text |
doc1 | the soccer is good |
doc2 | the soccer is very good |
doc3 | the soccer is difficult |
doc4 | the soccer difficult |
doc5 | the baseball |
일반적으로 관계형 DB에서는 위 내용을 보이는 대로 테이블 구조로 저장한다.
위 테이블에서 soccer가 포함된 행들을 가져온다고 하면 text 열을 한 줄 씩 찾아 내려가면서 soccer 가 있으면 가져오고 없으면 넘어가는 식이다.
엘라스틱 서치는 데이터를 저장할 때 역 인덱스라는 구조를 만들어 저장한다.
텀 | ID | 텀 | ID |
the | doc1 doc2 doc3 doc4 doc5 | soccer | doc1 doc2 doc3 doc4 |
is | doc1 doc2 doc3 | very | doc2 |
difficult | doc3 doc4 | baseball | doc5 |
엘라스틱서치에서는 추출된 각 키워드를 텀이라고 부른다.
역 인덱스가 있으면 soccer 를 포함하고 있는 도큐먼트들의 id를 바로 얻어올 수 있다.
엘라스틱서치는 데이터가 늘어나도 역 인덱스가 가리키는 id의 배열값이 추가되는 것뿐이기 때문에 속도의 저하 없이 빠른속도로 검색이 가능하다.
텍스트 분석 - Text Analysis
elasticsearch 에 저장되는 도큐먼트는 모든 문자열 필드 별로 역 인덱스를 생성한다.
elasticsearch에 문자열 필드가 저장될 때 데이터에서 검색어 토큰을 저장하기 위해 여러 단계의 처리 과정을 거친다.
이 전체 과정을 텍스트 분석 이라고 하고 이 과정을 처리하는 기능을 애널라이저라고 한다.
애널라이저는 0~3개 캐릭터 필터와 1개의 토크나이저(Tokenizer) 그리고 0~n 개의 토큰 필터(Token Filter)로 이루어 진다.
텍스트 데이터가 입력되면 가장 먼저 필요에 따라 전체 문장에서 특정 문자를 대치하거나 제거하는데 이 과정을 담당하는 기능이 캐릭터 필터이다.
문장에 속한 단어들을 텀 단위로 하나씩 분리 해 내는 처리 과정을 거치는데 이 과정을 담당하는 기능이 토크나이저이다.
토크나이저는 반드시 1개만 적용이 가능하다.
분리된 텀 들을 하나씩 가공하는 과정을 거치는데 이 과정을 담당하는 기능이 토큰 필터 이다.
토큰 필터는 0개 부터 여러개를 적용할 수 있다.
텀 중에서는 검색어로서의 가치가 없는 단어들이 있는데 이런 단어를 불용어라고 한다.
불용어는 검색어 토큰에서 제외된다.
필요에 따라서 동의어를 추가 하기도 한다.
synonym 토큰 필터를 사용하여 quick 텀에 동의어로 fast를 지정하면 fast 로 검색했을 때도 같은 의미인 quick 을 포함하는 도큐먼트가 검색되도록 할 수 있다.
_analyze
elasticsearch 에서는 분석된 문장을 _analyze API를 이용해서 확인할 수 있다.
토크나이저는 tokenizer , 토큰 필터는 filter 항목의 값으로 입력하면 된다. 토크나이저는 하나만 적용되기 때문에 바로 입력하고, 토큰필터는 여러개를 적용할 수 있기 때문에 배열 형식으로 입력한다.
The quick brown fox jumps over the lazy dog 문장을 whitespace 토크나이저와 lowercase, stop, snowball 토큰 필터를 적용해봤다.
토큰필터 lowercase 는 대문자를 모두 소문자로 바꿔준다. 대소문자 구별없이 검색이 가능하게 된다.
stop은 불용어들을 제거해준다.
snowball은 문법상 변형된 단어를 일반적으로 검색에 쓰이는 기본 형태로 변환하여 검색이 가능하게 한다.
예를들면 jumps , jumping 을 ~s와 ~ing을 제거해서 jump로 변경 된다.
명령어
GET _analyze
{
"text" : "The quick brown fox jumps over the lazy dog",
"tokenizer" : "whitespace",
"filter" : [
"lowercase",
"stop",
"snowball"
]
}
결과
명령어
GET _analyze
{
"text" : "The quick brown fox jumps over the lazy dog",
"analyzer" : "snowball"
}
whitespace 토크나이저 , lowercase, stop, snowball 토큰 필터들을 조합한 것이 snowball 애널라이저 이다.
인덱스에 애널라이저를 지정한다.
명령어
PUT sport_6
{
"mappings": {
"properties": {
"message": {
"type": "text",
"analyzer": "snowball"
}
}
}
}
테스트 데이터를 넣는다
PUT sport_6/_doc/1
{
"message": "The quick brown fox jumps over the lazy dog"
}
결과 : match 쿼리로 jump , jumping 또는 jumps 중 어떤 값으로 검색 해도 결과가 나타난다.
snowball 애널라이저를 거쳐 jumping을 입력해도 jump로 검색한다.
역인덱스에는 jumps 가 아닌 jump로 저장 되어있다.
GET sport_6/_search
{
"query": {
"match": {
"message": "jumping"
}
}
}
Term 쿼리
elasticsearch에서 제공하는 쿼리 중에는 term 쿼리가 있다. match 쿼리와 문법은 유사하지만 term 쿼리는 입력한 검색어는 애널라이저를 적용하지 않고 입력된 검색어 그대로 일치하는 텀을 찾는다.
jumps , jumping 으로 검색하면 결과가 나타나지 않고 jump 로 검색해야 결과가 나타난다.
명령어
GET sport_6/_search
{
"query": {
"term": {
"message": "jumps"
}
}
}
결과
jump로 검색해야만 데이터가 조회된다.
referecence
https://esbook.kimjmin.net/06-text-analysis/6.3-analyzer-1/6.3-analyzer