ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Elasticsearch] 핵심 개념 - 매핑 타입이 사라진 이유
    IT 발자취.../Elastic Stack 2020. 4. 9. 01:17

    https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html

     

    Removal of mapping types | Elasticsearch Reference [7.6] | Elastic

    Indices created in Elasticsearch 7.0.0 or later no longer accept a _default_ mapping. Indices created in 6.x will continue to function as before in Elasticsearch 6.x. Types are deprecated in APIs in 7.0, with breaking changes to the index creation, put map

    www.elastic.co

    Elasticsearch 7.0.0 버전부터 _default_ 매핑이 더이상 제공되지 않는다. 6.x 버전 이전에 만들어진 인덱스는 6.x버전에서는 정상적으로 동작 할 것이다.

    7.0부터는 인덱스 생성, put /get mapping, put /get template와 get field mapping API등 커다란 변화와 함께 더이상 타입이 사용되지 않는다.

    mapping type이란?

    elasticsearch가 처음 릴리즈될 때부터 각 도큐먼트는 싱글 인덱스에 저장되고 싱글 매핑 타입에 할당되었다.

    매핑 타입은 인덱스된 개체 또는 도큐먼트의 타입들을 보여주기 위해서 사용되었다.

    > 예를 들면, twitter 인스턴스는 반드시 user 타입 tweet 타입을 가져야 한다.

     

    각 매핑 타입은 각자의 필드를 가질 수 있고, user 타입은 반드시 full_name, user_name, email 필드를 가진다. tweet 타입 user타입에서 user_name을 가지는 것 처럼 content 필드, tweeted_at 필드를 가질 수 있다.

     

     도큐먼트 타입명이 포함된 _type 메타 필드가 있으며, URL에 타입명을 지정하여 검색을 하나 이상의 유형으로 제한할 수 있다.

    GET twitter/user,tweet/_search
    {
      "query": {
        "match": {
          "user_name":"kimchy"
        }
      }
    }

    _type 필드는 도큐먼트의 _id와 결합되어 _uid 필드를 생성하므로, 동일한 _id를 가진 다른 타입의 도큐먼트가 하나의 index에 존재할 수 있게 되었다.

     

    매핑 타입은 도큐먼트들 사이에서 parent-child 관계를 형성하는데 사용되었다. 그래서 question 타입의 도큐먼트는 answer 타입의 도큐먼트의 부모가 될 수 있었다.

     

    (중요) 왜 매핑 타입이 사라졌는가?

    다른 블로그를 보면 Elasticssearch 구조를 쉽게 설명하기 위해서 RDB를 빗대어 이야기하는데, 이는 잘못된 설명일 수 있다.

    기본적으로 "index"를 RDB에서 "database"와 유사하다고 말했고, "type"은 "table"이라고 했었다.

     

    이것은 잘못된 가정으로 이어진 나쁜 유추였다. SQL 데이터베이스에서 테이블들은 서로 독립적이다.

    한 테이블의 열은 다른 테이블의 같은 이름을 가진 열과 관련이 없다. 이는 매핑 타입의 필드 경우에는 해당되지 않는다.

    엘라스틱서치 인덱스에서 다른 매핑 타입에서 같은 이름을 가진 필드는 동일한 Lucene 필드를 내부적으로 지원합니다.

     

    위의 예시를 보면, user 타입 내부의 user_name 필드은 tweet 타입의 user_name 필드와 적확히 같은 필드로 저장된다. 그리고 user_name 필드는 반드시 두 타입 모두에 같은 매핑 (정의)를 가져야만 한다.

     

    예를 들면 같은 인덱스 내부에서 어느 타입의 date 필드와 다른 타입의 boolean 필드 삭제하길 원할 경우 좋지 않은 결과를 야기한다.

     

    게다가, 동일한 인덱스 내부에서 공통 부분 중 없거나 소수의 필드를 가진 다른 entities를 저장하면 데이터가 희소해지고 (spare data) 도큐먼트를 효율적으로 압축하는 Lucene의 기능을 방해한다.

     

    이러한 이유로 엘라스틱서치에서는 매핑 타입이라는 개념을 삭제하기로 결정 했다.

     

    매핑 타입의 대안점

    도큐먼트 타입 별 인덱스

    첫번째 대안점으로는 도큐먼트 타입별로 인덱스를 가지는 것이다. tweets users를 하나의 twitter 인덱스에 저장하는 대신에, tweets tweets 인덱스에, users users 인덱스에 저장한다.

    인덱스들은 서로 완전히 독립되어 인덱스 사이에서 필드 타입의 충돌이 생기지 않는다.

     

    이 접근법에는 두가지의 이점이 있다

    1. 데이터는 밀도가 높기 때문에 Lucene에 사용된 압축 기술을 활용할 수 있다.
    2. 전문 검색에서 점수를 매기는데 사용되는 통계라는 용어는 동일한 색인의 모든 도큐먼트가 단일 엔티티를 나타내기 때문에 더 정확합니다.

    각 인덱스는 도큐먼트의 수에 따라 적절한 크기를 가질 수 있고, 이것은 다음을 의미한다.

    • users를 위해서는 더 작은 수의  primary 샤드를 생성
    • tweets을 위해서는 더 큰 수의 primary 샤드 생성

    Custom type field

    클러스터에 존재할 수 있는 기본 샤드 수에는 제한이 있으므로 수천 개의 문서 수집을 위해 전체 샤드를 낭비하고 싶지 않을 수 있다.

    이 경우, 예전의 _type과 유사한 기능을 가진 고유의 Custom type field를 구현할 수 있다.

    위의 user/tweet 예제를 보자. 원래, workflow는 아래와 같았다.

    PUT twitter
    {
      "mappings": {
        "user": {
          "properties": {
            "name": { "type": "text" },
            "user_name": {"type":"keyword"},
            "email" : {"type":"keyword"}
          }
        },
        "tweet": {
          "properties": {
            "content" : {"type":"text"},
            "user_name" : {"type":"keyword"},
            "twetted_at" : {"type":"date"},
          }
        }
      }
    }
     
    PUT twitter/user/kimchy
    {
      "name" : "Shay Banon",
      "user_name" : "kimchy",
      "email": "shay@kimchy.com"
    }
     
    PUT twitter/tweet/1
    {
      "user_name": "kimchy",
      "tweeted_at" : "2017-10-24T09:00:00Z",
      "content":"Types are going away"
    }
     
    GET twitter/tweet/_search
    {
      "query": {
         "match" : {
           "user_name" : "kimchy"
          }
       }
    }

    같은 내용을 커스텀 type 필드를 추가하여 사용할 수 있다.

    PUT twitter
    {
      "mappings" : {
        "_doc": {
          "properties": {
            "type":{"type":"keyword"},                           -- 1
            "name":{"type":"text"},
            "user_name":{"type":"keyword"},
            "email":{"type":"keyword"},
            "content":{"type":"text"},
            "tweeted_at":{"type":"date"},
          }
        }
      }
    }
     
    PUT twitter/_doc/user_kimchy
    {
      "type":"user",                                             -- 2
      "name":"Shay Banon",
      "user_name": "kimchy",
      "email": "shay@kimchy.com"
    }
     
    PUT twitter/_doc/tweet_1
    {
      "type":"tweet",                                            -- 3
      "user_name":"kimchy",
      "tweeted_at":"2017-10-24T09:00:00Z",
      "content":"Types are going away"
    }
     
    GET twitter/_search
    {
      "query": {
        "bool": {
          "must": {
            "match" : {
              "user_name":"kimchy"
            }
          },
          "filter" : {
            "match" : {
              "type": "tweet"                                    -- 4
            }
          }
        }
      }
    }
    1. 명시적 type 필드 암시적 _type 필드를 대신한다.
    2. user 타입 명시
    3. tweet  타입 명시
    4. filter로 색인

    매핑 타입 없는 부모 / 자식

    이전에, 하나의 매핑 타입을 상위로, 하나 이상의 다른 매핑 타입을 하위로 작성하여 부모-자식 관계를 표현 했다.

    타입이 사라져 더 이상 이러한 문법을 사용할 수 없게 되었다. 

     

    도큐먼트 사이의 관계를 표현하는 방식이 새로운 조인 필드를 사용하는 것으로 변경된점을 제외하면, 이전 처럼 부모-자식 관계는 계속 작동 한다. 

     

    매핑 타입을 제거하는 계획

    매핑 타입 제거는 중요한 이슈라서 피해를 최소화하는 계획을 세움

    Elasticsearch 5.6.0

    • 인덱스에 index.mapping.single_type: true 로 설정하는 것으로 인덱스별 단일 타입이 가능하게 한 기능하게함
    • 6.0 부터는 강제함
    • 부모 - 자식 표현을 위해 인덱스에 조인 필드를 사용가능하게함

    Elasticsearch 6.x

    • 5.x 에서 생성된 인덱스들을 6.x에서도 5.x 버전에서 사용했던 것과 동일하게 사용할 수 있게함
    • 6.x에서 생성된 인덱스들만 인덱스별 단일 타입으로 허용하게함
      • 타입명으로 아무것이나 사용가능하나 오직 하나만 생성 가능
      • 선호되는 타입명은 _doc 이며 인덱스 API는 7.0에서 가지는 경로와 같은 경로를 가짐 
        PUT {index}/_doc/{id} and POST {index}/_doc
    • uid필드를 형성하기 위해 더 이상 _type 명과 _id를 결합할 필요가 없어짐
    • 새로운 인덱스들은 더 이상 예전의 부모-형제 관계를 지원하지 않으며, join field로 대신됨
    • _default_ 매핑은 더 이상 사용되지 않음
    • 6.8버전에서, 인덱스 생성, 인덱스 템플릿, 그리고 매핑 API는 타입명을 requests와 responses에 포함시켜야만하는지 여부를 확인하는 query string parameter (include_type_name)를 지원함
      • 기본값은 true이며, 7.0버전으로 업그레이드 준비를 위해 명시적인 값으로 설정해야만 한다.
      • include_type_name을 설정하지 않으면, deprecation warning을 발생한다.
      • 명시적 타입을 사용하지않은 인덱스들은 dummy 타입인 _doc으로 사용됨

    Elasticsearch 7.x

    • request의 특정 타입은 더이상 사용되지 않음.
      • 예를 들면, 도큐먼트 인덱싱은 더이상 도큐먼트 타입을 요구하지 않음
      • 새로운 인덱스 API는 id를 명시적을 표현할 경우에는 PUT {index}/_doc/{id} ,id를 자동으로 생성하기를 바랄 경우 POST {index}/_doc과 같음
      • 7.0에서 _doc은 경로의 영구적인 경로이며, 도큐먼트 타입 대신에 엔드 포인트명을 표현한다.
    • 인덱스 생성, 인덱스 템플릿, 매핑 API에서 include_type_name 은 기존적으로 false이다.
    • _default_ 매핑 타입이 사라졌다.

    Elasticsearch 8.x

    • 요청에 타입을 지정하는 것은 더 이상 지원되지 않는다.
    • include_type_name 파라미터가 사라졌다

    댓글

Designed by Gintire