이번에 개발하다가 이상한 점을 발견했다.
기존 should로만 구성된 nested query에 필수 조건이 붙어 must를 추가로 넣었는데, 쿼리는 잘 되는 듯 보였으나, inner_hit이 제대로 나오지 않는 현상이다. 쿼리의 결과는 제대로 나오고 있어서 제대로 되고있다고 착각했다.
아래 예시 데이터로 설명하겠다.
mapping
blogs라는 인덱스에 post doc이 있고, 그 안에는 nested로 해당 blog가 누구에게 공유되었는지(sharedTo)와 언제까지 공유가 유효한지(expiration)을 가지고 있다. authority는 해당 post에대한 권한을 의미한다.
PUT blogs
{
"mappings": {
"_doc": {
"properties": {
"post": {
"properties": {
"postId": {
"type": "keyword"
},
"contents": {
"type": "text"
}
}
},
"sharedPeople": {
"type" : "nested",
"properties": {
"expiration": {
"type": "date"
},
"authority": {
"type": "keyword"
},
"sharedTo":{
"type":"keyword"
}
}
}
}
}
}
}
doc 2개 추가
1번 doc은 A,B,C에게 공유되었고
2번 doc은 B,C에게 공유되었다.
PUT blogs/_doc/1
{
"post": {
"postId": 1,
"contents": "hello"
},
"sharedPeople": [
{
"exiration": "2021-05-20",
"authority": "1",
"sharedTo": "A"
},
{
"exiration": "2021-05-20",
"authority": "2",
"sharedTo": "B"
}
,
{
"exiration": "2021-05-20",
"authority": "3",
"sharedTo": "C"
}
]
}
PUT blogs/_doc/2
{
"post": {
"postId": 2,
"contents": "world"
},
"sharedPeople": [
{
"exiration": "2021-05-20",
"authority": "2",
"sharedTo": "B"
}
,
{
"exiration": "2021-05-20",
"authority": "3",
"sharedTo": "C"
}
]
}
A가 공유받은 문서를 가져오는 쿼리
여러번 공유되었을 수도 있기 때문에, 쿼리에서는 공유 권한(authority)순으로 정렬해서 가장 큰 값을 inner_hit으로 받아온다.
GET blogs/_search
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "sharedPeople",
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"terms": {
"sharedPeople.sharedTo": [
"A"
]
}
}
]
}
}
]
}
},
"inner_hits": {
"name": "sharedInfo",
"from": 0,
"size": 1,
"sort": [
{
"sharedPeople.authority": {
"order": "desc"
}
}
]
}
}
}
}
}
}
"hits" : {
"total" : 1,
"max_score" : 0.0,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.0,
"_source" : {
"post" : {
"postId" : 1,
"contents" : "hello"
},
"sharedPeople" : [
{
"exiration" : "2021-05-20",
"authority" : "1",
"sharedTo" : "A"
},
{
"exiration" : "2021-05-20",
"authority" : "2",
"sharedTo" : "B"
},
{
"exiration" : "2021-05-20",
"authority" : "3",
"sharedTo" : "C"
}
]
},
"inner_hits" : {
"sharedInfo" : {
"hits" : {
"total" : 1,
"max_score" : null,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "sharedPeople",
"offset" : 0
},
"_score" : null,
"_source" : {
"exiration" : "2021-05-20",
"authority" : "1",
"sharedTo" : "A"
},
"sort" : [
"1"
]
}
]
}
}
}
}
]
}
여기에 공유기간을 추가조건으로 must로 넣었을때
GET blogs/_search
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "sharedPeople",
"query": {
"bool": {
"must": [
{
"range": {
"sharedPeople.exiration": {
"from": "2020-05-20",
"to": null,
"include_lower": false,
"include_upper": true
}
}
}
],
"should": [
{
"bool": {
"must": [
{
"terms": {
"sharedPeople.sharedTo": [
"A"
]
}
}
]
}
}
]
}
},
"inner_hits": {
"name": "sharedInfo",
"from": 0,
"size": 1,
"sort": [
{
"sharedPeople.authority": {
"order": "desc"
}
}
]
}
}
}
}
}
}
"hits" : {
"total" : 1,
"max_score" : 0.0,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.0,
"_source" : {
"post" : {
"postId" : 1,
"contents" : "hello"
},
"sharedPeople" : [
{
"exiration" : "2021-05-20",
"authority" : "1",
"sharedTo" : "A"
},
{
"exiration" : "2021-05-20",
"authority" : "2",
"sharedTo" : "B"
},
{
"exiration" : "2021-05-20",
"authority" : "3",
"sharedTo" : "C"
}
]
},
"inner_hits" : {
"sharedInfo" : {
"hits" : {
"total" : 3,
"max_score" : null,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "sharedPeople",
"offset" : 2
},
"_score" : null,
"_source" : {
"exiration" : "2021-05-20",
"authority" : "3",
"sharedTo" : "C"
},
"sort" : [
"3"
]
}
]
}
}
}
}
]
}
위와같이 결과중에 inner_hit에 C의 권한이 나온다.
inner_hit에서 쿼리 중 아래의 should권한이 무시된 것이다.
"should": [
{
"bool": {
"must": [
{
"terms": {
"sharedPeople.sharedTo": [
"A"
]
}
}
]
}
}
]
#! Deprecation: Should clauses in the filter context will no longer automatically set the minimum should match to 1 in the next major version. You should group them in a [filter] clause or explicitly set [minimum_should_match] to 1 to restore this behavior in the next major version.
아래와같이 minimun_should_match를 명시해보자
GET blogs/_search
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "sharedPeople",
"query": {
"bool": {
"must": [
{
"range": {
"sharedPeople.exiration": {
"from": "2020-05-20",
"to": null,
"include_lower": false,
"include_upper": true
}
}
}
],
"should": [
{
"bool": {
"must": [
{
"terms": {
"sharedPeople.sharedTo": [
"A"
]
}
}
]
}
}
],
"minimum_should_match" : 1
}
},
"inner_hits": {
"name": "sharedInfo",
"from": 0,
"size": 1,
"sort": [
{
"sharedPeople.authority": {
"order": "desc"
}
}
]
}
}
}
}
}
}
"hits" : {
"total" : 1,
"max_score" : 0.0,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.0,
"_source" : {
"post" : {
"postId" : 1,
"contents" : "hello"
},
"sharedPeople" : [
{
"exiration" : "2021-05-20",
"authority" : "1",
"sharedTo" : "A"
},
{
"exiration" : "2021-05-20",
"authority" : "2",
"sharedTo" : "B"
},
{
"exiration" : "2021-05-20",
"authority" : "3",
"sharedTo" : "C"
}
]
},
"inner_hits" : {
"sharedInfo" : {
"hits" : {
"total" : 1,
"max_score" : null,
"hits" : [
{
"_index" : "blogs",
"_type" : "_doc",
"_id" : "1",
"_nested" : {
"field" : "sharedPeople",
"offset" : 0
},
"_score" : null,
"_source" : {
"exiration" : "2021-05-20",
"authority" : "1",
"sharedTo" : "A"
},
"sort" : [
"1"
]
}
]
}
}
}
}
]
}
제대로 A의 권한이 나오고 있다.