본문 바로가기

Elasticsearch

[Elasticsearch] object vs nested 설명 및 예제

반응형

Elasticsearch object vs nested 

 

 

Obeject 

- 한 필드 안에 하위 필드를 넣는 Object

- es는 따로 배열타입의 필드를 따로 선언하지 않고 필드 타입 값만 동일하다면 배열로 그냥 넣으면 된다. -> Search 등 사용 방법은 동일하다.

ex. { "title": "A" } 

ex. { "title": ["A", "B"] }

 

Object mapping

"characters"라는 object를 가진 인덱스 test_index mapping하기 

PUT test_index
{
  "mappings": {
    "properties": {
      "characters": {
        "properties": {
          "name": {
            "type": "text"
          },
          "age": {
            "type": "byte"
          },
          "side": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

 

Object PUT data 

PUT test_index/_doc/1
{
  "characters": {
    "name": "gildong",
    "age": 30,
    "side": "hero"
  }
}

 

 

Object search

"." 을 이용해서 object 객체 안의 내용을 가져온다. 

GET test_index/_search
{
  "query": {
    "match": {
      "characters.name": "gildong"
    }
  }
}

결과 : 

{
  "took" : 677,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "characters" : {
            "name" : "gildong",
            "age" : 30,
            "side" : "hero"
          }
        }
      }
    ]
  }
}

 

object는 일반적인 Db에서 사용한 것과 비슷하다. 이제 object와 Nested의 차이를 알아보며 Nested 공부하기 

 

 

Object vs Nested 중요한 차이

object와 nested의 중요한 차이로는 2 가지가 있다. 첫 번째는 점수 계산 방식이고 두 번째는 Search 할 때의 쿼리 날리는 방식이다. 

 

Object 

먼저 아래 데이터를 입력하고 

PUT test_index/_doc/2
{
  "title": "Some fruits",
  "characters": [
    {
      "name": "greatest apples",
      "count": 2
    },
    {
      "name": "mangos",
      "count": 5
    }
    ]
}
PUT test_index/_doc/3
{
  "title": "Some fruits2",
  "characters": [
    {
      "name": "mangos",
      "count": 2
    },
    {
      "name": "bananas",
      "count": 5
    }
    ]
}

name = mangos, count = 5를 검색하고 싶다고 하면 방금 입력한 두 개의 데이터 중 title = "Some fruits"안에 banana, 5가 모두 하나의 Object 안에 들어가 있어서 왠지 some fruits가 검색 결과로 나올 것 같지만,,, 

 

Search Query 날리기

GET test_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "characters.name": "mangos" 
          }
        },
        {
          "match": {
            "characters.count": 5
          }
        }
      ]
    }
  }
}

결과 : 

"hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.5568054,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.5568054,
        "_source" : {
          "title" : "Some fruits2",
          "characters" : [
            {
              "name" : "mangos",
              "count" : 2
            },
            {
              "name" : "bananas",
              "count" : 5
            }
          ]
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.50179505,
        "_source" : {
          "title" : "Some fruits",
          "characters" : [
            {
              "name" : "greatest apples",
              "count" : 2
            },
            {
              "name" : "mangos",
              "count" : 5
            }
          ]
        }
      }
    ]
  }

결과는 "title"이 "Some fruits2"  두 번째 도큐먼트가 나왔다. 사실 Some fruites의 "greatest apples"를 -> "apples"로 변경하면 두 개의 도큐먼트 모두 동일한 스코어로 나온다. 예시를 위해 데이터 길이 값을 늘려 Some fruits의 score값이 Some fruits2 보다 점수 계산이 낮도록 만들었다. 즉, 하나의 객체 안에 내가 원하는 데이터가 모두 들어 있어도 elasticsearch object는 객체 하나씩 묶어 생각하지 않는 다는 것 !! 

 

그렇다면 mangos와 5를 모두 가지고 있는 객체 - Some fruits 가 먼저 나오도록 하려면 object들을 하나의 Object마다 감싸주어야 하는데 그것이 "nested"이다. 말 그대로 둥지가 틀어진 (?) 느낌

 

 

Nested

먼저 Nested를 사용하려면 Index Mappings 부터 설정해주어야 하기 때문에 이미 Mappings가 되어 있는 index라면 Mappings를 수정할 수 없으니 새로 index를 만들어 reindex해 주어야 한다. 

 

새롭게 index mappings 

* 일반 Object 매핑 시에는 mappings > properties > [field-name] > properties > [object-fields] 이렇게 되었지만 nested는 해당 Object Type을 "nested"로 명시해준다. 

PUT test_index
{
  "mappings": {
    "properties": {
      "characters": {
        "type": "nested",    // 여기만 추가됨 
        "properties": {
          "name": {
            "type": "text"
          },
          "count": {
            "type": "short"
          }
        }
      }
    }
  }
}

다시 위에서 넣은 데이터 그대로 넣어주고 검색 쿼리를 날린다. 

검색 쿼리를 날릴 때 또 objdect와 다른 점은 "nested" 입니다~ 라고 알려줘야 하는 것 ! "nested"를 작성하지 않으면 검색결과가 나오지 않는다. 

 

search query 

GET test_index/_search
{
  "query": {
    "nested": { // "query" 바로 아래에 "nested" 를 적어주고 "path" 설정
      "path": "characters",
      "query": {   // 다시 "query"를 적어주어야 함
        "bool": {
          "must": [
            {
              "match": {
                "characters.name": "mangos"
              }
            },
            {
              "match": {
                "characters.count": 5
              }
            }
            ]
        }
      }
    }
  }
}

object 일반 검색 쿼리보다 "nested"가 추가되었다. "path"는 객체 데이터의 필드명을 적어주고 다시 같은 뎁스에서 "query"문을 동일하게 작성해주면 된다. 

 

결과 : 

  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.7549126,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.7549126,
        "_source" : {
          "title" : "Some fruits",
          "characters" : [
            {
              "name" : "greatest apples",
              "count" : 2
            },
            {
              "name" : "mangos",
              "count" : 5
            }
          ]
        }
      }
    ]
  }

mangos & 5 가 한번에 담긴 객체가 있는 도큐먼트 Some fruits 만 검색되었다. Nested를 사용하면 path로 설정한 characters 안에 해당 검색하는 것이 모두 매칭되어야 결과로 반환되는 듯 하다. 

 

 

Object와 Nested의 시각화 

출처 : Elasticsearch 가이드 북 url 하단 참고

 

object 안의 필드 값들은 하나의 도큐먼트에 전부 포함되어 있고 nested는 필드 값이 각각 묶여서 분리되어 저장된다. 

 

 

 

Reference : https://esbook.kimjmin.net/07-settings-and-mappings/7.2-mappings/7.2.5-object-nested

 

7.2.5 Object 와 Nested - Elastic 가이드북

JSON 에서는 한 필드 안에 하위 필드를 넣는 object, 즉 객체 타입의 값을 사용할 수 있습니다. 보통은 한 요소가 여러 하위 정보를 가지고 있는 경우 object 타입 형태로 사용합니다. 다음은 movie 인덱

esbook.kimjmin.net

반응형