Elasticsearch bool 복합쿼리 개념 정리 및 실습 / 예제
elasticsearch 검색에 있어 정확한 검색을 위해 bool 쿼리는 기본적으로 쓰이는 아주 유용한 query이다. 그동안 기존 코드를 사용하고 대강만 알고 있었는데 elasticsearch guide book 을 통해 정확하게 공부하고 정리해 보았다. match_all, match, match_phrase을 구별할 줄 안다면 Bool query는 금방 습득할 수 있다.
여러 조건을 모두 통합해서 검색을 할 때 상위에 Bool query를 사용한다. bool query는 다음과 같은 4개의 인자를 가지고 있다.
Bool Query | |
must | 반드시 해당 쿼리가 도큐먼트에 존재해야 검색됨 |
must_not | 쿼리가 거짓인 도큐먼트들을 검색 |
should | "must"처럼 반드시까진 아니고 옵셔널한 느낌 - should 쿼리 내용이 있으면 더 높은 점수를 받는다. (없어도 되지만 있으면 좋은..) 검색 결과 이 쿼리에 해당하는 도큐먼트의 score 점수를 높인다. |
filter | 쿼리가 참인 도큐먼트를 필터한다. 하지만 score계산에 영향을 주지 않는다. must보다 검색 속도가 빠르고 캐싱이 가능하다. |
실습하기 전, index 하나 만들고 bulk로 데이터들을 넣어놓기
PUT test_index
POST test_index/_bulk
{"index": {"_id":1}}
{"message": "The little cute cat" }
{"index": {"_id":2}}
{"message": "The little cute cat eats the red fish" }
{"index": {"_id":3}}
{"message": "The little cute cat eats the brown fish" }
{"index": {"_id":4}}
{"message": "The cute cat little fish" }
{"index": {"_id":5}}
{"message": "the red fish" }
1. bool - must 로 매칭되는 데이터 검색하기
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "cat"
}
},
{
"match_phrase": {
"message": "brown fish"
}
}
]
}
}
}
결과 :
{
"took" : 58,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.6690354,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.6690354,
"_source" : {
"message" : "The little cute cat eats the brown fish"
}
}
]
}
}
=> "cat"과 "brown fish" 둘 다 매칭되는 도큐먼트 1개가 나왔다.
2. bool - must_not 검색하기
위의 코드 must를 -> must_not으로 수정만 하면 "cat"과 "brown fish" 둘 다 모두 가지고 있지 않은 도큐먼트가 나온다.
GET test_index/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"message": "cat"
}
},
{
"match_phrase": {
"message": "brown fish"
}
}
]
}
}
}
결과 :
{
"took" : 72,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.0,
"_source" : {
"message" : "the red fish"
}
}
]
}
}
3. bool - should 사용하기
should 쿼리는 매칭되는 데이터에 가중치를 부여한다.
먼저 should 없이 매칭되는 쿼리를 날려보면,
GET test_index/_search
{
"query": {
"match": {
"message": "eats"
}
}
}
결과 :
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.744874,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.744874,
"_source" : {
"message" : "The little cute cat eats the red fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.744874,
"_source" : {
"message" : "The little cute cat eats the brown fish"
}
}
]
}
}
"eats"가 들어간 데이터 2건이 나온다.
여기서 "brown"매칭되는 데이터에 should 가중치를 넣어보기
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "eats"
}
}
],
"should": [
{
"match": {
"message": "brown"
}
}
]
}
}
}
결과 :
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.924373,
"_source" : {
"message" : "The little cute cat eats the brown fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.744874,
"_source" : {
"message" : "The little cute cat eats the red fish"
}
}
]
eats만 매칭되는 건 0.7448~ 점수였는데 should 쿼리로 "brown"과 매칭되는 걸 찾으니 1.9로 점수가 확 뛰었다. must는 반드시 있어야 해 ! 이고 Should는 매칭되는걸 우선적으로 검색해서 데꼬오자 ! 근데 매칭안되는 건 냅둬~ 느낌
should는 옵셔널하게 사용하고 반드시 포함되어야할 쿼리가 있다면 must를 사용하기!
4. match 와 should의 콜라보
match와 should의 콜라보는 우리와 친숙한 쿠팡, 에이블리 등등 플랫폼의 상품 검색 등 검색에서 좋은 결과를 가져다 준다. 예를 들어 아마존에서 고객이 "little fish"를 검색했을 때 "little red fish", "little fish", "red fish", "brown fish"... 등이 나올 것인데, 연관된 것 중 고객이 검색한 검색어와 정확히 일치하는 단어에 가중치를 두고 싶다면 아래와 같이 사용하면 된다.
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "little fish"
}
}
],
"should": [
{
"match_phrase": {
"message": "little fish"
}
}
]
}
}
}
match 에서 "little" 또는 "fish" (or operator) 둘 중 하나만 일치해도 모든 검색어를 가져오고 그 다음 should에서 match_phrase로 정확한 "little fish" 단어를 가진 데이터에 가중치를 주어 아래와 같은 결과가 나왔다 .
결과 :
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.2034782,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.2034782,
"_source" : {
"message" : "The cute cat little fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.48953635,
"_source" : {
"message" : "The little cute cat eats the red fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.48953635,
"_source" : {
"message" : "The little cute cat eats the brown fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.35513458,
"_source" : {
"message" : "the red fish"
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.32575765,
"_source" : {
"message" : "The little cute cat"
}
}
]
}
}
5. filter - 점수 score에 영향을 주지 않지만 빠르게 Yes or No 검색 가능
위에서 Bulk로 입력한 message 데이터 하나만으로는 filter 사용하기가 애매해서 다른 데이터를 더 넣고 실습해보기
- filter는 보통 false / true 와 같은 모아니면 도 데이터 또는 Range 에 많이 쓰인다고 한다.
아까 사용한 bulk 에 flag 값만 추가
POST test_index/_bulk
{"index": {"_id":1}}
{"message": "The little cute cat", "flag": false }
{"index": {"_id":2}}
{"message": "The little cute cat eats the red fish", "flag": true }
{"index": {"_id":3}}
{"message": "The little cute cat eats the brown fish", "flag": true }
{"index": {"_id":4}}
{"message": "The cute cat little fish", "flag": false }
{"index": {"_id":5}}
{"message": "the red fish", "flag": true }
그대로 해도 _id가 적혀있어서 덮어 씌워진다. (결과를 보면 result: updated, version : 2 로 나온다)
GET test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "little fish"
}
}
],
"filter": [
{
"match": {
"flag": true
}
}
]
}
}
}
little 또는 fish 를 가진 데이터 중에 flag 필드가 True인 데이터 검색하기
결과 :
{
"took" : 14,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.48953635,
"hits" : [
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.48953635,
"_source" : {
"message" : "The little cute cat eats the red fish",
"flag" : true
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.48953635,
"_source" : {
"message" : "The little cute cat eats the brown fish",
"flag" : true
}
},
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "5",
"_score" : 0.35513458,
"_source" : {
"message" : "the red fish",
"flag" : true
}
}
]
}
}
filter는 score에 영향을 미치지 않는다.!
filter 정리 끝,,,
match & match_all & match_phrase 사용법 및 차이에 대해 알아보기
Reference : https://esbook.kimjmin.net/05-search/5.2-bool
'Elasticsearch' 카테고리의 다른 글
[Elasticsearch] mapping field 수정 추가 삭제 (0) | 2022.11.10 |
---|---|
[Elasticsearch] Analyzer, Tokenizer, Filter 개념 및 활용 방법 (0) | 2022.11.09 |
[Elasticsearch] object vs nested 설명 및 예제 (0) | 2022.11.08 |
[elasticsearch] PUT vs POST 사용법 및 차이 (0) | 2022.11.07 |
[elasticsearch] match_all, match, match_phrase 사용 방법 및 차이점 (0) | 2022.11.07 |