중첩(nested) 쿼리

중첩(nested) 쿼리

nested 쿼리는 다른 쿼리를 감싸서 중첩(nested) 필드를 검색하는 래퍼 역할을 해요. 중첩 필드 객체는 마치 별도의 문서로 인덱싱된 것처럼 검색됩니다. 객체가 검색과 일치하면 nested 쿼리는 루트 레벨의 부모 문서를 반환해요.

출처: 문서

본문

예제 (Example)

nested 쿼리를 실행하려면 먼저 인덱스에 중첩 필드가 있어야 해요.

중첩 필드를 포함하는 예제 인덱스를 구성하려면 다음 요청을 보내세요.

PUT /testindex 
{
  "mappings": {
    "properties": {
      "patient": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          }
        }
      }
    }
  }
}

다음으로 예제 인덱스에 문서를 인덱싱해요.

PUT /testindex/_doc/1
{
  "patient": {
    "name": "John Doe",
    "age": 56
  }
}

중첩 patient 필드를 검색하려면 쿼리를 nested 쿼리로 감싸고 중첩 필드의 경로(path)를 제공해요.

GET /testindex/_search
{
  "query": {
    "nested": {
      "path": "patient",
      "query": {
        "match": {
          "patient.name": "John"
        }
      }
    }
  }
}

쿼리는 일치하는 문서를 반환해요.

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "testindex",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "patient": {
            "name": "John Doe",
            "age": 56
          }
        }
      }
    ]
  }
}

내부 히트 가져오기 (Retrieving inner hits)

쿼리와 일치한 내부 히트를 반환하려면 inner_hits 파라미터를 제공해요.

GET /testindex/_search
{
  "query": {
    "nested": {
      "path": "patient",
      "query": {
        "match": {
          "patient.name": "John"
        }
      },
      "inner_hits": {}
    }
  }
}

응답에는 추가적인 inner_hits 필드가 포함돼요. _nested 필드는 내부 히트가 발생한 특정 내부 객체를 식별해요. 여기에는 중첩 히트와 _source 내 위치에 대한 상대적인 오프셋(offset)이 담겨 있어요. 정렬과 점수 계산 때문에 inner_hits 안의 히트 객체 위치는 중첩 객체의 원래 위치와 다른 경우가 많습니다.

기본적으로 inner_hits 안의 히트 객체 _source는 _nested 필드에 대해 상대적으로 반환돼요. 이 예제에서 inner_hits 안의 _source는 전체 patient 객체를 포함하는 최상위 _source와 달리 name과 age 필드를 포함합니다.

