LanguageManual Transform

LanguageManual Transform

Hive는 커스텀 매퍼(mapper)와 리듀서(reducer)를 데이터 스트림에 끼워 넣을 수 있는 TRANSFORM 절을 제공해요. external 스크립트를 이용해 복잡한 변환 로직을 실행할 수 있습니다.

출처: 문서

본문

Transform/Map-Reduce 문법

Hive 언어가 기본 지원하는 기능을 이용해 커스텀 매퍼와 리듀서를 데이터 스트림에 끼워 넣을 수 있어요. 예를 들어 커스텀 매퍼 스크립트 - map_script - 와 커스텀 리듀서 스크립트 - reduce_script - 를 실행하려면 TRANSFORM 절을 사용해 매퍼/리듀서 스크립트를 임베드하는 다음 명령을 내리면 됩니다.

기본적으로 컬럼은 사용자 스크립트에 전달되기 전에 STRING으로 변환되고 TAB으로 구분돼요. 마찬가지로 모든 NULL 값은 빈 문자열과 구분하기 위해 리터럴 문자열 \N으로 변환됩니다. 사용자 스크립트의 표준 출력은 TAB으로 구분된 STRING 컬럼으로 취급되고, \N만 포함한 셀은 NULL로 재해석된 뒤 결과 STRING 컬럼이 테이블 선언에 지정된 데이터 타입으로 평소 방식대로 캐스팅돼요. 사용자 스크립트는 표준 에러로 디버그 정보를 출력할 수 있으며, 이는 hadoop 태스크 상세 페이지에 표시됩니다. 이 기본값들은 ROW FORMAT ...으로 재정의할 수 있어요.

Windows에서는 스크립트 이름 대신 "cmd /c your_script"를 사용하세요.

경고(Warning)

변환 전에 STRING 컬럼을 살균(sanitize)하는 건 사용자 책임이에요. STRING 컬럼에 탭이 있으면, identity transformer로 시작값을 그대로 되돌릴 수 없어요! 도움이 필요하면 REGEXP_REPLACE를 참고해 탭을 TRANSFORM() 호출로 들어가기 전에 다른 문자로 바꾸세요.

경고(Warning)

형식상 *MAP ...*와 *REDUCE ...*는 *SELECT TRANSFORM( ... )*의 구문 변환(syntactic transformation)이에요. 다시 말해 쿼리를 읽는 사람에게 주석이나 메모 역할을 합니다. 조심하세요: 이 키워드의 사용은 위험할 수 있어요 (예: "REDUCE"를 입력한다고 reduce 단계가 강제로 발생하지 않고, "MAP"을 입력한다고 새 map 단계가 강제로 발생하지 않습니다!)

Sort By / Cluster By / Distribute By와 Larry Ogrodnek의 블로그 글도 함께 보세요.

clusterBy: CLUSTER BY colName (',' colName)*
distributeBy: DISTRIBUTE BY colName (',' colName)*
sortBy: SORT BY colName (ASC | DESC)? (',' colName (ASC | DESC)?)*

rowFormat
  : ROW FORMAT
    (DELIMITED [FIELDS TERMINATED BY char] 
               [COLLECTION ITEMS TERMINATED BY char]
               [MAP KEYS TERMINATED BY char]
               [ESCAPED BY char]
               [LINES SEPARATED BY char]
     | 
     SERDE serde_name [WITH SERDEPROPERTIES 
                            property_name=property_value, 
                            property_name=property_value, ...])

outRowFormat : rowFormat
inRowFormat : rowFormat
outRecordReader : RECORDREADER className

