부모(has_parent) 쿼리
부모(has_parent) 쿼리
has_parent 쿼리는 특정 쿼리와 일치하는 부모 문서를 가진 자식 문서를 반환해요. 같은 인덱스 안의 문서들 사이에 부모/자식 관계를 맺으려면 조인(join) 필드 유형을 사용하면 됩니다.
has_parent 쿼리는 수행하는 조인 연산 때문에 다른 쿼리보다 느려요. 일치하는 부모 문서의 수가 늘어날수록 성능이 저하됩니다. 검색에 포함된 has_parent 쿼리 하나하나가 쿼리 성능에 큰 영향을 줄 수 있어요. 속도를 우선시한다면 이 쿼리 사용을 피하거나 최대한 제한하는 게 좋아요.
출처: 문서
본문
예제 (Example)
has_parent 쿼리를 실행하려면 먼저 인덱스에 부모/자식 관계를 맺기 위한 조인 필드가 있어야 해요. 인덱스 매핑 요청은 다음과 같은 형식을 사용해요.
PUT /example_index
{
"mappings": {
"properties": {
"relationship_field": {
"type": "join",
"relations": {
"parent_doc": "child_doc"
}
}
}
}
}
이 예제에서는 먼저 has_child 쿼리 예제에서 설명한 대로 제품과 해당 브랜드를 나타내는 문서가 담긴 인덱스를 구성해 보겠어요.
부모의 자식을 검색하려면 has_parent 쿼리를 사용해요. 다음 쿼리는 쿼리와 일치하는 economy 브랜드가 만든 자식 문서(제품)를 반환해요.
GET testindex1/_search
{
"query" : {
"has_parent": {
"parent_type":"brand",
"query": {
"match" : {
"name": "economy"
}
}
}
}
}
응답은 해당 브랜드가 만든 모든 제품을 반환해요.
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "testindex1",
"_id": "4",
"_score": 1,
"_routing": "2",
"_source": {
"name": "Electronic watch",
"sales_count": 300,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
},
{
"_index": "testindex1",
"_id": "5",
"_score": 1,
"_routing": "2",
"_source": {
"name": "Digital watch",
"sales_count": 100,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
}
]
}
}
내부 히트 가져오기 (Retrieving inner hits)
쿼리와 일치한 부모 문서를 반환하려면 inner_hits 파라미터를 제공해요.
GET testindex1/_search
{
"query" : {
"has_parent": {
"parent_type":"brand",
"query": {
"match" : {
"name": "economy"
}
},
"inner_hits": {}
}
}
}
응답에는 inner_hits 필드에 부모 문서가 포함돼요.
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "testindex1",
"_id": "4",
"_score": 1,
"_routing": "2",
"_source": {
"name": "Electronic watch",
"sales_count": 300,
"product_to_brand": {
"name": "product",
"parent": "2"
}
},
"inner_hits": {
"brand": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "testindex1",
"_id": "2",
"_score": 1.3862942,
"_source": {
"name": "Economy brand",
"product_to_brand": "brand"
}
}
]
}
}
}
},
{
"_index": "testindex1",
"_id": "5",
"_score": 1,
"_routing": "2",
"_source": {
"name": "Digital watch",
"sales_count": 100,
"product_to_brand": {
"name": "product",
"parent": "2"
}
},
"inner_hits": {
"brand": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "testindex1",
"_id": "2",
"_score": 1.3862942,
"_source": {
"name": "Economy brand",
"product_to_brand": "brand"
}
}
]
}
}
}
}
]
}
}
내부 히트를 가져오는 방법에 대한 자세한 내용은 "Inner hits"를 참고하세요.
파라미터 (Parameters)
다음 표는 has_parent 쿼리가 지원하는 모든 최상위 파라미터를 나열해요.
- parent_type (필수): 조인 필드 매핑에 정의된 부모 관계의 이름을 지정해요.
- query (필수): 부모 문서에 실행할 쿼리예요. 부모 문서가 쿼리와 일치하면 자식 문서가 반환돼요.
- ignore_unmapped (선택): 매핑되지 않은 parent_type 필드를 무시하고 오류 대신 문서를 반환하지 않을지 나타내요. 일부 인덱스에 parent_type 필드가 없을 수 있는 여러 인덱스를 쿼리할 때 이 파라미터를 제공할 수 있어요. 기본값은
false예요. - score (선택): 일치하는 부모 문서의 관련성 점수가 자식 문서에 집계될지 나타내요.
false면 부모 문서의 관련성 점수를 무시하고 각 자식 문서에 쿼리의 boost(기본값 1)와 같은 관련성 점수를 부여해요.true면 일치하는 부모 문서의 관련성 점수가 자식 문서의 관련성 점수에 집계돼요. 기본값은false예요. - inner_hits (선택): 제공하면 쿼리와 일치한 기본 히트(부모 문서)를 반환해요.
정렬 제한 (Sorting limitations)
has_parent 쿼리는 표준 정렬 옵션을 사용한 결과 정렬을 지원하지 않아요. 부모 문서의 필드를 기준으로 자식 문서를 정렬해야 한다면 function_score 쿼리를 사용하고 자식 문서의 점수로 정렬할 수 있어요.
앞선 예제에서 먼저 자식 문서를 정렬할 customer_satisfaction 필드를 부모(brand) 문서에 추가해요.
PUT testindex1/_doc/1
{
"name": "Luxury watch brand",
"product_to_brand" : "brand",
"customer_satisfaction": 4.5
}
PUT testindex1/_doc/2
{
"name": "Economy watch brand",
"product_to_brand" : "brand",
"customer_satisfaction": 3.9
}
이제 부모 브랜드의 customer_satisfaction 필드를 기준으로 자식 문서(제품)를 정렬할 수 있어요. 다음 쿼리는 점수에 부모 문서의 customer_satisfaction 필드를 곱해요.
GET testindex1/_search
{
"query": {
"has_parent": {
"parent_type": "brand",
"score": true,
"query": {
"function_score": {
"script_score": {
"script": "_score * doc['customer_satisfaction'].value"
}
}
}
}
}
}
응답에는 가장 높은 부모 customer_satisfaction 순으로 정렬된 제품이 포함돼요.
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 4.5,
"hits": [
{
"_index": "testindex1",
"_id": "3",
"_score": 4.5,
"_routing": "1",
"_source": {
"name": "Mechanical watch",
"sales_count": 150,
"product_to_brand": {
"name": "product",
"parent": "1"
}
}
},
{
"_index": "testindex1",
"_id": "4",
"_score": 3.9,
"_routing": "2",
"_source": {
"name": "Electronic watch",
"sales_count": 300,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
},
{
"_index": "testindex1",
"_id": "5",
"_score": 3.9,
"_routing": "2",
"_source": {
"name": "Digital watch",
"sales_count": 100,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
}
]
}
}
다음 단계 (Next steps)
- 내부 히트를 가져오는 방법에 대해 자세히 알아보세요.