Retrieve inner hits
출처: 문서
본문
inner hits 조회하기
OpenSearch에서 nested 객체나 parent-join을 사용해 검색을 수행하면, 그 밑에 있는 히트(nested 내부 객체 또는 자식 문서)는 기본적으로 숨겨져 있어요. 검색 쿼리에 inner_hits 파라미터를 사용하면 inner hits를 조회할 수 있어요.
inner_hits는 다음 기능과도 함께 사용할 수 있어요:
nested 객체에서의 inner hits
nested 객체를 사용하면 객체 배열을 인덱싱하면서 같은 문서 안에서 그 관계를 유지할 수 있어요. 다음 예제 요청은 inner_hits 파라미터를 사용해 내부에 숨겨진 inner hits를 조회해요.
-
nested 객체가 포함된 인덱스 매핑을 생성해요:
PUT /my_index { "mappings": { "properties": { "user": { "type": "nested", "properties": { "name": { "type": "text" }, "age": { "type": "integer" } } } } } }{% include copy-curl.html %}
-
데이터를 인덱싱해요:
POST /my_index/_doc/1 { "group": "fans", "user": [ { "name": "John Doe", "age": 28 }, { "name": "Jane Smith", "age": 34 } ] }{% include copy-curl.html %}
-
inner_hits로 쿼리해요:GET /my_index/_search { "query": { "nested": { "path": "user", "query": { "bool": { "must": [ { "match": { "user.name": "John" } } ] } }, "inner_hits": {} } } }{% include copy-curl.html %}
앞선 쿼리는 이름이 John인 nested user 객체를 검색하고, 매칭되는 nested 문서를 응답의 inner_hits 섹션에 반환해요:
{
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_index",
"_id" : "1",
"_score" : 0.6931471,
"_source" : {
"group" : "fans",
"user" : [
{
"name" : "John Doe",
"age" : 28
},
{
"name" : "Jane Smith",
"age" : 34
}
]
},
"inner_hits" : {
"user" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_index",
"_id" : "1",
"_nested" : {
"field" : "user",
"offset" : 0
},
"_score" : 0.6931471,
"_source" : {
"name" : "John Doe",
"age" : 28
}
}
]
}
}
}
}
]
}
}
parent/child 객체에서의 inner hits
parent-join 관계를 사용하면 같은 인덱스 안에서 서로 다른 타입의 문서 간에 관계를 만들 수 있어요. 다음 예제 요청은 parent/child 객체를 사용해 inner_hits로 검색해요.
-
parent-join 필드가 있는 인덱스를 생성해요:
PUT /my_index { "mappings": { "properties": { "my_join_field": { "type": "join", "relations": { "parent": "child" } }, "text": { "type": "text" } } } }{% include copy-curl.html %}
-
데이터를 인덱싱해요:
# Index a parent document PUT /my_index/_doc/1 { "text": "This is a parent document", "my_join_field": "parent" } # Index a child document PUT /my_index/_doc/2?routing=1 { "text": "This is a child document", "my_join_field": { "name": "child", "parent": "1" } }{% include copy-curl.html %}
-
inner_hits로 검색해요:GET /my_index/_search { "query": { "has_child": { "type": "child", "query": { "match": { "text": "child" } }, "inner_hits": {} } } }{% include copy-curl.html %}
앞선 쿼리는 쿼리 조건(이 경우 "child"라는 용어를 포함)에 매칭되는 자식 문서를 가진 부모 문서를 검색해요. 그리고 매칭되는 자식 문서를 응답의 inner_hits 섹션에 반환해요:
{
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my_index",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"text" : "This is a parent document",
"my_join_field" : "parent"
},
"inner_hits" : {
"child" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_index",
"_id" : "2",
"_score" : 0.6931471,
"_routing" : "1",
"_source" : {
"text" : "This is a child document",
"my_join_field" : {
"name" : "child",
"parent" : "1"
}
}
}
]
}
}
}
}
]
}
}
parent-join과 nested 객체를 inner_hits와 함께 사용하기
다음 예제는 parent-join과 nested 객체를 inner_hits와 함께 사용하는 방법을 보여줘요.
-
다음 매핑으로 인덱스를 생성해요:
PUT /my_index { "mappings": { "properties": { "my_join_field": { "type": "join", "relations": { "parent": "child" } }, "text": { "type": "text" }, "comments": { "type": "nested", "properties": { "user": { "type": "text" }, "message": { "type": "text" } } } } } }{% include copy-curl.html %}
-
데이터를 인덱싱해요:
# Index a parent document PUT /my_index/_doc/1 { "text": "This is a parent document", "my_join_field": "parent" } # Index a child document with nested comments PUT /my_index/_doc/2?routing=1 { "text": "This is a child document", "my_join_field": { "name": "child", "parent": "1" }, "comments": [ { "user": "John", "message": "This is a comment" }, { "user": "Jane", "message": "Another comment" } ] }{% include copy-curl.html %}
-
inner_hits로 쿼리해요:GET /my_index/_search { "query": { "has_child": { "type": "child", "query": { "nested": { "path": "comments", "query": { "bool": { "must": [ { "match": { "comments.user": "John" } } ] } }, "inner_hits": {} } }, "inner_hits": {} } } }{% include copy-curl.html %}
앞선 쿼리는 John이 작성한 댓글을 포함하는 자식 문서를 가진 부모 문서를 검색해요. inner_hits를 지정하면 매칭되는 자식 문서와 그 안의 nested 댓글이 함께 반환돼요:
{
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my_index",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"text" : "This is a parent document",
"my_join_field" : "parent"
},
"inner_hits" : {
"child" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_index",
"_id" : "2",
"_score" : 0.6931471,
"_routing" : "1",
"_source" : {
"text" : "This is a child document",
"my_join_field" : {
"name" : "child",
"parent" : "1"
},
"comments" : [
{
"user" : "John",
"message" : "This is a comment"
},
{
"user" : "Jane",
"message" : "Another comment"
}
]
},
"inner_hits" : {
"comments" : {
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "my_index",
"_id" : "2",
"_nested" : {
"field" : "comments",
"offset" : 0
},
"_score" : 0.6931471,
"_source" : {
"message" : "This is a comment",
"user" : "John"
}
}
]
}
}
}
}
]
}
}
}
}
]
}
}
inner_hits 파라미터
nested 객체와 parent-join 관계를 모두 사용하는 inner_hits 검색에는 다음 추가 파라미터를 전달할 수 있어요:
from:inner_hits결과에서 히트를 가져오기 시작하는 오프셋이에요.size: 반환할 inner hits의 최대 개수예요.sort: inner hits의 정렬 순서예요.name: 응답에서 inner hits에 붙일 사용자 지정 이름이에요. 하나의 쿼리에서 여러 개의 inner hits를 구분할 때 유용해요.
예제: nested 객체에서의 inner_hits 파라미터
-
다음 매핑으로 인덱스를 생성해요:
PUT /products { "mappings": { "properties": { "product_name": { "type": "text" }, "reviews": { "type": "nested", "properties": { "user": { "type": "text" }, "comment": { "type": "text" }, "rating": { "type": "integer" } } } } } }{% include copy-curl.html %}
-
데이터를 인덱싱해요:
POST /products/_doc/1 { "product_name": "Smartphone", "reviews": [ { "user": "Alice", "comment": "Great phone", "rating": 5 }, { "user": "Bob", "comment": "Not bad", "rating": 3 }, { "user": "Charlie", "comment": "Excellent", "rating": 4 } ] }{% include copy-curl.html %}
POST /products/_doc/2 { "product_name": "Laptop", "reviews": [ { "user": "Dave", "comment": "Very good", "rating": 5 }, { "user": "Eve", "comment": "Good value", "rating": 4 } ] }{% include copy-curl.html %}
-
inner_hits로 쿼리하면서 추가 파라미터를 지정해요:GET /products/_search { "query": { "nested": { "path": "reviews", "query": { "match": { "reviews.comment": "Good" } }, "inner_hits": { "from": 0, "size": 2, "sort": [ { "reviews.rating": { "order": "desc" } } ], "name": "top_reviews" } } } }{% include copy-curl.html %}
다음은 예상 결과예요:
{
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.83740485,
"hits" : [
{
"_index" : "products",
"_id" : "2",
"_score" : 0.83740485,
"_source" : {
"product_name" : "Laptop",
"reviews" : [
{
"user" : "Dave",
"comment" : "Very good",
"rating" : 5
},
{
"user" : "Eve",
"comment" : "Good value",
"rating" : 4
}
]
},
"inner_hits" : {
"top_reviews" : {
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "products",
"_id" : "2",
"_nested" : {
"field" : "reviews",
"offset" : 0
},
"_score" : null,
"_source" : {
"rating" : 5,
"comment" : "Very good",
"user" : "Dave"
},
"sort" : [
5
]
},
{
"_index" : "products",
"_id" : "2",
"_nested" : {
"field" : "reviews",
"offset" : 1
},
"_score" : null,
"_source" : {
"rating" : 4,
"comment" : "Good value",
"user" : "Eve"
},
"sort" : [
4
]
}
]
}
}
}
}
]
}
}
예제: parent-join 관계에서의 inner_hits 파라미터
-
다음 매핑으로 인덱스를 생성해요:
PUT /company { "mappings": { "properties": { "my_join_field": { "type": "join", "relations": { "employee": "task" } }, "name": { "type": "text" }, "description": { "type": "text", "fields": { "keyword": { "type": "keyword" } } } } } }{% include copy-curl.html %}
-
데이터를 인덱싱해요:
# Index a parent document PUT /company/_doc/1 { "name": "Alice", "my_join_field": "employee" }{% include copy-curl.html %}
# Index child documents PUT /company/_doc/2?routing=1 { "description": "Complete the project", "my_join_field": { "name": "task", "parent": "1" } }{% include copy-curl.html %}
PUT /company/_doc/3?routing=1 { "description": "Prepare the report", "my_join_field": { "name": "task", "parent": "1" } }{% include copy-curl.html %}
PUT /company/_doc/4?routing=1 { "description": "Update project", "my_join_field": { "name": "task", "parent": "1" } }{% include copy-curl.html %}
-
inner_hits파라미터로 쿼리해요:GET /company/_search { "query": { "has_child": { "type": "task", "query": { "match": { "description": "project" } }, "inner_hits": { "from": 0, "size": 10, "sort": [ { "description.keyword": { "order": "asc" } } ], "name": "related_tasks" } } } }{% include copy-curl.html %}
다음은 예상 결과예요:
{
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits": [
{
"_index": "company",
"_id": "1",
"_score": 1,
"_source": {
"name": "Alice",
"my_join_field": "employee"
},
"inner_hits": {
"related_tasks": {
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "company",
"_id": "2",
"_score": null,
"_routing": "1",
"_source": {
"description": "Complete the project",
"my_join_field": {
"name": "task",
"parent": "1"
}
},
"sort": [
"Complete the project"
]
},
{
"_index": "company",
"_id": "4",
"_score": null,
"_routing": "1",
"_source": {
"description": "Update project",
"my_join_field": {
"name": "task",
"parent": "1"
}
},
"sort": [
"Update project"
]
}
]
}
}
}
}
]
}
}
inner_hits 사용의 장점
-
상세한 쿼리 결과
inner_hits를 사용하면 부모 문서의 검색 결과에서 바로 매칭되는 nested 문서나 자식 문서에 대한 상세 정보를 조회할 수 있어요. 추가 쿼리를 수행하지 않고도 매치의 맥락과 세부 사항을 파악할 수 있어서 특히 유용해요.활용 예시: 블로그 포스트 인덱스에서 댓글을 nested 객체로 저장했다고 해볼게요. 특정 댓글이 포함된 블로그 포스트를 검색할 때, 검색 조건에 맞는 관련 댓글을 포스트 정보와 함께 조회할 수 있어요.
-
최적화된 성능
inner_hits없이는 관련 문서를 가져오려면 여러 쿼리를 실행해야 할 수 있어요.inner_hits를 사용하면 이런 쿼리를 하나로 묶을 수 있어서 OpenSearch 서버로의 왕복 횟수가 줄고 전반적인 성능이 향상돼요.활용 예시: 이커머스 애플리케이션에서 상품을 부모 문서로, 리뷰를 자식 문서로 저장했다고 해볼게요.
inner_hits를 사용한 단일 쿼리 하나로 상품과 관련 리뷰를 함께 가져올 수 있어서 여러 번의 개별 쿼리를 피할 수 있어요. -
간소화된 쿼리 로직
parent/child 또는 nested 문서 로직을 하나의 쿼리로 결합하면 애플리케이션 코드가 단순해지고 복잡도도 줄어들어요. 쿼리 로직을 OpenSearch에서 중앙에서 관리함으로써 코드를 더 유지 보수하기 쉽고 일관성 있게 유지하는 데 도움이 돼요.
활용 예시: 채용 포털에서 채용 공고를 부모 문서로, 지원서를 nested 또는 자식 문서로 저장했다고 해볼게요. 하나의 쿼리에서 채용 공고와 특정 지원서를 함께 가져와서 애플리케이션 로직을 단순화할 수 있어요.
-
문맥에 맞는 관련성
inner_hits를 사용하면 어떤 nested 문서나 자식 문서가 쿼리 조건에 매칭되는지 정확히 보여주기 때문에 문맥에 맞는 관련성을 얻을 수 있어요. 결과의 관련성이 쿼리에 매칭되는 문서의 특정 부분에 달려 있는 애플리케이션에서는 이게 아주 중요해요.활용 예시: 고객 지원 시스템에서 티켓을 부모 문서로, 댓글이나 업데이트를 nested 또는 자식 문서로 저장했다고 해볼게요. 어떤 특정 댓글이 검색에 매칭되는지 파악하면 티켓 검색의 맥락을 더 잘 이해할 수 있어요.