Nested 필드 타입

Nested 필드 타입

nested 필드 타입은 object 필드 타입의 특수한 형태예요. 어떤 object 필드든 객체 배열을 받을 수 있어요. 배열 안의 각 객체는 동적으로 object 필드 타입으로 매핑되고 평탄화된 형식으로 저장돼요. 즉, 배열 안의 객체들은 개별 필드로 분해되고, 모든 객체에 걸친 각 필드의 값은 함께 저장돼요. 중첩 객체를 하나의 덩어리로 보존해서 그 객체에 검색을 수행해야 할 때는 때때로 nested 타입을 사용해야 해요.

출처: 문서

본문

평탄화된 형식 (Flattened form)

기본적으로 각 중첩 객체는 동적으로 object 필드 타입으로 매핑돼요. 어떤 object 필드든 객체 배열을 받을 수 있어요.

PUT testindex1/_doc/100
{ 
  "patients": [ 
    {"name" : "John Doe", "age" : 56, "smoker" : true},
    {"name" : "Mary Major", "age" : 85, "smoker" : false}
  ] 
}

이 객체들이 저장될 때 평탄화되어, 내부 표현은 각 필드에 대한 모든 값의 배열을 가지게 돼요.

{
    "patients.name" : ["John Doe", "Mary Major"],
    "patients.age" : [56, 85],
    "patients.smoker" : [true, false]
}

일부 쿼리는 이 표현에서 올바르게 작동해요. 75세보다 많은 환자 또는 흡연자를 검색하면 문서 100이 매칭되어야 해요.

GET testindex1/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "patients.smoker": true
          }
        },
        {
          "range": {
            "patients.age": {
              "gte": 75
            }
          }
        }
      ]
    }
  }
}

쿼리는 문서 100을 올바르게 반환해요.

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3616575,
    "hits" : [
      {
        "_index" : "testindex1",
        "_type" : "_doc",
        "_id" : "100",
        "_score" : 1.3616575,
        "_source" : {
          "patients" : [
            {
              "name" : "John Doe",
              "age" : "56",
              "smoker" : true
            },
            {
              "name" : "Mary Major",
              "age" : "85",
              "smoker" : false
            }
          ]
        }
      }
    ]
  }
}

반대로, 75세보다 많은 환자 그리고 흡연자를 검색하면 문서 100은 매칭되지 않아야 해요.

GET testindex1/_search 
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "patients.smoker": true
          }
        },
        {
          "range": {
            "patients.age": {
              "gte": 75
            }
          }
        }
      ]
    }
  }
}

하지만 이 쿼리는 여전히 문서 100을 잘못 반환해요. 개별 필드의 값 배열이 만들어지면서 나이와 흡연 여부 사이의 관계가 사라졌기 때문이에요.

Nested 필드 타입

중첩 객체는 별도의 문서로 저장되며, 부모 객체는 자식에 대한 참조를 가져요. 객체를 중첩으로 표시하려면 nested 필드 타입으로 매핑을 만들어요.

PUT testindex1
{
  "mappings" : {
    "properties": {
      "patients": { 
        "type" : "nested"
      }
    }
  }
}

그런 다음 nested 필드 타입이 있는 문서를 색인해요.

PUT testindex1/_doc/100
{ 
  "patients": [ 
    {"name" : "John Doe", "age" : 56, "smoker" : true},
    {"name" : "Mary Major", "age" : 85, "smoker" : false}
  ] 
}

다음 nested 쿼리를 사용해 75세보다 많은 환자 또는 흡연자를 검색할 수 있어요.

GET testindex1/_search
{
  "query": {
    "nested": {
      "path": "patients",
      "query": {
        "bool": {
          "should": [
            {
              "term": {
                "patients.smoker": true
              }
            },
            {
              "range": {
                "patients.age": {
                  "gte": 75
                }
              }
            }
          ]
        }
      }
    }
  }
}

쿼리는 두 환자를 올바르게 반환해요.

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.8465736,
    "hits" : [
      {
        "_index" : "testindex1",
        "_id" : "100",
        "_score" : 0.8465736,
        "_source" : {
          "patients" : [
            {
              "name" : "John Doe",
              "age" : 56,
              "smoker" : true
            },
            {
              "name" : "Mary Major",
              "age" : 85,
              "smoker" : false
            }
          ]
        }
      }
    ]
  }
}

다음 nested 쿼리를 사용해 75세보다 많은 환자 그리고 흡연자를 검색할 수 있어요.

GET testindex1/_search
{
  "query": {
    "nested": {
      "path": "patients",
      "query": {
        "bool": {
          "must": [
            {
              "term": {
                "patients.smoker": true
              }
            },
            {
              "range": {
                "patients.age": {
                  "gte": 75
                }
              }
            }
          ]
        }
      }
    }
  }
}

이전 쿼리는 예상대로 결과를 반환하지 않아요.

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

파라미터 (Parameters)

object 필드 타입이 받는 파라미터는 다음 표와 같아요. 모든 파라미터는 선택 사항이에요.

파라미터 설명
dynamic 객체에 새 필드를 동적으로 추가할 수 있는지 여부를 지정해요. 유효 값은 true, false, strict, strict_allow_templates, false_allow_templates이에요. 기본값은 true예요.
include_in_parent 자식 nested 객체의 모든 필드를 평탄화된 형식으로 부모 문서에도 추가할지 여부를 지정하는 불리언 값이에요. 기본값은 false예요.
include_in_root 자식 nested 객체의 모든 필드를 평탄화된 형식으로 루트 문서에도 추가할지 여부를 지정하는 불리언 값이에요. 기본값은 false예요.
properties 이 객체의 필드들이며, 지원되는 모든 타입이 될 수 있어요. dynamic이 true로 설정되어 있으면 이 객체에 새 속성을 동적으로 추가할 수 있어요.

다음 단계 (Next steps)

  • nested 필드에서의 조인 쿼리에 대해 알아보기.
  • inner hits 검색에 대해 알아보기.
  • disable objects 매핑 파라미터에 대해 알아보기.

더 알아보기 (Learn more)