query:
  FROM (
    FROM src
    MAP expression (',' expression)*
    (inRowFormat)?
    USING 'my_map_script'
    ( AS colName (',' colName)* )?
    (outRowFormat)? (outRecordReader)?
    ( clusterBy? | distributeBy? sortBy? ) src_alias
  )
  REDUCE expression (',' expression)*
    (inRowFormat)?
    USING 'my_reduce_script'
    ( AS colName (',' colName)* )?
    (outRowFormat)? (outRecordReader)?

  FROM (
    FROM src
    SELECT TRANSFORM '(' expression (',' expression)* ')'
    (inRowFormat)?
    USING 'my_map_script'
    ( AS colName (',' colName)* )?
    (outRowFormat)? (outRecordReader)?
    ( clusterBy? | distributeBy? sortBy? ) src_alias
  )
  SELECT TRANSFORM '(' expression (',' expression)* ')'
    (inRowFormat)? 
    USING 'my_reduce_script'
    ( AS colName (',' colName)* )?
    (outRowFormat)? (outRecordReader)?

SQL 표준 기반 인증은 TRANSFORM을 허용하지 않음

Hive 0.13.0 이상 릴리스에서 SQL 표준 기반 인증(SQL standard based authorization)을 구성하면 TRANSFORM 절은 허용되지 않아요 (HIVE-6415).

TRANSFORM 예제

예제 #1:

  FROM (
    FROM pv_users
    MAP pv_users.userid, pv_users.date
    USING 'map_script'
    AS dt, uid
    CLUSTER BY dt) map_output
  INSERT OVERWRITE TABLE pv_users_reduced
    REDUCE map_output.dt, map_output.uid
    USING 'reduce_script'
    AS date, count;
  FROM (
    FROM pv_users
    SELECT TRANSFORM(pv_users.userid, pv_users.date)
    USING 'map_script'
    AS dt, uid
    CLUSTER BY dt) map_output
  INSERT OVERWRITE TABLE pv_users_reduced
    SELECT TRANSFORM(map_output.dt, map_output.uid)
    USING 'reduce_script'
    AS date, count;

예제 #2:

  FROM (
    FROM src
    SELECT TRANSFORM(src.key, src.value) ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.TypedBytesSerDe'
    USING '/bin/cat'
    AS (tkey, tvalue) ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.TypedBytesSerDe'
    RECORDREADER 'org.apache.hadoop.hive.contrib.util.typedbytes.TypedBytesRecordReader'
  ) tmap
  INSERT OVERWRITE TABLE dest1 SELECT tkey, tvalue

스키마 없는 Map-reduce 스크립트(Schema-less Map-reduce Scripts)

USING my_script 뒤에 AS 절이 없으면 Hive는 스크립트 출력이 2부분으로 구성된다고 가정해요: 첫 번째 탭 앞의 key와, 첫 번째 탭 뒤의 나머지 value입니다. 참고로 이는 AS key, value를 지정하는 것과 다릅니다. 그 경우 탭이 여러 개면 value는 첫 탭과 두 번째 탭 사이의 부분만 포함하기 때문이에요.

스크립트의 출력 스키마를 지정하지 않고 CLUSTER BY key를 직접 할 수 있다는 점도 참고하세요.

  FROM (
    FROM pv_users
    MAP pv_users.userid, pv_users.date
    USING 'map_script'
    CLUSTER BY key) map_output
  INSERT OVERWRITE TABLE pv_users_reduced
    REDUCE map_output.key, map_output.value
    USING 'reduce_script'
    AS date, count;

TRANSFORM 출력의 타입 지정(Typing the output of TRANSFORM)

스크립트의 출력 필드는 기본적으로 문자열로 타입이 정해져요. 예를 들어:

  SELECT TRANSFORM(stuff)
  USING 'script'
  AS thing1, thing2

다음 문법으로 바로 캐스팅할 수 있어요:

  SELECT TRANSFORM(stuff)
  USING 'script'
  AS (thing1 INT, thing2 INT)

더 알아보기 (Learn more)

TRANSFORM은 Hive 외부의 스크립트로 유연한 처리를 할 수 있게 해주지만, 탭이나 NULL 처리에 주의해야 해요. CLUSTER BY/DISTRIBUTE BY/SORT BY와 함께 사용해 데이터 분배를 제어할 수 있습니다.