본문 바로가기
IT/Elasticsearch

Elasticsearch Mappings - Nested type

by 최고영회 2022. 6. 23.
728x90
반응형
SMALL

Elasticsearch는 기본적으로 동적매핑을 지원하기 때문에 index 에 doc를 추가하면 자동으로 매핑이 생성된다.

하지만 보다 더 디테일하게 작업하기 위해서는 미리 매핑 정보를 설정해 두는 것이 좋다. 

개발/테스트를 하다보면 mapping 정보를 추가/수정/삭제 해 보면서 문제를 해결하는 경우가 많다. 

mapping 정보는 한번 추가하면 수정이 불가능하기 때문에 (다른 index를 만들고 기존 index data를 다시 insert 하고 index name 을 변경하는 방법으로는 가능) 초기 설계가 중요하다. 

 

mapping 확인 

GET {index_name}/_mapping

 

mapping 정의 

PUT {index_name}

{
  "mappings": {
    "properties": {
      "logTime": {
        "type": "date", 
        "format": "yyyyMMddHHmmss.SSS"
      }, 
      "filed_name": {
        "type": "integer"
      },
      "privacyTypes": {
        "type": "nested",
        "properties": {
          "no": {
            "type": "integer"
          },
          "name": {
            "type": "keyword"
          },
          "count": {
            "type": "integer"
          },
          "data": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

 

문자열을 처리하는 type 은 text 와 keyword 가 있는데 

text 는 문자열을 term 단위로 쪼개어 inverted index 구조를 만들기 때문에 보통 full-text 검색에 사용할 문자열을 text로 지정한다. 

keyword 는 입력된 문자열을 하나의 token 으로 저장하기 때문에 보통 aggregation 이나 sorting 에 사용할 문자열을 keyword로 지정한다. 

 

위 예제에서 눈여겨 볼것은 privacyTypes 의 nested type 이다. 

아래와 같은 document 에서 privacyTypeList 처럼 json 형태로 저장하는 경우 

{
  "reqTime": "xxxx",
  "logTime": "xxxx",
  "bizNo": 1,
  "bizName": "xxx",
  "user": {
    // user information
  }
  "privacyTypes": [
    {
      "no": 1,
      "name": "jumin",
      "count": 12,
      "data": "xxxx"
    },
    {
      "no": 2,
      "name": "cellphone",
      "count": 8,
      "data": "xxxx"
    }
]

"privacyTypes.name" 과 같은 방법으로 query 할 수 있고 aggregation 할 수 있다. 

 

만약 위와 같이 object type field 에 여러개의 object 값들이 서로 다른 역색인구조를 갖도록 하려면 

nested 타입으로 지정해야 한다. 

nested 타입으로 지정하면 반드시 nested 쿼리(path 라는 옵션으로 nested로 정의된 필드를 먼저 명시하고 그 안에 쿼리 수행)를 사용해야 한다. 

nested 필드의 내부에 있는 값들은 모두 별개의 document로 취급이 된다. 

 

업무정보(bizNo)로 group by 하고 각 업무안에서 사용된 개인정보유형별 count 의 집계를 구할 경우 아래와 같이 nested 를 이용하여 aggregation 할 수 있다. 

{
    "query":{
        "bool":{
            "filter":[
                {
                    "range":{
                        "reqTime":{
                            "gt": "20220526000000"
                        }
                    }
                }
            ]
        }
    },
    "size":0,
    "aggs": {
      "by_biz" : {
        "terms": {
          "field": "bizNo"
        },
        "aggs" : {
          "privacy_types": {
              "nested": {
                  "path": "privacyTypeList"
              }, 
              "aggs": {
                  "privacyTypeNameTerms": {
                      "terms": {
                          "field": "privacyTypeList.name"
                      },
                       "aggs": {
                            "count": {
                                "sum": {
                                    "field": "privacyTypeList.count"
                                }
                            }
                        }
                  }
              } 
          }
        }
      }
    }
}
"buckets": [
    {
        "key": 1,
        "doc_count": 2,
        "privacy_types": {
            "doc_count": 4,
            "privacyTypeNameTerms": {
                "doc_count_error_upper_bound": 0,
                "sum_other_doc_count": 0,
                "buckets": [
                    {
                        "key": "주민등록번호",
                        "doc_count": 2,
                        "count": {
                            "value": 18.0
                        }
                    },
                    {
                        "key": "핸드폰",
                        "doc_count": 2,
                        "count": {
                            "value": 136.0
                        }
                    }
                ]
            }
        }
    }
]

 

728x90
반응형
LIST