-
[ELK Stack] Elasticsearch 검색(search) - Compound QueryELK Stack 2020. 12. 1. 16:50반응형
실제 사용한 부분에 대해서만 설명하겠습니다.
먼저 하기와 같이 test에 사용하는 data를 생성하겠습니다.
PUT /test_query/_doc/1 { "sports": "football", "name": "Messi" } PUT /test_query/_doc/2 { "sports": "football", "name": "Ibrahimovic" } PUT /test_query/_doc/3 { "sports": "basketball", "name": "LeBron James" } PUT /test_query/_doc/4 { "sports": "basketball", "name": "DF ER Nicole James basketball" } PUT /test_query/_doc/5 { "sports": "James basketball", "name": "James Nicole Nicole Nicole James James James Nicole Nicole James" }
혹시나 모르시는 분있을가봐 하는 얘기인데요, 하기 명령은 Kibana의 Dev Tools에서 실행할수 있습니다.
www.elastic.co/guide/en/kibana/current/console-kibana.html
Boolean query
여러가지 검색조건을 조합해서 검색합니다.
- must: 검색결과에 해당 조건이 반드시 포함되어야 함. query context에서 동작함.
- filter: 검색결과에 해당 조건이 반드시 포함되어야 함.
- must와 다른점은 relevance score에 영향을 주지 않음. 해당 조건이 포함되어있는지 YES/NO 여부만 확인하기 때문에 filter는 속도가 빠름.
- filter context에서 동작 함.
- should: optional 조건임. 포함된 조건들이 검색결과에 포함될수도 있고 포함되지 않을수도 있음.
- minimum_should_match 값을 설정하는 방법으로 should에 있는 조건이 검색결과에 포함될지를 결정할 수 있음. 검색조건에 should만 있으면 minimum_should_match 값이 default로 1이고 should외의 조건이 존재하면 minimum_should_match 값이 default로 0.
- query context에서 동작함.
- must_not: 해당 조건은 검색결과에 포함되지 말아야 함. filter와 마찬가지로 score에 영향을 주지 않음.
하기 내용을 참조하였습니다.
www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
Boolean query에서 주의할점은 should와 filter/must_not을 결합하여 사용 시 minimum_should_match값을 고려해야 하는것입니다. 위에서 설명했듯이 should는 기타 조건과 조합하여 검색시 minimum_should_match 값이 default로 0으로 설정됩니다. 즉 검색결과에 should 의 그 어떤 조건에도 match되지 않는 결과들이 포함될수 있다는 것입니다.
하기 query를 날려봅니다.
GET /test_query/_search { "query": { "bool": { "should": [ {"match": { "name": "Messi" }} ], "filter": [ {"match": { "sports": "basketball" }} ] } } }
얼핏보면(?), 일단 저는 검색결과에서 "name"이 "Messi" 인 결과에서 "sports"가 "basketball"로 되어있는 값을 가져오려고 위와 같이 작성하였습니다. 제 생각대로 하면 검색결과는 존재하지 않습니다. 그러나 실행해보면 하기와 같은 결과가 return됩니다.
{ "took" : 5, "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_query", "_type" : "_doc", "_id" : "3", "_score" : 0.0, "_source" : { "sports" : "basketball", "name" : "LeBron James" } } ] } }
즉 should 조건이 무시되고 filter조건만 만족하는 결과가 return된것입니다.
위와 같은 의도로 검색하려면 하기와 같이 변경하면 됩니다.
- minimum_should_match 값을 1로 변경
- should match대신 must 를 사용
GET /test_query/_search { "query": { "bool": { "should": [ {"match": { "name": "Messi" }} ], "minimum_should_match": 1, "filter": [ {"match": { "sports": "basketball" }} ] } } } GET /test_query/_search { "query": { "bool": { "must": [ {"match": { "name": "Messi" }} ], "filter": [ {"match": { "sports": "basketball" }} ] } } }
Constant score:
만약 filter에 score를 주고 싶으면 constant_score를 사용하면 됩니다.
GET /test_query/_search { "query": { "constant_score": { "filter": { "match": { "sports": "basketball" } }, "boost": 1.0 } } } { "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "test_query", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "sports" : "basketball", "name" : "LeBron James" } } ] } }
Disjunction max query
여러개 query 조건이 있을 때 dis_max는 그 중 가 장 큰 relevance score를 최종 score로 사용합니다. 만약 tie_breaker가 설정이 되어 있으면 기타 조건의 score에 tie_breaker 값을 곱한후 최종 score에 plus 합니다.
하기 두 query결과 값을 보면 쉽게 이해할 수 있습니다.
(1). 첫번째는 boolean query의 must로 검색하였습니다. 정확하게 검색하는 "Nicole James basketball" 이라는 값이 존재하는 item(_id: 4)이 있음에도 (_id: 5) item이 score가 가장 높게 return 되었습니다.
GET /test_query/_search { "query": { "bool": { "must": [ {"match": {"sports": "Nicole James basketball"}}, {"match": {"name": "Nicole James basketball"}} ] } } } "hits" : [ { "_index" : "test_query", "_type" : "_doc", "_id" : "5", "_score" : 4.097313, "_source" : { "sports" : "James basketball", "name" : "James Nicole Nicole Nicole James James James Nicole Nicole James" } }, { "_index" : "test_query", "_type" : "_doc", "_id" : "4", "_score" : 3.4452512, "_source" : { "sports" : "basketball", "name" : "DF ER Nicole James basketball" } }, { "_index" : "test_query", "_type" : "_doc", "_id" : "3", "_score" : 1.564933, "_source" : { "sports" : "basketball", "name" : "LeBron James" } } ]
(2). dis_max로 검색해 보겠습니다.
GET /test_query/_search { "query": { "dis_max": { "queries": [ {"match": {"sports": "Nicole James basketball"}}, {"match": {"name": "Nicole James basketball"}} ] } } } "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 2.7090812, "hits" : [ { "_index" : "test_query", "_type" : "_doc", "_id" : "4", "_score" : 2.7090812, "_source" : { "sports" : "basketball", "name" : "DF ER Nicole James basketball" } }, { "_index" : "test_query", "_type" : "_doc", "_id" : "5", "_score" : 2.3688042, "_source" : { "sports" : "James basketball", "name" : "James Nicole Nicole Nicole James James James Nicole Nicole James" } }, { "_index" : "test_query", "_type" : "_doc", "_id" : "3", "_score" : 0.8287628, "_source" : { "sports" : "basketball", "name" : "LeBron James" } } ]
결과에서 보다시피 (_id: 4) item이 가장 높은 score를 가지고 있습니다. dis_max는 검색 조건중에서 가장 높은 score를 사용하기 때문에 위와 같은 결과를 받습니다. 추가로 dis_max 결과와 boolean query 결과의 score를 보면 값이 차이가 많이 나는 것을 확인할 수도 있습니다.
검색하는 문구가 정확하게 포함되어 있는 결과의 score를 높이고 싶을 때 dis_max를 사용하면 좋을것 같습니다.
다음 페이지에서는 full text query 관련해서 설명하겠습니다.
2020/12/01 - [ELK Stack] - [ELK Stack] [초보자] Elasticsearch 검색(search) - Full Text Query
반응형'ELK Stack' 카테고리의 다른 글
[ELK Stack] Filebeat 소개 및 사용 (0) 2022.08.31 [ELK Stack] Elasticsearch cluster 롤링 업그레이드 관련(7.2 -> 7.17.2) (0) 2022.08.25 [ELK Stack]Elasticsearch 검색 - Full Text Query (0) 2020.12.01 [ELK Stack] Elasticsearch 검색 - Highlight, Nested Field (0) 2020.10.20 [ELK Stack] [초보자] Logstash 시작하기 (0) 2020.10.18