본문 바로가기
WIKI 기술 지식 베이스

Retrieve inner hits

원문 보기 위키 갱신

출처: 문서

본문

inner hits 조회하기

OpenSearch에서 nested 객체나 parent-join을 사용해 검색을 수행하면, 그 밑에 있는 히트(nested 내부 객체 또는 자식 문서)는 기본적으로 숨겨져 있어요. 검색 쿼리에 inner_hits 파라미터를 사용하면 inner hits를 조회할 수 있어요.

inner_hits는 다음 기능과도 함께 사용할 수 있어요:

nested 객체에서의 inner hits

nested 객체를 사용하면 객체 배열을 인덱싱하면서 같은 문서 안에서 그 관계를 유지할 수 있어요. 다음 예제 요청은 inner_hits 파라미터를 사용해 내부에 숨겨진 inner hits를 조회해요.

  1. nested 객체가 포함된 인덱스 매핑을 생성해요:

    PUT /my_index
    {
      "mappings": {
        "properties": {
          "user": {
            "type": "nested",
            "properties": {
              "name": { "type": "text" },
              "age": { "type": "integer" }
            }
          }
        }
      }
    }
    

    {% include copy-curl.html %}

  2. 데이터를 인덱싱해요:

    POST /my_index/_doc/1
    {
      "group": "fans",
      "user": [
        {
          "name": "John Doe",
          "age": 28
        },
        {
          "name": "Jane Smith",
          "age": 34
        }
      ]
    }
    

    {% include copy-curl.html %}

  3. 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로 검색해요.

  1. parent-join 필드가 있는 인덱스를 생성해요:

    PUT /my_index
    {
      "mappings": {
        "properties": {
          "my_join_field": {
            "type": "join",
            "relations": {
              "parent": "child"
            }
          },
          "text": {
            "type": "text"
          }
        }
      }
    }
    

    {% include copy-curl.html %}

  2. 데이터를 인덱싱해요:

    # 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 %}

  3. 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와 함께 사용하는 방법을 보여줘요.

  1. 다음 매핑으로 인덱스를 생성해요:

    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 %}

  2. 데이터를 인덱싱해요:

    # 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 %}

  3. 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 파라미터

  1. 다음 매핑으로 인덱스를 생성해요:

    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 %}

  2. 데이터를 인덱싱해요:

    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 %}

  3. 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 파라미터

  1. 다음 매핑으로 인덱스를 생성해요:

    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 %}

  2. 데이터를 인덱싱해요:

    # 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 %}

  3. 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 또는 자식 문서로 저장했다고 해볼게요. 어떤 특정 댓글이 검색에 매칭되는지 파악하면 티켓 검색의 맥락을 더 잘 이해할 수 있어요.

다음 단계

더 알아보기 (Learn more)