RHive 튜토리얼 4 - UDF, UDAF, UDTF 함수RHive - advanced functionsRHive는 기초함수(basic functions), HDFS, map/reduce를 위한 apply 계열, 그리...
이같은 assign이 과정이 필요한 이유는 R에서 작성한 코드와 벡터, 매트릭스,데이터프레임, 펑션들 중어느 것이 분산환경에서 사용될 것인지 지정(assign)해 주는 작업이 필요하기 때문이다.rhive.assign이 ...
 	  rhive.assign("sum3values",	  sum3values)	  [1]	  TRUE아래와 같이 함수가 아닌 객체를 지정할 수도 있다.coef1	  <-­‐	  3.141593	  rhive.assig...
sum3values	  <-­‐	  function(a,b,c)	  {	    	  	  a	  +	  b	  +	  c	    }	    	  	    rhive.assign("sum3values",	  sum3val...
sumAllColumns.partial	  <-­‐	  function(values)	  {	  	  	  values	  }	  	  	  sumAllColumns.merge	  <-­‐	  function(prev,...
이렇게 배포한 R 펑션과 객체들을 실제로 사용하기 위해서는 rhive.query에 전달하는SQL구문에 기술해야만 사용할 수 있다.다음에 나오는 예제들을 통해 배포한 함수들을 어떻게 작동시키는지 배우게 될 것이다.RHiv...
이제 이 COUNT 함수와 유사한 일을 하는 함수를 R로 작성해서 동작시키는 방법을소개할 것이다.우선 아래와 같이 USArrests 테이블의 description을 확인해 본다.rhive.desc.table("USArr...
 	  	  	  	  	  	  	  	  	  rowname	  urbanpop	  crimes	  1	  	  	  	  	  	  	  	  	  Alabama	  	  	  	  	  	  	  58	  	  ...
여기서 주의할 것은 R()펑션이 return하는 값은 하나 뿐이라는 것이다.즉, 위의 예제의 SQL구문 결과를 보면 R() 펑션은 결과적으로 하나의 새로운column값을 만드는 것을 알 수 있다.사실 위의 예제에서 사용...
하지만RHive는 이것을 R언어를 이용해 작성할 수 있도록 지원하고 있다.설명하지는 않았지만 앞서의 예제들에서 여러분은 sumAllcolumns라는 4개의 UDAF펑션을 이미 보았다.sumAllcolumns라는 이름으로...
rhive.query("SELECT	  *	  FROM	  iris	  LIMIT	  10")	  	  	  	  rowname	  sepallength	  sepalwidth	  petallength	  petalwi...
 	  prev	  +	  values	  }	  	  	  sumAllColumns.terminate	  <-­‐	  function(values)	  {	  	  	  values	  }	  	  	  rhive.a...
999999999998위의 실행결과에서 마지막으로 출력(print)된 결과를 보면 컬럼이 2개인 3개의 레코드를만들어 낸 것을 볼 수 있다.먼저 주목할 것은 rhive.query로 전달된 SQL구문안에 있는 RA()라는...
sumAllColumns.terminate	  RHive 용 UDAF 펑션들은 같은 유저가 임의로 지정하는 prefix로 시작하는 4개의펑션들로 구성되어야 하며 postfix로는 .partial, .merge, .ter...
완벽한 이해가 아닌 사용법만을 이해하고 싶다면RHive를 UDAF 지원을 이용하기 위해서는 펑션을 4개 만들어야 하며 정해진 룰에따라야 한다는 것을 기억해야 한다.RHive - UDAF 3이제 UDAF용 4개의 펑션들의...
if	  (is.null(prev))	  {	  	  	  	  	  	  	  prev	  <-­‐	  rep(0.0,	  length(values))	  	  	  }이렇게 반복적으로 수행되어서 마지막에 레코드에서 ...
2	  versicolor	    3	  	  virginica	    	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	...
 	  if	  (is.null(prev))	  {	  	  	  	  	  prev	  <-­‐	  rep(0.0,	  length(values))	  	  	  }	  	  	  prev	  +	  values	  ...
3	  	  	  	  	  	  	  329.4	  	  	  	  	  	  148.7	  	  	  	  	  	  	  277.6	  	  	  	  	  	  101.3	  SQL문이 다소 복잡해 졌으나 최종결...
Upcoming SlideShare
Loading in …5
×

RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수

2,085 views

Published on

RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수 (한글판)

  • Be the first to comment

RHive tutorial 4: RHive 튜토리얼 4 - UDF, UDTF, UDAF 함수

  1. 1. RHive 튜토리얼 4 - UDF, UDAF, UDTF 함수RHive - advanced functionsRHive는 기초함수(basic functions), HDFS, map/reduce를 위한 apply 계열, 그리고UDF, UDAF, UDTF를 지원하기 위한 고급 함수들을 지원한다.Advanced function들은 Hive의 UDF와 UDAF를 R로 구현하여 적용하는데 필요한UDF/UDAF 함수들로 구성되어 있다.이 함수들을 활용하면 매우 낮은 복잡한 수준까지 R을 적용하여 Hadoop과 Hive를이용한 Map/Reduce 프로그래밍을 할 수 있으며Data mining의 복잡한 알고리즘이나 데이터 프로세싱도 많은 부분을 R언어를이용해서 처리할 수 있다.RHive - UDF and UDAF functionsHive는 UDF(User Defined Function), UDAF(User Defined Aggregate Function),UDTF(User Defined Table create Function)을 제공한다.UDF는 count, avg, min, max와 같은 SQL구문으로 한 컬럼 또는 여러 컬럼에 대해연산을 수행하는 Hive의 내장된 function을 말한다.Hive는 기본적으로 몇개의 UDF를 지원하며 사용자가 개발하여 추가할 수 있다.하지만 원래 Hive에서의 UDF, UDAF, UDTF는 모두 Java로 작성되어야 하며 R언어를직접 사용할 수 없다.RHive는 UDF와 UDAF를 R언어로 작성하고 Hive에서 수행할 수 있게 기능을 지원한다.또 RHive가 미리 작성해 둔 UDTF를 활용하여 복잡한 컬럼 분해 작업을 가능하게 해준다.이 튜토리얼에서는 UDF와 UDAF작성할 때 사용하는 함수들과 예제를 통해 이것들을어떻게 구현하고 적용하는지를 설명한다.rhive.assignrhive.assign 함수는 R에서 작성된 함수들과 생성한 변수들을 Hive에서 참조할 수 있게지정하는 역할을 한다.
  2. 2. 이같은 assign이 과정이 필요한 이유는 R에서 작성한 코드와 벡터, 매트릭스,데이터프레임, 펑션들 중어느 것이 분산환경에서 사용될 것인지 지정(assign)해 주는 작업이 필요하기 때문이다.rhive.assign이 바로 분산환경으로 내보내기 위한 함수와 변수, 객체들을 지정하는 일을한다.주의할 점은 rhive.assign는 분산환경으로 함수와 변수, 객체들을 배포하기 전에 필요한작업들을 수행하지만 실제로 분산환경에서 배포하지는 않는다.단지 준비를 위한 것으로 실제로 배포작업을 해주는 rhive.export나 rhive.exporlAll과같은 펑션들과 연달아 쓰이는 것이 일반적이다.배포의 의미는 Hadoop의 Map/Reduce처럼 Hive에서 사용될 함수와 객체들을Hadoop의 Job node에 미리 대기시켜 두었다가데이터를 처리할 때 불러 쓰기 위한 준비과정으로 생각하면 된다.rhive.assign 함수는 인수(argument)를 2개 입력받으며첫번째는 R에서 생성한 심볼의 character type의 alias이며 두 번째는 배포할 심볼자체이다.만약 분산환경에 전달할 심볼이 newsum이라는 이름을 가지고 있다면rhive.assign을 사용하여 다음과 같이 지정해준다.newsum  <-­‐  function(value)  {      value  +  1  }  rhive.assign("newsum",  newsum)구문이 다소 어색해 보일 수는 있지만 이것은 R의 구조로 인한 문제로 향후 버전에서개선될 것이다.첫번째 인수에는 두번째 인수로 들어갈 심볼을 문자열로 만들어주기만 하면 된다.보통은 심볼의 이름과 같은 문자열을 넣어주는 것이 작업하는데 편리하며심볼가 동일 하지 않은 다른 문자열을 주어도 상관없지만이름을 바꾸는 경우 실제 사용할때는 지정한 심볼의 이름이 바뀌는 것을 주의해야 하고혼동하기 쉬우므로 바꾸지 않는 것이 좋다.다음에 나오는 예를 통해 rhive.assign을 사용하는 방법을 살펴보자.다음 사용예는 sum3values라는 function 만들고 rhive.assign을 이용해서 분산환경에배포될 것들을 정의한 예이다.sum3values  <-­‐  function(a,b,c)  {      a  +  b  +  c  }  
  3. 3.    rhive.assign("sum3values",  sum3values)  [1]  TRUE아래와 같이 함수가 아닌 객체를 지정할 수도 있다.coef1  <-­‐  3.141593  rhive.assign("coef1",  coef1)데이터프레임을 비롯한 어떤 것도 가능하다.library(MASS)  >  head(cats)      Sex  Bwt  Hwt  1      F  2.0  7.0  2      F  2.0  7.4  3      F  2.0  9.5  4      F  2.1  7.2  5      F  2.1  7.3  6      F  2.1  7.6  >  rhive.assign("cats",  cats)  [1]  TRUE객체와 dataframe등은 분산환경에 배포해서 기존에 만들어둔 값이나 coefficient등을참조해서 연산하는데 이용할 수 있다.다만 이런 객체들이 분산환경으로 배포되면 분산환경내에서는 공유메모리(sharedmemory)와 같은 개념이 아니고단지 local memory에 존재하는 것들이므로 주의해야 한다.rhive.exportrhive.export는 R에서 만들어진 객체들을 분산환경에 실제로 배포해서 분산환경에서실행되도록 준비하는 것을 처리해 준다.rhive.export는 rhive.assign과 함께 사용되며 rhive.export의 인수로 주는 객체의이름들은 반드시 rhive.assign으로 배포준비가 끝난 것이어야 한다.다음의 예를 통해서 사용법을 쉽게 알 수 있다.
  4. 4. sum3values  <-­‐  function(a,b,c)  {      a  +  b  +  c   }       rhive.assign("sum3values",  sum3values)       rhive.export(sum3values)rhive.export는 첫번째 인수(argument)인 exportname을 제외하고도 많은 인수를가지고 있다.하지만 이런 것들은 복잡하게 구성된 환경에서 사용될 수 있도록배포할 서버와 port등을 별도로 지정할 수 있게 해 둔 것으로보통의 경우에는 사용할 필요가 없다.이런것들을 사용해야 할 만큼 RHive를 복잡한 환경에 구성해야 한다면 매뉴얼을참조하거나 RHive 개발팀에 문의하도록 한다.rhive.exportAllrhive.exportAll 함수느 rhive.export와 기능상으로 동일한 함수이지만다른점은 rhive.exportAll은 인수로 넘겨준 문자열로 시작하는 심볼을 모두 한꺼번에넘겨주는 역할을 한다.이 함수는 주로 R로 작성된 UDAF function을 배포하기 위한 용도로 사용된다.R로 작성된 UDAF 펑션은 같은 이름으로 시작하는 4개 펑션으로 구성되어야 하는제약이 있으며 이것들을 쉽게 배포하기 위해 만들어둔 일종의 rhive.export를 변형한함수이다.다음의 예는 4개의 함수를 만들고 이것들을 분산환경의 RHive 서버로 배포하는 작업을한다.sumAllColumns  <-­‐  function(prev,  values)  {          if  (is.null(prev))  {                  prev  <-­‐  rep(0.0,  length(values))          }              prev  +  values  }      
  5. 5. sumAllColumns.partial  <-­‐  function(values)  {      values  }      sumAllColumns.merge  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {          prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }      sumAllColumns.terminate  <-­‐  function(values)  {          values  }      rhive.assign("sumAllColumns",  sumAllColumns)  rhive.assign("sumAllColumns.partial",  sumAllColumns.partial)  rhive.assign("sumAllColumns.merge",  sumAllColumns.merge)  rhive.assign("sumAllColumns.terminate",  sumAllColumns.terminate)      rhive.exportAll("sumAllColumns")  실제로 위에서 마지막줄은 다음과 동일하다.#  rhive.exportAll("sumAllColumns")      rhive.export("sumAllColumns")  rhive.export("sumAllColumns.partial")  rhive.export("sumAllColumns.merge")  rhive.export("sumAllColumns.terminate")rhive.assign과 rhive.export, rhive.exportAll은 R에서 생성한 펑션과 객체들을분산환경에서 가동중인 Rserve로 전달하여 Hive와 Hadoop이 사용할 수 있도록준비하는 작업까지만 수행한다.
  6. 6. 이렇게 배포한 R 펑션과 객체들을 실제로 사용하기 위해서는 rhive.query에 전달하는SQL구문에 기술해야만 사용할 수 있다.다음에 나오는 예제들을 통해 배포한 함수들을 어떻게 작동시키는지 배우게 될 것이다.RHive - UDF usage이제 UDF를 적용해 볼 테이블을 하나 준비해야 한다.Hive에 UDF를 테스트해 볼 적당한 테이블이 없다면 테이블을 하나 만든다.이 튜토리얼에서는 USArrests라는 data를 Hive 테이블로 변환할 것이다.USArrests는 R이 원래 가지고 있는 작은 데이터이다.아래와 같이 USArrests를 Hive 테이블로 변환해서 저장한다.rhive.write.table(USArrests)      rhive.query("SELECT  *  FROM  USArrests  LIMIT  10")                rowname  murder  assault  urbanpop  rape  1            Alabama      13.2          236              58  21.2  2              Alaska      10.0          263              48  44.5  3            Arizona        8.1          294              80  31.0  4          Arkansas        8.8          190              50  19.5  5      California        9.0          276              91  40.6  6          Colorado        7.9          204              78  38.7  7    Connecticut        3.3          110              77  11.1  8          Delaware        5.9          238              72  15.8  9            Florida      15.4          335              80  31.9  10          Georgia      17.4          211              60  25.8다음의 예는 USArrests 테이블의 전체 레코드 수를 카운트 하는 것이다.rhive.query("SELECT  COUNT(*)  FROM  USArrests")      X_c0  1      50  위의 예에서 사용한 COUNT 함수는 SQL에서 사용하는 함수이며 Hive UDF의 하나이다.아마도 SQL문법에 익숙한 사용자라면 가장 많이 사용하는 SQL 내장 함수임을 알고있을 것이다.
  7. 7. 이제 이 COUNT 함수와 유사한 일을 하는 함수를 R로 작성해서 동작시키는 방법을소개할 것이다.우선 아래와 같이 USArrests 테이블의 description을 확인해 본다.rhive.desc.table("USArrests")      col_name  data_type  comment  1    rowname        string  2      murder        double  3    assault              int  4  urbanpop              int  5          rape        double이제 USArrests 테이블에서 murder와 assault, rape 컬럼의 값을 모두 더하는 간단한함수를 만들고 실행할 것이다.다음은 그에 대한 전체 코드이다.library(RHive)  rhive.connect()      sumCrimes  <-­‐  function(column1,  column2,  column3)  {      column1  +  column2  +  column3  }      rhive.assign("sumCrimes",  sumCrimes)  rhive.export("sumCrimes")      rhive.query("SELECT   rowname,   urbanpop,   R(sumCrimes,   murder,  assault,  rape,  0.0)  FROM  usarrests")      rhive.close()실행한 결과는 아래와 같다.rhive.query("SELECT   rowname,   urbanpop,   R(sumCrimes,   murder,  assault,  rape,  0.0)  AS  crimes  FROM  usarrests")  
  8. 8.                    rowname  urbanpop  crimes  1                  Alabama              58    270.4  2                    Alaska              48    317.5  3                  Arizona              80    333.1  ...  48    West  Virginia              39      96.0  49            Wisconsin              66      66.4  50                Wyoming              60    183.4위의 예제에서 중요한 것은SQL 구문내에 쓰여진 R() 이라는 펑션이다.이 펑션은 Hive의 UDF function이며 R의 펑션이 아니다.정확히는 RHive가 R의 펑션을 Hive에서 처리할 수 있도록 하기 위해서 RHive에서Hive에 추가해 놓은 함수이다.R() 펑션은 sum이나 avg, min과 같은 펑션이며 하는 일은R로 작성된 펑션을 호출하고 인수를 넘겨주고 리턴값을 받아내서 Hive에 다시 전달해주는 역할을 한다.즉, 아래와 같은 SQL구문내에서 사용한 R() 펑션의 사용된 것을 설명하면 SELECT   rowname,   urbanpop,   R(sumCrime,   murder,   assault,   rape,   0.0)  FROM  usarrestssumCrime은 rhive.export에 의해 배포된 R 펑션의 이름이며,뒤에 연달아오는 murder, assault, rape라는 것은 Hive 테이블의 컬럼 이름으로써usarrests라는 Hive 테이블이 가지고 있는 column들의 이름이다.그리고 R() 펑션에 입력된 마지막 인수인 0.0은 R() 펑션이 return 할 값의 type이다.subCrime이라는 펑션이 리턴하는 값이 numeric인 경우에는 0.0을 입력하고character인 경우에는 ""를 넣는다.예를들어 subCrime이라는 R함수가 return하는 값이 character형이라면 아래와 같이입력한다.rhive.query("SELECT   rowname,   urbanpop,   R(sumCrime,   murder,  assault,  rape,  "")  FROM  usarrests")결국 아래의 구문은 앞서의 결과에서 보았듯이 3개의 컬럼으로 구성된 결과를 리턴한다.SELECT   rowname,   urbanpop,   R(sumCrime,   murder,   assault,   rape,  0.0)  FROM  usarrests
  9. 9. 여기서 주의할 것은 R()펑션이 return하는 값은 하나 뿐이라는 것이다.즉, 위의 예제의 SQL구문 결과를 보면 R() 펑션은 결과적으로 하나의 새로운column값을 만드는 것을 알 수 있다.사실 위의 예제에서 사용한 SQL구문은 원래 Hive SQL만으로도 처리가 가능한다.실제로 아래의 2개의 구문은 동일한 결과를 보여준다.RHive UDF SQLrhive.query("SELECT   rowname,   urbanpop,   R(sumCrime,   murder,  assault,  rape,  "")  FROM  usarrests")Hive SQLrhive.query("SELECT   rowname,   urbanpop,   murder   +   assault   +   rape  AS  crimes  FROM  usarrests")이 튜토리얼에서는 학습을 위해서 익히기 쉬운 예를 위해 실제로는 유용하지 않은 것을예로 만든 것이다.Hive는 기본적으로 많은 UDF와 column들간의 사칙연산등을 지원하고 있다.여러분이 RHive을 이용해서 대용량 분석 작업을 할 때 만약 Hive SQL에 지원하는기능이 이미 있고그것으로 해결이 가능한 것이라면 UDF를 사용하기 전에 Hive SQL이 그것을지원하는지 확인하고그것을 이용해서 처리하는 것을 추천한다.관련된 내용은 아래 URL에서 찾을 수 있다.https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF만약 Hive에서 기능을 지원하지 않고 여러 컬럼들을 이용해서 복잡한 계산을 하거나데이터마이닝(data mining)이나 기계학습(machine learning)을 위한 자질(feature)값을 추출하는 일을 해야 한다면RHive UDF 기능이 매우 유용할 것이다.RHive - UDAF 1UDF와 유사한 것으로 Hive UDAF라는 것을 지원하고 있다.UDAF는 aggregation을 위한 지원(support)하기 위한 것으로SQL구문에서 "group by"에 의해 지정된 column의 값을 키(key)로 하여 취합된데이터들에 대해서순차적으로 어떤 연산을 수행하게 해주는 펑션이다.이것 또한 UDF처럼 새로운 것을 Hive에 추가하기 위해서 Java로 모듈을 작성해야
  10. 10. 하지만RHive는 이것을 R언어를 이용해 작성할 수 있도록 지원하고 있다.설명하지는 않았지만 앞서의 예제들에서 여러분은 sumAllcolumns라는 4개의 UDAF펑션을 이미 보았다.sumAllcolumns라는 이름으로 시작하는 펑션들은 입력된 인수의 값을 모두 더하는일에 관련된 함수들이다.여기서 여러분은 몇가지 의문을 가질 것이다.첫째, "어째서 UDAF라는 기능은 4개의 펑션이 한꺼번에 필요한 것인가" 일것이고둘째, UDAF는 어떤 것에 이용할 수 있는가" 일 것이다.이를 이해하기 위해서는 먼저 실행코드를 보고 이해하는 것이 좋다.먼저 UDAF용 함수들을 적용하기에 적절한 테이블을 만들기 위해서 R의 datasets에기본 내장되어 있는iris data를 Hive에 업로드 한다.rhive.write.table(iris)      [1]  "iris"  >  rhive.list.tables()                tab_name  1                  aids2  2                    iris  3  new_usarrests  4          usarrests      rhive.desc.table("iris")            col_name  data_type  comment  1          rowname        string  2  sepallength        double  3    sepalwidth        double  4  petallength        double  5    petalwidth        double  6          species        string      
  11. 11. rhive.query("SELECT  *  FROM  iris  LIMIT  10")        rowname  sepallength  sepalwidth  petallength  petalwidth  species  1                1                  5.1                3.5                  1.4                0.2    setosa  2                2                  4.9                3.0                  1.4                0.2    setosa  3                3                  4.7                3.2                  1.3                0.2    setosa  4                4                  4.6                3.1                  1.5                0.2    setosa  5                5                  5.0                3.6                  1.4                0.2    setosa  6                6                  5.4                3.9                  1.7                0.4    setosa  7                7                  4.6                3.4                  1.4                0.3    setosa  8                8                  5.0                3.4                  1.5                0.2    setosa  9                9                  4.4                2.9                  1.4                0.2    setosa  10            10                  4.9                3.1                  1.5                0.1    setosa  iris data가 어떻게 구성되어 있는지 대략 파악할 수 있을 것이다.이제 iris 테이블에 species 컬럼의 값이 같은 것들이 취합해서 각 column의 값들을더하는 작업을 할 것이며그것의 완성된 전체코드와 실행결과는 아래와 같다.sumAllColumns  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {              prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }      sumAllColumns.partial  <-­‐  function(values)  {      values  }      sumAllColumns.merge  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {          prev  <-­‐  rep(0.0,  length(values))      }  
  12. 12.    prev  +  values  }      sumAllColumns.terminate  <-­‐  function(values)  {      values  }      rhive.assign("sumAllColumns",  sumAllColumns)  rhive.assign("sumAllColumns.partial",  sumAllColumns.partial)  rhive.assign("sumAllColumns.merge",  sumAllColumns.merge)  rhive.assign("sumAllColumns.terminate",  sumAllColumns.terminate)      rhive.exportAll("sumAllColumns")      result  <-­‐  rhive.query("      SELECT   species,   RA(sumAllColumns,   sepallength,   sepalwidth,  petallength,  petalwidth)      FROM  iris      GROUP  BY  species")      print(result)            species  1          setosa  2  versicolor  3    virginica                                                                                                                                                  X_c1  1  250.29999999999998,171.40000000000003,73.10000000000001,12.299999999999995  2                                                       296.8,138.50000000000003,212.99999999999997,66.3  3                             329.3999999999999,148.7,277.59999999999997,101.29
  13. 13. 999999999998위의 실행결과에서 마지막으로 출력(print)된 결과를 보면 컬럼이 2개인 3개의 레코드를만들어 낸 것을 볼 수 있다.먼저 주목할 것은 rhive.query로 전달된 SQL구문안에 있는 RA()라는 펑션이다.이것은 R() 펑션과 비슷한 것으로 R로 작성된 펑션을 UDAF로 구동시켜주는 펑션이다.RA()펑션의 return값은 모두 character type이며 하나의 값을 Hive로 전달한다.그리고 Hive는 리턴받은 결과들을 처리하고 다시 최종적으로 RHive에 전달한다.주의할 점의 RA() 펑션은 UDAF이므로 SQL의 GROUP BY 구문과 함께 사용해야만 한다.이에 대한 자세한 내용은 Hive문서를 참조하라.위에서 사용된 SQL구문을 구체적으로 설명하면SELECT   species,   RA(sumAllColumns,   sepallength,   sepalwidth,  petallength,  petalwidth)      FROM  iris      GROUP  BY  species"GROUP BY"에 의해서 취합되는 species라는이름의 컬럼의 값들을 기준으로 모여진데이터들끼리 연산을 따로 하는 것이다.그리고 그 연산의 대상이 되는 컬럼들은 sepallength, sepalwidth, petallength,petalwidth이며 RA() 펑션은 인수로 UDAF로 사용될 R펑션들의 접두어(prefix)를입력받고 그 뒤로 두 번째 인수부터 사용자가 정의한 column들을 입력 받아서 R로작성된 UDAF함수 4개를 각각 상황에 맞게 적용하여 처리한 것이다.그리고 GROUP BY로 지정한 column인 species의 값과 UDAF에 의해 만들어진 값을새로운 컬럼으로 생성하여 결과를 만들어 낸 것이다.여기서 아직 앞서의 의문이 풀리지 않았을 것이며 또 추가로 여러분은 몇개의 의문이 더생겼을지도 모른다.아직 설명되지 않은 것들에 대해서는 다음 절에서 설명한다.RHive - UDAF 2이제 앞서의 예에서 만든 4개의 UDAF용 R펑션과 부족한 점을 설명할 것이다.총 4개의 펑션이 UDAF를 위해서 만들어졌고 사용되었는데 아래와 같다.sumAllColumns  sumAllColumns.partial  sumAllColumns.merge  
  14. 14. sumAllColumns.terminate  RHive 용 UDAF 펑션들은 같은 유저가 임의로 지정하는 prefix로 시작하는 4개의펑션들로 구성되어야 하며 postfix로는 .partial, .merge, .terminate 그리고 postfix가없는 이름을 가진 함수들로 작성되어야 한다.이것은 RHive에 정한 naming rule로 바꿀 수 없다.4개의 펑션이 필요한 이유는 Hive UDAF가 작동될 때 function들이 작동할 수 있는Map/Reduce 과정에서의 포인트가 4곳이기 때문이다.foobar라는 이름으로 시작하는 UDAF 함수 4개를 만들었다고 가정하면 각 펑션별로작동되는 곳들은 아래와 같다. foobar  -­‐  Map의  aggregation을  수행하는  곳  (정확히는  combine  단계)   foobar.partial  -­‐  Map의  aggregation  된  결과를  reduce에  전달하는  곳   foobar.merge  -­‐  Reduce의  aggregation을  수행하는  곳   foobar.terminate   -­‐   Reduce에서   최종   aggregation   된   것을   종료하는   곳그리고 foobar와 foobar.merge는 유사한 일을 하며 이름은 상관없지만 인수는 2개를가지고 있어야 하며foobar.partial과 foobar.terminate도 역시 서로 비슷하며 이것들은 이름은 상관없지만인수를 1개만 가질 수 있다.이제 이 함수들이 어떻게 언제 작동되는지에 대한 것이 아직도 의문으로 남아 있을것이다.이제 이 4개의 함수들이 어떻게 서로 연결되어 작동하는지 이해하기 위해함수들이 작동되는 흐름을 알아여 하는데 그것은 아래와 같다.foobar  -­‐  combine  aggregation  (map)  foobar.partial  -­‐  combine  return  (map)  foobar.merge  -­‐  reduce  aggregation  foobar.terminate  -­‐  reduce  terminate  여기서 combine 단계는 Hive의 설정에 따라 처리되지 않고 통과(pass)하고모든 것을 reduce 단계에서 처리될 수도 있다.설정을 정확하게 하지 않는다면 이 함수부분이 언제 통과하고 언제 수행되는지를 알기어렵다.따라서 4개의 펑션을 모두 만들어 놓는 것이 안전하다.고급 지식과 완벽한 이해를 위해서는 Hive와 Hadoop의 문서를 참조하라.
  15. 15. 완벽한 이해가 아닌 사용법만을 이해하고 싶다면RHive를 UDAF 지원을 이용하기 위해서는 펑션을 4개 만들어야 하며 정해진 룰에따라야 한다는 것을 기억해야 한다.RHive - UDAF 3이제 UDAF용 4개의 펑션들의 인수들과 작동 방식에 대해서 설명할 것이다.앞서 예제에서 만든 sumAllColumns라는 펑션들 중sumAllColumns와 sumAllColumns.merge를 살펴보자.두 함수내의 코드는 동일하다.sumAllColumns  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {              prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }      sumAllColumns.merge  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {          prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }이 함수들은 인수를 2개를 처리해야만 하는데첫번째 인수는 sumAllColumns와 sumAllColumns.merge함수에서 return한 값이다시 sumAllColumns와 sumAllColumns.merge함수의 인수로 들어오는 것이다.두번째 인수는 현재 record에 대해서 Hive가 넘겨주는 값이다.첫번째와 두번째 인수는 실제로 모두 vector이거나 list이다.vector로 넘겨지기 때문 각각의 column들에 대해서는 SQL 구문에서 입력한column들의 순서를 기억할 필요가 있다.첫번째 인수로 넘겨지는 prev는 함수가 return한 값이 다시 돌아서 넘겨지는 것이므로함수가 맨처음 실행될 때는 값이 없는 NULL 상태로 넘겨지게 된다.그래서 함수내에서 is.null로 NULL인지 확인하고 처리한 것을 볼 수 있다.
  16. 16. if  (is.null(prev))  {              prev  <-­‐  rep(0.0,  length(values))      }이렇게 반복적으로 수행되어서 마지막에 레코드에서 return되는 값들은sumAllColumns.partial과 sumAllColumns.terminate의 인수로 각각 넘겨진다.두 함수의 함수내 코드는 동일하다.sumAllColumns.partial  <-­‐  function(values)  {      values  }      sumAllColumns.terminate  <-­‐  function(values)  {      values  }이 두 함수들은 반복적으로 수행되지 않으며 그 때문에 인수를 하나만 받을 수 있다.그리고 4개의 함수중에 가장 마지막에 실행되는 sumAllColumns.terminate가return한 값은Hive로 전달되며 하나의 column의 값으로 만들어진다.위 예제에서는 각각 2개씩의 함수들이 동일한 코드를 가지고 있는 것을 볼 수 있는데이 튜토리얼에서는 이것 역시 설명을 위한 쉬운 예제를 만든 것으로실제 사용할 때는 사용자에 의해서 4개의 펑션이 모두 다른 코드를 가질 수도 있다.그래서 함수내의 코드가 동일하다고 해도 항상 4개의 함수가 있어야 한다.RHive - UDTF이제 앞의 예에서 작성한 코드의 결과값을 좀더 우아하게(graceful)하게 고치려고 한다.character(string)값 하나로 나오는 것은 다루기가 매우 힘들기 때문이다.이것을 분해할 필요가 있으며 이를 위해서 RHive가 지원하는 UDTF 펑션인 unfold를사용할 것이다.그 결과가 앞서 예에서 SQL 구문을 실행한 결과이다. print(result)            species   1          setosa  
  17. 17. 2  versicolor   3    virginica                                                                                                                                                  X_c1   1   250.29999999999998,171.40000000000003,73.10000000000001,12.2999 99999999995   2                                                       296.8,138.50000000000003,212.999999 99999997,66.3   3                             329.3999999999999,148.7,277.59999999999997,101.2 9999999999998  위에서 2번째 컬럼인 X_c1은 UDAF에 의해서 만들어진 값이며 character type으로되어 있다.그리고 값으로는 수치값들이 "," 로 구분되어 있음을 알 수 있다.이것을 다시 numeric vector로 만들기 위해서는 strsplit과 같은 R 내장함수를 이용해야하는데record수가 적을 때는 문제가 없지만 record 수가 많다면 처리하는데 문제가 발생한다.위의 예에서는 레코드수가 고작 3개이지만 크기가 큰 테이블에 비슷한 처리를 할 때는record수가 3,000,000개가 넘을 수도 있다.따라서 UDAF가 return한 값은 구분되어 각각의 column값으로 만들어져야 한다.이것을 위해서는 subquery와 UDTF가 필요하며UDTF를 사용해서 수정된 코드는 아래와 같다.sumAllColumns  <-­‐  function(prev,  values)  {      if  (is.null(prev))  {              prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }      sumAllColumns.partial  <-­‐  function(values)  {      values  }      sumAllColumns.merge  <-­‐  function(prev,  values)  {  
  18. 18.    if  (is.null(prev))  {          prev  <-­‐  rep(0.0,  length(values))      }      prev  +  values  }      sumAllColumns.terminate  <-­‐  function(values)  {      values  }      rhive.assign("sumAllColumns",  sumAllColumns)  rhive.assign("sumAllColumns.partial",  sumAllColumns.partial)  rhive.assign("sumAllColumns.merge",  sumAllColumns.merge)  rhive.assign("sumAllColumns.terminate",  sumAllColumns.terminate)      rhive.exportAll("sumAllColumns")      result  <-­‐  rhive.query(      "SELECT   unfold(dummytable.dummycolumn,   0.0,   0.0,   0.0,   0.0,  ,)                          AS   (sepallength,   sepalwidth,   petallength,  petalwidth)        FROM  (            SELECT   RA(sumAllColumns,   sepallength,   sepalwidth,  petallength,  petalwidth)  AS  dummycolumn            FROM  iris            GROUP  BY  species            )  dummytable")      print(result)      sepallength  sepalwidth  petallength  petalwidth  1              250.3            171.4                73.1              12.3  2              296.8            138.5              213.0              66.3  
  19. 19. 3              329.4            148.7              277.6            101.3  SQL문이 다소 복잡해 졌으나 최종결과에서 UDAF가 return값이모두 unfold라는 UDTF에 의해서 각각의 column들로 분리되어 만들어진 것을 볼 수있다.unfold는 RHive에 지원하는 UDTF 함수이며 R코드를 따로 적용할 필요는 없다.그리고 Hive의 UDTF는 현재 제약으로 인해 SELECT절에 다른 구문을 넣을 수 없다는단점이 있다.이것은 RHive에서는 해결할 수 없는 것으로 Hive의 기능이 개선될 때까지 기다려야 할것이다.지금까지의 UDF, UDAF, UDTF는 SQL구문을 이용해서 1단계 Map/Reduce로 작업이처리되도록 한 것이다.만약 여러분이 RHive를 이용해서 매우 복잡한 작업을 하려고 한다면여러 단계의 Map/Reduce가 필요 할 수 있다.이것은 일반적인 Map/Reduce 구현체(implementation)이나 Hadoop streaming구현체에서 흔히 볼 수 있는 것이다.이런 여러 단계의 Map/Reduce를 결합해서 작업을 하려고 한다면중간 결과를 저장하기 위한 임시 테이블을 만들어 두고 결과를 저장한 후 삭제하는작업을 해야 할 수 있다.

×