Compound Query
앞서 이미 query 의 종류에 대해 살펴보았고 지금까지 본 모든 query 는 leaf query 로
이는 Elasticsearch query 의 기본이 되며 주어진 fields 에 대해
값을 검색시 하나의 operation 만 허용한다. ( n field + 1 operation )
이에 반해 compound query 란 이런 leaf query 의 조합으로
다수의 operation 을 조합하는 것이다.
Query type context vs Filter type context
Compound query 는 query type context 와 filter type context 를 구분하여 조합하게 되는데
context 는 한글로 표현하자면 "절" 이다.
바꿔말하면 query 절과 filter 절이 있는데 이런 절 안에는
Elasticsearch 에서 제공하는 query 를 채울 수 있다.
query ( queries )
두 절의 다른 점은 query 절에는 relevant score 를 계산하는 full-text query 로만 구성해야 하며
"How well does this document match this query clause"
filter 절에 넣은 query 는 작동시 Releavant Score 를 사용하지 않고 단순히 일치 / 불일치만 계산하므로
“Does this document match this query clause?”
filter 절에는 이런 특성을 가지는 term level query 로 구성해야 한다.
예를 들어 아래 compound query 는 must 라는 query 절과 filter 라는 filter 절을 포함하며
must query 절에는 match 라는 full-text query ( relevant score 고려한 결과를 내는 쿼리 ) 를 사용하였고
filter 절에는 term , range 처럼 term level query 를 사용하였다.
GET /my_index/default/_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
|
bool query ( bool )
bool query 는 총 4가지 옵션 필터를 제공하는데 must, must_not, should, filter 옵션이다.
이중 must, must_not, should 는 query type context 로 구성해야 하며
filter 옵션은 filter type context 로 구성해야 한다.
각 옵션의 의미는 아래와 같다.
must : 해당 절에 지정된 모든 query 결과가 true 가 되어야 가 일치 document 으로 간주한다.
must_not : 해당 절에 지정된 모든 query 결과가 false 가 되어야 일치 document 으로 간주한다.
should : 해당 절에 지정된 query 가 많이 일치할 수록 Relevance Score 를 높혀 검색 순위를 높힌다.
filter : 해당 절에 지정된 모든 query 가 true 가 되어야 일치 document 로 간주한다.
단 이 절은 relevance score 계산에 포함되지 않는 filter type context 이다.
must, filter
이중 먼저 가장 많이 사용되는 must , filter 옵션을 사용해 보자.
아래와 같이 테스트 해보면 검색 결과로 ingredients.name 이 parmesan 이 포함되고
perparation_time_minutes 가 15 이하인 행들이 검색될 것이다.
GET /recipe/default/_search
{
"query": {
"bool": {
"must": [
{
"match":{
"ingredients.name":"parmesan"
}
}
],
"filter": [
{
"range":{
"preparation_time_minutes": {
"lte":15
}
}
}
]
}
}
}
|
{
"took" : 10,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.447008,
"hits" : [
{
"_index" : "recipe",
"_type" : "default",
"_id" : "1",
"_score" : 1.447008,
"_source" : {
"title" : "....",
"preparation_time_minutes" : 12,
"servings" : {
"min" : 4,
"max" : 6
},
"steps" : [
"...."
],
"ingredients" : [
...
{
"name" : "Parmesan cheese"
}
],
...
}
},
{
"_index" : "recipe",
"_type" : "default",
"_id" : "10",
"_score" : 1.0727434,
"_source" : {
"title" : "Penne With Hot-As-You-Dare Arrabbiata Sauce",
"description" : "....",
"preparation_time_minutes" : 15,
"servings" : {
"min" : 4,
"max" : 4
},
"steps" : [
"....
],
"ingredients" : [
...
{
"name" : "Finely grated Parmesan cheese",
"quantity" : "60g"
},
{
"name" : "Minced flat-leaf parsley leaves",
"quantity" : "Small handful"
}
],
...
}
},
{
"_index" : "recipe",
"_type" : "default",
"_id" : "11",
"_score" : 0.44000342,
"_source" : {
"title" : "Spaghetti Puttanesca (Pasta or Spaghetti With Capers, Olives, and Anchovies)",
"description" : "....",
"preparation_time_minutes" : 15,
"servings" : {
"min" : 2,
"max" : 3
},
"steps" : [
"...."
],
"ingredients" : [
...
{
"name" : "Finely grated Pecorino Romano or Parmesan cheese",
"quantity" : "30g"
},
{
"name" : "Freshly ground black pepper"
},
{
"name" : "Can oil-packed tuna",
"quantity" : "140g"
}
],
...
}
}
]
}
}
|
must_not
여기에 더해 이번에는 tuna 가 포함되지 않는 결과만 보고 싶다고 하면 아래와 같이 하면 되겠다.
GET /recipe/default/_search
{
"query": {
"bool": {
"must": [
{
"match":{
"ingredients.name":"parmesan"
}
}
],
"must_not": [
{
"match":{
"ingredients.name":"tuna"
}
}
],
"filter": [
{
"range":{
"preparation_time_minutes": {
"lte":15
}
}
}
]
}
}
}
|
{
"took" : 10,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.447008,
"hits" : [
{
"_index" : "recipe",
"_type" : "default",
"_id" : "1",
"_score" : 1.447008,
"_source" : {
"title" : "Fast and Easy Pasta With Blistered Cherry Tomato Sauce",
"description" : "..."
"preparation_time_minutes" : 12,
"servings" : {
"min" : 4,
"max" : 6
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Dry pasta",
"quantity" : "450g"
},
{
"name" : "Kosher salt"
},
{
"name" : "Cloves garlic",
"quantity" : "4"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "90ml"
},
{
"name" : "Cherry tomatoes",
"quantity" : "750g"
},
{
"name" : "Fresh basil leaves",
"quantity" : "30g"
},
{
"name" : "Freshly ground black pepper"
},
{
"name" : "Parmesan cheese"
}
],
"created" : "2017/03/29",
"ratings" : [
4.5,
5.0,
3.0,
4.5
]
}
},
{
"_index" : "recipe",
"_type" : "default",
"_id" : "10",
"_score" : 1.0727434,
"_source" : {
"title" : "Penne With Hot-As-You-Dare Arrabbiata Sauce",
"description" : "..."
"preparation_time_minutes" : 15,
"servings" : {
"min" : 4,
"max" : 4
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Kosher salt"
},
{
"name" : "Penne pasta",
"quantity" : "450g"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "3 tablespoons"
},
{
"name" : "Clove garlic",
"quantity" : "1"
},
{
"name" : "Crushed red pepper"
},
{
"name" : "Can whole peeled tomatoes",
"quantity" : "400g"
},
{
"name" : "Finely grated Parmesan cheese",
"quantity" : "60g"
},
{
"name" : "Minced flat-leaf parsley leaves",
"quantity" : "Small handful"
}
],
...
}
}
]
}
}
|
should
마지막으로 파슬리를 선호한다고 가정하면 아래와 같이 적용해 보자.
기존 2 개 결과가 서로 순서가 바뀌는 것을 확인할 수 있게 된다.
GET /recipe/default/_search
{
"query": {
"bool": {
"must": [
{
"match":{
"ingredients.name":"parmesan"
}
}
],
"must_not": [
{
"match":{
"ingredients.name":"tuna"
}
}
],
"should": [
{
"match":{
"ingredients.name":"parsley"
}
}
],
"filter": [
{
"range":{
"preparation_time_minutes": {
"lte":15
}
}
}
]
}
}
}
|
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.7949219,
"hits" : [
{
"_index" : "recipe",
"_type" : "default",
"_id" : "10",
"_score" : 1.7949219,
"_source" : {
"title" : "Penne With Hot-As-You-Dare Arrabbiata Sauce",
"description" : "..."
"preparation_time_minutes" : 15,
"servings" : {
"min" : 4,
"max" : 4
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Kosher salt"
},
{
"name" : "Penne pasta",
"quantity" : "450g"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "3 tablespoons"
},
{
"name" : "Clove garlic",
"quantity" : "1"
},
{
"name" : "Crushed red pepper"
},
{
"name" : "Can whole peeled tomatoes",
"quantity" : "400g"
},
{
"name" : "Finely grated Parmesan cheese",
"quantity" : "60g"
},
{
"name" : "Minced flat-leaf parsley leaves",
"quantity" : "Small handful"
}
],
...
},
{
"_index" : "recipe",
"_type" : "default",
"_id" : "1",
"_score" : 1.447008,
"_source" : {
"title" : "Fast and Easy Pasta With Blistered Cherry Tomato Sauce",
"description" : "..."
"preparation_time_minutes" : 12,
"servings" : {
"min" : 4,
"max" : 6
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Dry pasta",
"quantity" : "450g"
},
{
"name" : "Kosher salt"
},
{
"name" : "Cloves garlic",
"quantity" : "4"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "90ml"
},
{
"name" : "Cherry tomatoes",
"quantity" : "750g"
},
{
"name" : "Fresh basil leaves",
"quantity" : "30g"
},
{
"name" : "Freshly ground black pepper"
},
{
"name" : "Parmesan cheese"
}
],
...
}
}
]
}
}
|
디버깅을 위해서는 _name 필드를 사용하면 된다.
GET /recipe/default/_search
{
"query": {
"bool": {
"must": [
{
"match":{
"ingredients.name":{
"query":"parmesan",
"_name":"parmesan_must"
}
}
}
],
"must_not": [
{
"match":{
"ingredients.name":{
"query":"tuna",
"_name":"tuna_must_not"
}
}
}
],
"should": [
{
"match":{
"ingredients.name":{
"query":"parsley",
"_name":"parsley_should"
}
}
}
],
"filter": [
{
"range":{
"preparation_time_minutes": {
"lte":15,
"_name":"preparation_time_filter"
}
}
}
]
}
}
}
|
{
"took" : 10,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.7949219,
"hits" : [
{
"_index" : "recipe",
"_type" : "default",
"_id" : "10",
"_score" : 1.7949219,
"_source" : {
"title" : "Penne With Hot-As-You-Dare Arrabbiata Sauce",
"description" : "..."
"preparation_time_minutes" : 15,
"servings" : {
"min" : 4,
"max" : 4
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Kosher salt"
},
{
"name" : "Penne pasta",
"quantity" : "450g"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "3 tablespoons"
},
{
"name" : "Clove garlic",
"quantity" : "1"
},
{
"name" : "Crushed red pepper"
},
{
"name" : "Can whole peeled tomatoes",
"quantity" : "400g"
},
{
"name" : "Finely grated Parmesan cheese",
"quantity" : "60g"
},
{
"name" : "Minced flat-leaf parsley leaves",
"quantity" : "Small handful"
}
],
"created" : "2017/04/27",
"ratings" : [
1.5,
2.0,
4.0,
3.5,
3.0,
5.0,
1.5
]
},
"matched_queries" : [
"parmesan_must",
"preparation_time_filter",
"parsley_should"
]
},
{
"_index" : "recipe",
"_type" : "default",
"_id" : "1",
"_score" : 1.447008,
"_source" : {
"title" : "Fast and Easy Pasta With Blistered Cherry Tomato Sauce",
"description" : "..."
"preparation_time_minutes" : 12,
"servings" : {
"min" : 4,
"max" : 6
},
"steps" : [
"..."
],
"ingredients" : [
{
"name" : "Dry pasta",
"quantity" : "450g"
},
{
"name" : "Kosher salt"
},
{
"name" : "Cloves garlic",
"quantity" : "4"
},
{
"name" : "Extra-virgin olive oil",
"quantity" : "90ml"
},
{
"name" : "Cherry tomatoes",
"quantity" : "750g"
},
{
"name" : "Fresh basil leaves",
"quantity" : "30g"
},
{
"name" : "Freshly ground black pepper"
},
{
"name" : "Parmesan cheese"
}
],
"created" : "2017/03/29",
"ratings" : [
4.5,
5.0,
3.0,
4.5
]
},
"matched_queries" : [
"parmesan_must",
"preparation_time_filter"
]
}
]
}
}
|
weight
boost 옵션으로 각 쿼리마다 가산점 비율을 조절할 수 있다. ( 기본값은 1 )
1보다 크면 점수가 높게 오르고 1보다 적으면 점수가 낮게 오른다.
하지만 2를 준다고해서 점수가 2배로 오르는 것은 아니며, 정규화를 거친 후 적용된다.
GET /_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "test1",
"boost": 1.2
}
}
},
{
"match": {
"keyword": {
"query": "test2",
"boost": 2
}
}
}
]
}
}
}
|
'Monitoring > Elasticsearch' 카테고리의 다른 글
11. Query Result Options (0) | 2020.01.17 |
---|---|
10. Joining Query (0) | 2020.01.17 |
08. Query (0) | 2020.01.17 |
07. Analyzer (1) | 2020.01.17 |
06. Mapping (0) | 2020.01.17 |