{
  "took": 38,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "testindex",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "patient": {
            "name": "John Doe",
            "age": 56
          }
        },
        "inner_hits": {
          "patient": {
            "hits": {
              "total": {
                "value": 1,
                "relation": "eq"
              },
              "max_score": 0.2876821,
              "hits": [
                {
                  "_index": "testindex",
                  "_id": "1",
                  "_nested": {
                    "field": "patient",
                    "offset": 0
                  },
                  "_score": 0.2876821,
                  "_source": {
                    "name": "John Doe",
                    "age": 56
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

매핑에서 _source 필드를 구성해 _source 반환을 비활성화할 수도 있어요. 자세한 내용은 "Source"를 참고하세요.

내부 히트를 가져오는 방법에 대한 자세한 내용은 "Inner hits"를 참고하세요.

다중 레벨 중첩 쿼리 (Multi-level nested queries)

다중 레벨 중첩 쿼리를 사용하면 다른 중첩 객체 안에 중첩 객체가 있는 문서를 검색할 수 있어요. 이 예제에서는 계층의 각 레벨에 대해 nested 쿼리를 지정해 여러 레이어의 중첩 필드를 쿼리해 보겠어요.

먼저 다중 레벨 중첩 필드가 있는 인덱스를 만들어요.

PUT /patients
{
  "mappings": {
    "properties": {
      "patient": {
        "type": "nested",
        "properties": {
          "name": {
            "type": "text"
          },
          "contacts": {
            "type": "nested",
            "properties": {
              "name": {
                "type": "text"
              },
              "relationship": {
                "type": "text"
              },
              "phone": {
                "type": "keyword"
              }
            }
          }
        }
      }
    }
  }
}

다음으로 예제 인덱스에 문서를 인덱싱해요.

PUT /patients/_doc/1
{
  "patient": {
    "name": "John Doe",
    "contacts": [
      {
        "name": "Jane Doe",
        "relationship": "mother",
        "phone": "5551111"
      },
      {
        "name": "Joe Doe",
        "relationship": "father",
        "phone": "5552222"
      }
    ]
  }
}

중첩 patient 필드를 검색하려면 다중 레벨 중첩 쿼리를 사용해요. 다음 쿼리는 contact 정보에 relationship이 mother인 Jane이라는 사람이 포함된 환자를 검색해요.

GET /patients/_search
{
  "query": {
    "nested": {
      "path": "patient",
      "query": {
        "nested": {
          "path": "patient.contacts",
          "query": {
            "bool": {
              "must": [
                { "match": { "patient.contacts.relationship": "mother" } },
                { "match": { "patient.contacts.name": "Jane" } }
              ]
            }
          }
        }
      }
    }
  }
}

쿼리는 이 세부 정보와 일치하는 contact 항목을 가진 환자를 반환해요.

{
  "took": 14,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3862942,
    "hits": [
      {
        "_index": "patients",
        "_id": "1",
        "_score": 1.3862942,
        "_source": {
          "patient": {
            "name": "John Doe",
            "contacts": [
              {
                "name": "Jane Doe",
                "relationship": "mother",
                "phone": "5551111"
              },
              {
                "name": "Joe Doe",
                "relationship": "father",
                "phone": "5552222"
              }
            ]
          }
        }
      }
    ]
  }
}

파라미터 (Parameters)

다음 표는 nested 쿼리가 지원하는 모든 최상위 파라미터를 나열해요.

  • path (필수): 검색하려는 중첩 객체로의 경로를 지정해요.
  • query (필수): 지정된 path 안의 중첩 객체에 실행할 쿼리예요. 중첩 객체가 쿼리와 일치하면 루트 부모 문서가 반환돼요. nested_object.subfield 같은 점 표기법(dot notation)으로 중첩 필드를 검색할 수 있어요. 다중 레벨 중첩은 지원되며 자동으로 감지됩니다. 따라서 다른 nested 쿼리 안의 내부 nested 쿼리는 루트 대신 올바른 중첩 레벨에 자동으로 매칭돼요.
  • ignore_unmapped (선택): 매핑되지 않은 path 필드를 무시하고 오류 대신 문서를 반환하지 않을지 나타내요. 일부 인덱스에 path 필드가 없을 수 있는 여러 인덱스를 쿼리할 때 이 파라미터를 제공할 수 있어요. 기본값은 false예요.
  • score_mode (선택): 일치하는 내부 문서의 점수가 부모 문서의 점수에 어떻게 영향을 주는지 정의해요. 유효한 값은 다음과 같아요.
    • avg: 일치하는 모든 내부 문서의 평균 관련성 점수를 사용해요.
    • max: 일치하는 내부 문서 중 가장 높은 관련성 점수를 부모에 부여해요.
    • min: 일치하는 내부 문서 중 가장 낮은 관련성 점수를 부모에 부여해요.
    • sum: 일치하는 모든 내부 문서의 관련성 점수를 합산해요.
    • none: 내부 문서의 관련성 점수를 무시하고 부모 문서에 0점을 부여해요.
    • 기본값은 avg예요.
  • inner_hits (선택): 제공하면 쿼리와 일치한 기본 히트를 반환해요.

다음 단계 (Next steps)

  • 내부 히트를 가져오는 방법에 대해 자세히 알아보세요.

더 알아보기 (Learn more)