SlideShare a Scribd company logo
1 of 31
Download to read offline
Taewook Eom 
Data Infrastructure Group 
SK planet 
taewook@sk.com 
2014-09-25 
Programming Cascading
Big Data Processing 
저자동 고유연성 
고자동 저유연성
Cascading 
http://www.cascading.org/ 
Since 2007, by Chris Wensel (CTO, founder of Concurrent, Inc.)
Cascading 
데이터베이스 기초 개념과 배관(파이프와 연산자)을 비유하여 추상화 제공 
엔터프라이즈 data workflow의 비즈니스 프로세스 관리를 위한 패턴 언어
http://docs.cascading.org/cascading/2.5/userguide/pdf/userguide.pdf 
http://docs.cascading.org/impatient/ https://github.com/Cascading/Impatient 
Cascading for the Impatient
Cascading 
•Flow Planner가 사전 계획 단계(compile time)에서 에러 확인 p.23 
–연산에 필요한 필드 p.31 
–연산 순서 
–파이프와 탭의 연결 상태 
–의존성 그래프 생성 -> DAG 생성 p.37 
•DAG(Directed Acyclic Graph) 
–Data work flow에 적합한 형태 
–다양한 데이터 처리 엔진에서 사용: Microsoft Dryad, Apache Tez, Apache Spark 
•엔터프라이즈 환경에 적합 
–논리적 계획이 아닌 물리적 계획으로 예측 가능 p.24 
–결정적 전략으로 실행마다 물리적 실행 계획이 바뀌지 않음 p.36 
–하나의 JAR 파일로 다양한 규모 적용(Same JAR, any scale) p.33 
•비즈니스 로직, 시스템 통합, 단위 테스트, 정합성 검사, 예외 처리 모두 포함 
•운영상 복잡성 낮춤 p.172 
–Ad-hoc Query나 빠른 응답 보다는 Hive처럼 높은 처리량 목적으로 ETL에 적합 p.142 
–JAVA 개발자들에게 익숙한 도구와 절차 p.172
Cascading Terminology 
http://docs.cascading.org/cascading/2.5/userguide/html/ch03.html#N2013B 3.1 Terminology 
•Pipe: Data stream 
•Filter: Data operation 
•Tuple: Data record 
•Branch: 분기나 병합이 없는 간단한 파이프 연결 
•Pipe Assembly: Pipe branch들의 연결 집합 
•Tuple Stream: Pipe branch나 assembly를 통과하는 Tuple들의 연속 
•Tap: Data source/sink 
•Flow: Tap들과 연결된 한 개 이상의 pipe assembly들의 연결상태 
•Cascade 
–Flow의 집합으로 하나의 프로세스로 실행 
–Flow는 다른 flow의 데이터 의존성이 만족될 때까지 실행되지 않음
Pipe Types 
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes 
•Each 
–Filter, Function 적용 
–Filter는 Tuple 삭제만 가능 
–Function은 필드 추가/변경과 여러 Tuple 출력 가능 
–Function의 기본 Output Selector는 Fields.RESULT 
•Every 
–GroupBy, CoGroup의 결과에만 사용 
–Aggregator, Buffer 적용 
•Function, Aggregator, Buffer의 Output Selector 필드 꼭 지정
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20438 The Each and Every Pipes
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20438 The Each and Every Pipes
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20438 The Each and Every Pipes
Buffer vs. Aggregator 
•공통점 
–GroupBy, CoGroup의 결과에 대해서만 동작 
–Aggregator와 Buffer의 기본 Output Selector는 Fields.ALL 
•차이점 
–Aggregator는 chained되지만 Buffer는 chained되지 않음 
–Buffer는 하나의 group에 대해 여러 개 결과 tuple 출력 가능 
–Buffer는 Aggregator를 똑같이 구현할 수 있으므로 Aggregator는 Buffer의 특별히 최적화된 형태라 볼 수 있음 
pipe = new GroupBy(pipe, new Fields("mdn"), new Fields("log_time")); pipe = new Every(pipe, new Count(new Fields("count"))); pipe = new Every(pipe, new Fields("mdn"), new DistinctCount(new Fields("unique_mdn_cnt"))); pipe = new Every(pipe, new Fields("pay_amt"), new Sum(new Fields("sum"), long.class)); pipe = new Every(pipe, new Fields("log_time"), new Last(new Fields("last_time")));
Pipe Types 
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes 
•Merge 
–Unsorted merge 
–같은 필드와 타입을 가진 둘 이상의 Pipe들을 하나의 stream으로 병합 
–Grouping을 하지 않아 GroupBy보다 빠름 (Aggregator/Buffer 사용불가) 
•GroupBy 
–Key 필드에 대해 Sorted merge 
–같은 필드와 타입을 가진 둘 이상의 Pipe들만 병합 가능 
–Group 내 임의의 순서 (속도는 낮아지지만 2차 정렬 가능) 
–Grouping 만들어 Every를 위한 준비 작업 
–Grouping 위해 grouping fields를 정렬해서 Merge 보다 느림 
•grouping fields에 대해 natural order로 정렬 
–2차 정렬 가능 
•2차 정렬 지정하지 않으면 group 내에서 임의 순서지만 더 빠르게 수행 
Fields sortFields = new Fields("value1", "value2"); sortFields.setComparator("value1", Collections.reverseOrder()); Pipe groupBy = new GroupBy(assembly, groupFields, sortFields);
Pipe Types 
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes 
•서로 다른 fields 가진 둘 이상의 stream을 공통 fields 값 기준으로 Join 
•CoGroup 
–SQL의 join과 유사(InnerJoin, OuterJoin, LeftJoin, RightJoin, MixedJoin) 
–outer join의 경우 존재하지 fields들은 null로 채움 
–결과에 모든 stream의 모든 fields가 출력되기 때문에, 모든 stream의 fields들은 중복된 이름을 포함할 수 없음 
•중복된 이름이 있을 경우 declaredFields 인자로 변경 가능 
–field의 순서로 짝맞춤. field 이름은 개발자를 위한 수단일 뿐 
–빠른 join 위해 오른쪽 stream의 모든 unique key tuple(bag)을 메모리에 저장 시도 
•설정 가능한 임계치를 넘어서면 메모리에서 disk로 쓰면서 진행(성능 저하) 
•임계치가 클 경우 메모리 에러 유발 
•가장 큰 group을 가장 왼쪽에 넣고 적절히 임계치를 조절하면 최고 성능 발휘 
•HashJoin 
–한 개의 큰 stream과 작은 stream들의 join에 최적화 (Map-side Join) 
•오른쪽 stream을 모두 메모리에 넣어 빠르게 비교 연산 (group 없어 전체 메모리에 올림) 
–Group 필요없어 임의 순서로 Join하여 CoGroup 보다 빠름 
–Group 존재하지 않아 aggregator나 buffer가 뒤따르지 못함 
–CheckPoint를 HashJoin 직전에 넣어 작게 된 stream 모두 디스크에 쓰는 방식 유용
http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20630 CoGroup
String inPath = args[ 0 ]; String outPath = args[ 1 ]; Properties properties = new Properties(); AppProps.setApplicationJarClass( properties, Main.class ); HadoopFlowConnector flowConnector = new HadoopFlowConnector( properties ); Tap inTap = new Hfs( new TextDelimited( true, "t" ), inPath ); Tap outTap = new Hfs( new TextDelimited( true, "t" ), outPath ); Pipe copyPipe = new Pipe( "copy" ); FlowDef flowDef = FlowDef.flowDef() .addSource( copyPipe, inTap ) .addTailSink( copyPipe, outTap ); flowConnector.connect( flowDef ).complete(); 
https://github.com/Cascading/Impatient/blob/master/part1/src/main/java/impatient/Main.java 
p.29 1.2 초간단 케스케이딩 애플리케이션
… Tap docTap = new Hfs( new TextDelimited( true, "t" ), docPath ); Tap wcTap = new Hfs( new TextDelimited( true, "t" ), wcPath ); Fields token = new Fields( "token" ); Fields text = new Fields( "text" ); RegexSplitGenerator splitter = new RegexSplitGenerator( token, "[ [](),.]" ); Pipe docPipe = new Each( "token", text, splitter, Fields.RESULTS ); Pipe wcPipe = new Pipe( "wc", docPipe ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef().setName( "wc" ) .addSource( docPipe, docTap ).addTailSink( wcPipe, wcTap ); … 
https://github.com/Cascading/Impatient/blob/master/part2/src/main/java/impatient/Main.java 
p.37 1.5 흔한 단어 세기
… Fields token = new Fields( "token" ); Fields text = new Fields( "text" ); RegexSplitGenerator splitter = new RegexSplitGenerator( token, "[ [](),.]" ); Fields fieldSelector = new Fields( "doc_id", "token" ); Pipe docPipe = new Each( "token", text, splitter, fieldSelector ); Fields scrubArguments = new Fields( "doc_id", "token" ); docPipe = new Each( docPipe, scrubArguments, new ScrubFunction( scrubArguments ), Fields.RESULTS ); Pipe wcPipe = new Pipe( "wc", docPipe ); wcPipe = new Retain( wcPipe, token ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef().setName( "wc" ) .addSource( docPipe, docTap ).addTailSink( wcPipe, wcTap ); Flow wcFlow = flowConnector.connect( flowDef ); wcFlow.writeDOT( "dot/wc.dot" ); wcFlow.complete(); 
https://github.com/Cascading/Impatient/blob/master/part3/src/main/java/impatient/Main.java 
doc_id text doc01 A rain shadow is a dry area on the lee back … doc02 This sinking, dry air produces a rain shadow, … doc03 A rain shadow is an area of dry land that lies … … 
p.55 2.2 토큰 다듬기
public class ScrubFunction extends BaseOperation implements Function { public ScrubFunction( Fields fieldDeclaration ) { super( 2, fieldDeclaration ); } public void operate( FlowProcess flowProcess, FunctionCall functionCall ) { TupleEntry argument = functionCall.getArguments(); String doc_id = argument.getString( 0 ); String token = scrubText( argument.getString( 1 ) ); if( token.length() > 0 ) { Tuple result = new Tuple(); result.add( doc_id ); result.add( token ); functionCall.getOutputCollector().add( result ); } } public String scrubText( String text ) { return text.trim().toLowerCase(); } } 
https://github.com/Cascading/Impatient/blob/master/part3/src/main/java/impatient/ScrubFunction.java 
p.49 2.1 사용자 정의 연산
p.55 2.2 토큰 다듬기
… String stopPath = args[ 2 ]; … Fields stop = new Fields( "stop" ); Tap stopTap = new Hfs( new TextDelimited( stop, true, "t" ), stopPath ); … Fields scrubArguments = new Fields( "doc_id", "token" ); docPipe = new Each( docPipe, scrubArguments, new ScrubFunction( scrubArguments ), Fields.RESULTS ); Pipe stopPipe = new Pipe( "stop" ); Pipe tokenPipe = new HashJoin( docPipe, token, stopPipe, stop, new LeftJoin() ); tokenPipe = new Each( tokenPipe, stop, new RegexFilter( "^$" ) ); Pipe wcPipe = new Pipe( "wc", tokenPipe ); wcPipe = new Retain( wcPipe, token ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef() .setName( "wc" ) .addSource( docPipe, docTap ) .addSource( stopPipe, stopTap ) .addTailSink( wcPipe, wcTap ); … 
https://github.com/Cascading/Impatient/blob/master/part4/src/main/java/impatient/Main.java 
stop a about after all along an and Any … 
p.57 2.3 복제 조인
p.57 2.3 복제 조인
… String tfidfPath = args[ 3 ]; … Fields fieldSelector = new Fields( "doc_id", "token" ); tokenPipe = new Retain( tokenPipe, fieldSelector ); … Pipe tfPipe = new Pipe( "TF", tokenPipe ); Fields tf_count = new Fields( "tf_count" ); tfPipe = new CountBy( tfPipe, new Fields( "doc_id", "token" ), tf_count ); Fields tf_token = new Fields( "tf_token" ); tfPipe = new Rename( tfPipe, token, tf_token ); Fields doc_id = new Fields( "doc_id" ); Fields tally = new Fields( "tally" ); Fields rhs_join = new Fields( "rhs_join" ); Fields n_docs = new Fields( "n_docs" ); Pipe dPipe = new Unique( "D", tokenPipe, doc_id ); dPipe = new Each( dPipe, new Insert( tally, 1 ), Fields.ALL ); dPipe = new Each( dPipe, new Insert( rhs_join, 1 ), Fields.ALL ); dPipe = new SumBy( dPipe, rhs_join, tally, n_docs, long.class ); Pipe dfPipe = new Unique( "DF", tokenPipe, Fields.ALL ); Fields df_count = new Fields( "df_count" ); dfPipe = new CountBy( dfPipe, token, df_count ); Fields df_token = new Fields( "df_token" ); Fields lhs_join = new Fields( "lhs_join" ); dfPipe = new Rename( dfPipe, token, df_token ); dfPipe = new Each( dfPipe, new Insert( lhs_join, 1 ), Fields.ALL ); Pipe idfPipe = new HashJoin( dfPipe, lhs_join, dPipe, rhs_join ); 
https://github.com/Cascading/Impatient/blob/master/part5/src/main/java/impatient/Main.java 
p.71 3.1 TF-IDF 구현 
tfPipe: (“doc_id”, “tf_token”, “tf_count”) 
dPipe: (“doc_id”) 
dfPipe: (“doc_id”, “token”) 
tfPipe: (“doc_id”, “token”, “tf_count”) 
dPipe: (“doc_id”, “tally”) 
dPipe: (“doc_id”, “tally”, “rhs_join”) 
dPipe: (“rhs_join”, “n_docs”) 
dfPipe: (“token”, “df_count”) 
dfPipe: (“df_token”, “df_count”) 
dfPipe: (“df_token”, “df_count”, “lhs_join”) 
idfPipe: (“df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”)
Pipe tfidfPipe = new CoGroup( tfPipe, tf_token, idfPipe, df_token ); Fields tfidf = new Fields( "tfidf" ); String expression = "(double) tf_count * Math.log( (double) n_docs / ( 1.0 + df_count ) )"; ExpressionFunction tfidfExpression = new ExpressionFunction( tfidf, expression, Double.class ); Fields tfidfArguments = new Fields( "tf_count", "df_count", "n_docs" ); tfidfPipe = new Each( tfidfPipe, tfidfArguments, tfidfExpression, Fields.ALL ); fieldSelector = new Fields( "tf_token", "doc_id", "tfidf" ); tfidfPipe = new Retain( tfidfPipe, fieldSelector ); tfidfPipe = new Rename( tfidfPipe, tf_token, token ); Pipe wcPipe = new Pipe( "wc", tfPipe ); Fields count = new Fields( "count" ); wcPipe = new SumBy( wcPipe, tf_token, tf_count, count, long.class ); wcPipe = new Rename( wcPipe, tf_token, token ); wcPipe = new GroupBy( wcPipe, count, count ); FlowDef flowDef = FlowDef.flowDef() .setName( "tfidf" ) .addSource( docPipe, docTap ) .addSource( stopPipe, stopTap ) .addTailSink( tfidfPipe, tfidfTap ) .addTailSink( wcPipe, wcTap ); … 
https://github.com/Cascading/Impatient/blob/master/part5/src/main/java/impatient/Main.java 
p.71 3.1 TF-IDF 구현 
tfidfPipe: (“doc_id”, “tf_token”, “tf_count”, 
“df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”) 
tfidfPipe: (“doc_id”, “tf_token”, “tf_count”, “df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”, “tfidf”) 
tfidfPipe: (“tf_token”, “doc_id”, “tfidf”) 
tfidfPipe: (“token”, “doc_id”, “tfidf”)
p.71 3.1 TF-IDF 구현
Programming Tips 
•Local Mode 
–Hadoop 사용하기 전에 로컬 파일을 이용해 개발/테스트/데이터 탐색 
–Hadoop API를 사용하지 않고, 메모리에서만 동작(메모리에 제한) 
–로컬 테스트 가능하나 로컬과 Hadoop 미묘한 API 차이 있음 
•cascading-hadoop-2.0.x.jar 대신 cascading-local-2.0.x.jar 사용 
•FileTap, LocalFlowConnector 사용 
•Test p.80 
–CascadingTestCase 
–Debug http://docs.cascading.org/cascading/2.5/userguide/html/ch09s02.html 
–Assert 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch08s02.html 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch09s09.html 
–Trap http://docs.cascading.org/cascading/2.5/userguide/html/ch08s03.html 
–Sample http://docs.cascading.org/cascading/2.5/userguide/html/ch09s03.html 
–Checkpoint 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch08s04.html 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch08s05.html
Programming Tips 
•작은 의미 구분으로 SubAssembly와 Flow를 만들고 Cascade 연결 
•Flow 연결 
–Head, Tail, Assembly들은 "이름" 통해서 연결되므로 이름 명시 중요 
–DAG로 되어 있어 마지막 sink들로 부터 역으로 연결 여부 검사 
–Pipe는 이전 Pipe의 이름 물려 받으므로 명시적 이름 구분이 runtime 오류 방지 
•필드 이름은 _, 소문자, 숫자만 사용 
–한글이나 –는 Janino compiler를 사용하는 Expression 함수에서 오류 발생 
–"first-name“은 필드 이름에 적합하지만, Expression에 사용되면 first-name.trim() 처럼 인식하면서 Janino에서 runtime 오류 발생 
–Expression function 보다 function 구현이 Janino 문제도 없고 재사용 쉬움 
•GroupBy의 sort 필드는 class type 먼저 맞추기 
–HDFS에 저장 후 다시 읽으면 무조건 String 타입으로 변경됨 
•Operation 재사용을 위해 전역변수나 property 이용 최소화하고 operation의 constructor 에 인자 넘기기
Programming Tips 
•Reducer 개수 지정 
–중간 Reducer 개수 
–최종 Reducer 개수 
Properties properties = new Properties(); properties.put("mapred.reduce.tasks", “10”); properties.put("mapred.map.tasks.speculative.execution", "true"); properties.put("mapred.reduce.tasks.speculative.execution", "false"); properties.put("mapred.job.priority", “HIGH”); AppProps.setApplicationJarClass(properties, Main.class); FlowConnector flowConnector = new HadoopFlowConnector(properties); 
TextDelimited scheme = new TextDelimited(new Fields(“key“, “value”), true, "t"); scheme.setNumSinkParts(1); Tap sinkTap = new Hfs(scheme, outputPath, SinkMode.REPLACE);
•http://docs.cascading.org/cascading/2.5/userguide/html/ch09.html 9. Built-In Operations 
–Identity Function 
–Text Functions 
–Regular Expression Operations 
–Java Expression Operations 
–Buffers 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch10.html 10. Built-in Assemblies 
–AggregateBy (AverageBy, CountBy, SumBy, FirstBy) 
–Rename 
–Retain 
–Unique 
•http://docs.cascading.org/cascading/2.5/userguide/html/ch13.html 13. Cookbook 
Programming Tips
Questions? 
Questions.foreach( answer(_) )
public class DistinctCount extends BaseOperation<HashSet<String>> implements Aggregator<HashSet<String>> { public DistinctCount(Fields fieldDeclaration) { super(fieldDeclaration); } @Override public void start(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { if (aggregatorCall.getContext() == null) { aggregatorCall.setContext(new HashSet<String>()); } else { aggregatorCall.getContext().clear(); } } @Override public void aggregate(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { TupleEntry argument = aggregatorCall.getArguments(); HashSet<String> context = aggregatorCall.getContext(); context.add(argument.getTuple().toString()); } @Override public void complete(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { aggregatorCall.getOutputCollector().add(new Tuple(aggregatorCall.getContext().size())); } }

More Related Content

What's hot

Apache Spark 입문에서 머신러닝까지
Apache Spark 입문에서 머신러닝까지Apache Spark 입문에서 머신러닝까지
Apache Spark 입문에서 머신러닝까지Donam Kim
 
The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습Hyun-woo Park
 
Data discovery & metadata management (amundsen installation)
Data discovery & metadata management (amundsen installation)Data discovery & metadata management (amundsen installation)
Data discovery & metadata management (amundsen installation)창언 정
 
Spark 소개 2부
Spark 소개 2부Spark 소개 2부
Spark 소개 2부Jinho Yoo
 
Pg report 20161010_02
Pg report 20161010_02Pg report 20161010_02
Pg report 20161010_02PgDay.Seoul
 
AWSKRUG DS 2020/12 - Let the Airflow in AWS
AWSKRUG DS 2020/12 - Let the Airflow in AWSAWSKRUG DS 2020/12 - Let the Airflow in AWS
AWSKRUG DS 2020/12 - Let the Airflow in AWSWoong Seok Kang
 
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기AWSKRUG - AWS한국사용자모임
 
Zeppelin notebook 만들기
Zeppelin notebook 만들기Zeppelin notebook 만들기
Zeppelin notebook 만들기Soo-Kyung Choi
 
Spark은 왜 이렇게 유명해지고 있을까?
Spark은 왜 이렇게  유명해지고 있을까?Spark은 왜 이렇게  유명해지고 있을까?
Spark은 왜 이렇게 유명해지고 있을까?KSLUG
 
Data pipeline and data lake
Data pipeline and data lakeData pipeline and data lake
Data pipeline and data lakeDaeMyung Kang
 
[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_database[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_databaseNAVER D2
 
Spark machine learning & deep learning
Spark machine learning & deep learningSpark machine learning & deep learning
Spark machine learning & deep learninghoondong kim
 
AWS없이 만든 AWS와 유사한 데이터 파이프라인
AWS없이 만든  AWS와 유사한 데이터 파이프라인AWS없이 만든  AWS와 유사한 데이터 파이프라인
AWS없이 만든 AWS와 유사한 데이터 파이프라인Kim Hyuk
 
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1 나무기술(주) 최유석 20170912
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1  나무기술(주) 최유석 20170912Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1  나무기술(주) 최유석 20170912
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1 나무기술(주) 최유석 20170912Yooseok Choi
 
data platform on kubernetes
data platform on kubernetesdata platform on kubernetes
data platform on kubernetes창언 정
 
2.apache spark 실습
2.apache spark 실습2.apache spark 실습
2.apache spark 실습동현 강
 
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종PgDay.Seoul
 
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...Jemin Huh
 

What's hot (20)

NiFi 시작하기
NiFi 시작하기NiFi 시작하기
NiFi 시작하기
 
Apache Spark 입문에서 머신러닝까지
Apache Spark 입문에서 머신러닝까지Apache Spark 입문에서 머신러닝까지
Apache Spark 입문에서 머신러닝까지
 
The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습
 
Data discovery & metadata management (amundsen installation)
Data discovery & metadata management (amundsen installation)Data discovery & metadata management (amundsen installation)
Data discovery & metadata management (amundsen installation)
 
Spark 소개 2부
Spark 소개 2부Spark 소개 2부
Spark 소개 2부
 
Pg report 20161010_02
Pg report 20161010_02Pg report 20161010_02
Pg report 20161010_02
 
AWSKRUG DS 2020/12 - Let the Airflow in AWS
AWSKRUG DS 2020/12 - Let the Airflow in AWSAWSKRUG DS 2020/12 - Let the Airflow in AWS
AWSKRUG DS 2020/12 - Let the Airflow in AWS
 
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기
Spark + S3 + R3를 이용한 데이터 분석 시스템 만들기
 
Zeppelin notebook 만들기
Zeppelin notebook 만들기Zeppelin notebook 만들기
Zeppelin notebook 만들기
 
Spark은 왜 이렇게 유명해지고 있을까?
Spark은 왜 이렇게  유명해지고 있을까?Spark은 왜 이렇게  유명해지고 있을까?
Spark은 왜 이렇게 유명해지고 있을까?
 
2020.02.06 우리는 왜 glue를 버렸나?
2020.02.06 우리는 왜 glue를 버렸나?2020.02.06 우리는 왜 glue를 버렸나?
2020.02.06 우리는 왜 glue를 버렸나?
 
Data pipeline and data lake
Data pipeline and data lakeData pipeline and data lake
Data pipeline and data lake
 
[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_database[113]how can realm_make_efficient_mobile_database
[113]how can realm_make_efficient_mobile_database
 
Spark machine learning & deep learning
Spark machine learning & deep learningSpark machine learning & deep learning
Spark machine learning & deep learning
 
AWS없이 만든 AWS와 유사한 데이터 파이프라인
AWS없이 만든  AWS와 유사한 데이터 파이프라인AWS없이 만든  AWS와 유사한 데이터 파이프라인
AWS없이 만든 AWS와 유사한 데이터 파이프라인
 
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1 나무기술(주) 최유석 20170912
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1  나무기술(주) 최유석 20170912Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1  나무기술(주) 최유석 20170912
Bigquery와 airflow를 이용한 데이터 분석 시스템 구축 v1 나무기술(주) 최유석 20170912
 
data platform on kubernetes
data platform on kubernetesdata platform on kubernetes
data platform on kubernetes
 
2.apache spark 실습
2.apache spark 실습2.apache spark 실습
2.apache spark 실습
 
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종
[Pgday.Seoul 2017] 5. 테드폴허브(올챙이) PostgreSQL 확장하기 - 조현종
 
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
 

Similar to Programming Cascading

7가지 동시성 모델 람다아키텍처
7가지 동시성 모델  람다아키텍처7가지 동시성 모델  람다아키텍처
7가지 동시성 모델 람다아키텍처Sunggon Song
 
하둡 타입과 포맷
하둡 타입과 포맷하둡 타입과 포맷
하둡 타입과 포맷진호 박
 
Programming skills 1부
Programming skills 1부Programming skills 1부
Programming skills 1부JiHyung Lee
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 명신 김
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIjieun kim
 
Cloudera Impala 1.0
Cloudera Impala 1.0Cloudera Impala 1.0
Cloudera Impala 1.0Minwoo Kim
 
[Swift] Protocol (2/2)
[Swift] Protocol (2/2)[Swift] Protocol (2/2)
[Swift] Protocol (2/2)Bill Kim
 
Presto User & Admin Guide
Presto User & Admin GuidePresto User & Admin Guide
Presto User & Admin GuideJEONGPHIL HAN
 
Big data analysis with R and Apache Tajo (in Korean)
Big data analysis with R and Apache Tajo (in Korean)Big data analysis with R and Apache Tajo (in Korean)
Big data analysis with R and Apache Tajo (in Korean)Gruter
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계Chiwon Song
 
Introduction to Parallel Programming
Introduction to Parallel ProgrammingIntroduction to Parallel Programming
Introduction to Parallel ProgrammingUNIST
 
C Language I
C Language IC Language I
C Language ISuho Kwon
 
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracleTABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle엑셈
 
웹개발자가 알아야할 기술
웹개발자가 알아야할 기술웹개발자가 알아야할 기술
웹개발자가 알아야할 기술jaypi Ko
 
세션1. block chain as a platform
세션1. block chain as a platform세션1. block chain as a platform
세션1. block chain as a platformJay JH Park
 
HTTP 완벽가이드- 19장 배포시스템
HTTP 완벽가이드- 19장 배포시스템HTTP 완벽가이드- 19장 배포시스템
HTTP 완벽가이드- 19장 배포시스템박 민규
 

Similar to Programming Cascading (20)

7가지 동시성 모델 람다아키텍처
7가지 동시성 모델  람다아키텍처7가지 동시성 모델  람다아키텍처
7가지 동시성 모델 람다아키텍처
 
하둡 타입과 포맷
하둡 타입과 포맷하둡 타입과 포맷
하둡 타입과 포맷
 
Programming skills 1부
Programming skills 1부Programming skills 1부
Programming skills 1부
 
불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14 불어오는 변화의 바람, From c++98 to c++11, 14
불어오는 변화의 바람, From c++98 to c++11, 14
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST API
 
Cloudera Impala 1.0
Cloudera Impala 1.0Cloudera Impala 1.0
Cloudera Impala 1.0
 
[Swift] Protocol (2/2)
[Swift] Protocol (2/2)[Swift] Protocol (2/2)
[Swift] Protocol (2/2)
 
Presto User & Admin Guide
Presto User & Admin GuidePresto User & Admin Guide
Presto User & Admin Guide
 
Big data analysis with R and Apache Tajo (in Korean)
Big data analysis with R and Apache Tajo (in Korean)Big data analysis with R and Apache Tajo (in Korean)
Big data analysis with R and Apache Tajo (in Korean)
 
Spring boot actuator
Spring boot   actuatorSpring boot   actuator
Spring boot actuator
 
20201121 코드 삼분지계
20201121 코드 삼분지계20201121 코드 삼분지계
20201121 코드 삼분지계
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
Introduction to Parallel Programming
Introduction to Parallel ProgrammingIntroduction to Parallel Programming
Introduction to Parallel Programming
 
C Language I
C Language IC Language I
C Language I
 
Warp
WarpWarp
Warp
 
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracleTABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle
TABLE ACCESS 패턴을 이용한 SQL 튜닝_Wh oracle
 
웹개발자가 알아야할 기술
웹개발자가 알아야할 기술웹개발자가 알아야할 기술
웹개발자가 알아야할 기술
 
Storm 훑어보기
Storm 훑어보기Storm 훑어보기
Storm 훑어보기
 
세션1. block chain as a platform
세션1. block chain as a platform세션1. block chain as a platform
세션1. block chain as a platform
 
HTTP 완벽가이드- 19장 배포시스템
HTTP 완벽가이드- 19장 배포시스템HTTP 완벽가이드- 19장 배포시스템
HTTP 완벽가이드- 19장 배포시스템
 

Programming Cascading

  • 1. Taewook Eom Data Infrastructure Group SK planet taewook@sk.com 2014-09-25 Programming Cascading
  • 2. Big Data Processing 저자동 고유연성 고자동 저유연성
  • 3. Cascading http://www.cascading.org/ Since 2007, by Chris Wensel (CTO, founder of Concurrent, Inc.)
  • 4. Cascading 데이터베이스 기초 개념과 배관(파이프와 연산자)을 비유하여 추상화 제공 엔터프라이즈 data workflow의 비즈니스 프로세스 관리를 위한 패턴 언어
  • 6. Cascading •Flow Planner가 사전 계획 단계(compile time)에서 에러 확인 p.23 –연산에 필요한 필드 p.31 –연산 순서 –파이프와 탭의 연결 상태 –의존성 그래프 생성 -> DAG 생성 p.37 •DAG(Directed Acyclic Graph) –Data work flow에 적합한 형태 –다양한 데이터 처리 엔진에서 사용: Microsoft Dryad, Apache Tez, Apache Spark •엔터프라이즈 환경에 적합 –논리적 계획이 아닌 물리적 계획으로 예측 가능 p.24 –결정적 전략으로 실행마다 물리적 실행 계획이 바뀌지 않음 p.36 –하나의 JAR 파일로 다양한 규모 적용(Same JAR, any scale) p.33 •비즈니스 로직, 시스템 통합, 단위 테스트, 정합성 검사, 예외 처리 모두 포함 •운영상 복잡성 낮춤 p.172 –Ad-hoc Query나 빠른 응답 보다는 Hive처럼 높은 처리량 목적으로 ETL에 적합 p.142 –JAVA 개발자들에게 익숙한 도구와 절차 p.172
  • 7. Cascading Terminology http://docs.cascading.org/cascading/2.5/userguide/html/ch03.html#N2013B 3.1 Terminology •Pipe: Data stream •Filter: Data operation •Tuple: Data record •Branch: 분기나 병합이 없는 간단한 파이프 연결 •Pipe Assembly: Pipe branch들의 연결 집합 •Tuple Stream: Pipe branch나 assembly를 통과하는 Tuple들의 연속 •Tap: Data source/sink •Flow: Tap들과 연결된 한 개 이상의 pipe assembly들의 연결상태 •Cascade –Flow의 집합으로 하나의 프로세스로 실행 –Flow는 다른 flow의 데이터 의존성이 만족될 때까지 실행되지 않음
  • 8. Pipe Types http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes •Each –Filter, Function 적용 –Filter는 Tuple 삭제만 가능 –Function은 필드 추가/변경과 여러 Tuple 출력 가능 –Function의 기본 Output Selector는 Fields.RESULT •Every –GroupBy, CoGroup의 결과에만 사용 –Aggregator, Buffer 적용 •Function, Aggregator, Buffer의 Output Selector 필드 꼭 지정
  • 12. Buffer vs. Aggregator •공통점 –GroupBy, CoGroup의 결과에 대해서만 동작 –Aggregator와 Buffer의 기본 Output Selector는 Fields.ALL •차이점 –Aggregator는 chained되지만 Buffer는 chained되지 않음 –Buffer는 하나의 group에 대해 여러 개 결과 tuple 출력 가능 –Buffer는 Aggregator를 똑같이 구현할 수 있으므로 Aggregator는 Buffer의 특별히 최적화된 형태라 볼 수 있음 pipe = new GroupBy(pipe, new Fields("mdn"), new Fields("log_time")); pipe = new Every(pipe, new Count(new Fields("count"))); pipe = new Every(pipe, new Fields("mdn"), new DistinctCount(new Fields("unique_mdn_cnt"))); pipe = new Every(pipe, new Fields("pay_amt"), new Sum(new Fields("sum"), long.class)); pipe = new Every(pipe, new Fields("log_time"), new Last(new Fields("last_time")));
  • 13. Pipe Types http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes •Merge –Unsorted merge –같은 필드와 타입을 가진 둘 이상의 Pipe들을 하나의 stream으로 병합 –Grouping을 하지 않아 GroupBy보다 빠름 (Aggregator/Buffer 사용불가) •GroupBy –Key 필드에 대해 Sorted merge –같은 필드와 타입을 가진 둘 이상의 Pipe들만 병합 가능 –Group 내 임의의 순서 (속도는 낮아지지만 2차 정렬 가능) –Grouping 만들어 Every를 위한 준비 작업 –Grouping 위해 grouping fields를 정렬해서 Merge 보다 느림 •grouping fields에 대해 natural order로 정렬 –2차 정렬 가능 •2차 정렬 지정하지 않으면 group 내에서 임의 순서지만 더 빠르게 수행 Fields sortFields = new Fields("value1", "value2"); sortFields.setComparator("value1", Collections.reverseOrder()); Pipe groupBy = new GroupBy(assembly, groupFields, sortFields);
  • 14. Pipe Types http://docs.cascading.org/cascading/2.5/userguide/html/ch03s03.html#N20276 Types of Pipes •서로 다른 fields 가진 둘 이상의 stream을 공통 fields 값 기준으로 Join •CoGroup –SQL의 join과 유사(InnerJoin, OuterJoin, LeftJoin, RightJoin, MixedJoin) –outer join의 경우 존재하지 fields들은 null로 채움 –결과에 모든 stream의 모든 fields가 출력되기 때문에, 모든 stream의 fields들은 중복된 이름을 포함할 수 없음 •중복된 이름이 있을 경우 declaredFields 인자로 변경 가능 –field의 순서로 짝맞춤. field 이름은 개발자를 위한 수단일 뿐 –빠른 join 위해 오른쪽 stream의 모든 unique key tuple(bag)을 메모리에 저장 시도 •설정 가능한 임계치를 넘어서면 메모리에서 disk로 쓰면서 진행(성능 저하) •임계치가 클 경우 메모리 에러 유발 •가장 큰 group을 가장 왼쪽에 넣고 적절히 임계치를 조절하면 최고 성능 발휘 •HashJoin –한 개의 큰 stream과 작은 stream들의 join에 최적화 (Map-side Join) •오른쪽 stream을 모두 메모리에 넣어 빠르게 비교 연산 (group 없어 전체 메모리에 올림) –Group 필요없어 임의 순서로 Join하여 CoGroup 보다 빠름 –Group 존재하지 않아 aggregator나 buffer가 뒤따르지 못함 –CheckPoint를 HashJoin 직전에 넣어 작게 된 stream 모두 디스크에 쓰는 방식 유용
  • 16. String inPath = args[ 0 ]; String outPath = args[ 1 ]; Properties properties = new Properties(); AppProps.setApplicationJarClass( properties, Main.class ); HadoopFlowConnector flowConnector = new HadoopFlowConnector( properties ); Tap inTap = new Hfs( new TextDelimited( true, "t" ), inPath ); Tap outTap = new Hfs( new TextDelimited( true, "t" ), outPath ); Pipe copyPipe = new Pipe( "copy" ); FlowDef flowDef = FlowDef.flowDef() .addSource( copyPipe, inTap ) .addTailSink( copyPipe, outTap ); flowConnector.connect( flowDef ).complete(); https://github.com/Cascading/Impatient/blob/master/part1/src/main/java/impatient/Main.java p.29 1.2 초간단 케스케이딩 애플리케이션
  • 17. … Tap docTap = new Hfs( new TextDelimited( true, "t" ), docPath ); Tap wcTap = new Hfs( new TextDelimited( true, "t" ), wcPath ); Fields token = new Fields( "token" ); Fields text = new Fields( "text" ); RegexSplitGenerator splitter = new RegexSplitGenerator( token, "[ [](),.]" ); Pipe docPipe = new Each( "token", text, splitter, Fields.RESULTS ); Pipe wcPipe = new Pipe( "wc", docPipe ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef().setName( "wc" ) .addSource( docPipe, docTap ).addTailSink( wcPipe, wcTap ); … https://github.com/Cascading/Impatient/blob/master/part2/src/main/java/impatient/Main.java p.37 1.5 흔한 단어 세기
  • 18. … Fields token = new Fields( "token" ); Fields text = new Fields( "text" ); RegexSplitGenerator splitter = new RegexSplitGenerator( token, "[ [](),.]" ); Fields fieldSelector = new Fields( "doc_id", "token" ); Pipe docPipe = new Each( "token", text, splitter, fieldSelector ); Fields scrubArguments = new Fields( "doc_id", "token" ); docPipe = new Each( docPipe, scrubArguments, new ScrubFunction( scrubArguments ), Fields.RESULTS ); Pipe wcPipe = new Pipe( "wc", docPipe ); wcPipe = new Retain( wcPipe, token ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef().setName( "wc" ) .addSource( docPipe, docTap ).addTailSink( wcPipe, wcTap ); Flow wcFlow = flowConnector.connect( flowDef ); wcFlow.writeDOT( "dot/wc.dot" ); wcFlow.complete(); https://github.com/Cascading/Impatient/blob/master/part3/src/main/java/impatient/Main.java doc_id text doc01 A rain shadow is a dry area on the lee back … doc02 This sinking, dry air produces a rain shadow, … doc03 A rain shadow is an area of dry land that lies … … p.55 2.2 토큰 다듬기
  • 19. public class ScrubFunction extends BaseOperation implements Function { public ScrubFunction( Fields fieldDeclaration ) { super( 2, fieldDeclaration ); } public void operate( FlowProcess flowProcess, FunctionCall functionCall ) { TupleEntry argument = functionCall.getArguments(); String doc_id = argument.getString( 0 ); String token = scrubText( argument.getString( 1 ) ); if( token.length() > 0 ) { Tuple result = new Tuple(); result.add( doc_id ); result.add( token ); functionCall.getOutputCollector().add( result ); } } public String scrubText( String text ) { return text.trim().toLowerCase(); } } https://github.com/Cascading/Impatient/blob/master/part3/src/main/java/impatient/ScrubFunction.java p.49 2.1 사용자 정의 연산
  • 20. p.55 2.2 토큰 다듬기
  • 21. … String stopPath = args[ 2 ]; … Fields stop = new Fields( "stop" ); Tap stopTap = new Hfs( new TextDelimited( stop, true, "t" ), stopPath ); … Fields scrubArguments = new Fields( "doc_id", "token" ); docPipe = new Each( docPipe, scrubArguments, new ScrubFunction( scrubArguments ), Fields.RESULTS ); Pipe stopPipe = new Pipe( "stop" ); Pipe tokenPipe = new HashJoin( docPipe, token, stopPipe, stop, new LeftJoin() ); tokenPipe = new Each( tokenPipe, stop, new RegexFilter( "^$" ) ); Pipe wcPipe = new Pipe( "wc", tokenPipe ); wcPipe = new Retain( wcPipe, token ); wcPipe = new GroupBy( wcPipe, token ); wcPipe = new Every( wcPipe, Fields.ALL, new Count(), Fields.ALL ); FlowDef flowDef = FlowDef.flowDef() .setName( "wc" ) .addSource( docPipe, docTap ) .addSource( stopPipe, stopTap ) .addTailSink( wcPipe, wcTap ); … https://github.com/Cascading/Impatient/blob/master/part4/src/main/java/impatient/Main.java stop a about after all along an and Any … p.57 2.3 복제 조인
  • 22. p.57 2.3 복제 조인
  • 23. … String tfidfPath = args[ 3 ]; … Fields fieldSelector = new Fields( "doc_id", "token" ); tokenPipe = new Retain( tokenPipe, fieldSelector ); … Pipe tfPipe = new Pipe( "TF", tokenPipe ); Fields tf_count = new Fields( "tf_count" ); tfPipe = new CountBy( tfPipe, new Fields( "doc_id", "token" ), tf_count ); Fields tf_token = new Fields( "tf_token" ); tfPipe = new Rename( tfPipe, token, tf_token ); Fields doc_id = new Fields( "doc_id" ); Fields tally = new Fields( "tally" ); Fields rhs_join = new Fields( "rhs_join" ); Fields n_docs = new Fields( "n_docs" ); Pipe dPipe = new Unique( "D", tokenPipe, doc_id ); dPipe = new Each( dPipe, new Insert( tally, 1 ), Fields.ALL ); dPipe = new Each( dPipe, new Insert( rhs_join, 1 ), Fields.ALL ); dPipe = new SumBy( dPipe, rhs_join, tally, n_docs, long.class ); Pipe dfPipe = new Unique( "DF", tokenPipe, Fields.ALL ); Fields df_count = new Fields( "df_count" ); dfPipe = new CountBy( dfPipe, token, df_count ); Fields df_token = new Fields( "df_token" ); Fields lhs_join = new Fields( "lhs_join" ); dfPipe = new Rename( dfPipe, token, df_token ); dfPipe = new Each( dfPipe, new Insert( lhs_join, 1 ), Fields.ALL ); Pipe idfPipe = new HashJoin( dfPipe, lhs_join, dPipe, rhs_join ); https://github.com/Cascading/Impatient/blob/master/part5/src/main/java/impatient/Main.java p.71 3.1 TF-IDF 구현 tfPipe: (“doc_id”, “tf_token”, “tf_count”) dPipe: (“doc_id”) dfPipe: (“doc_id”, “token”) tfPipe: (“doc_id”, “token”, “tf_count”) dPipe: (“doc_id”, “tally”) dPipe: (“doc_id”, “tally”, “rhs_join”) dPipe: (“rhs_join”, “n_docs”) dfPipe: (“token”, “df_count”) dfPipe: (“df_token”, “df_count”) dfPipe: (“df_token”, “df_count”, “lhs_join”) idfPipe: (“df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”)
  • 24. Pipe tfidfPipe = new CoGroup( tfPipe, tf_token, idfPipe, df_token ); Fields tfidf = new Fields( "tfidf" ); String expression = "(double) tf_count * Math.log( (double) n_docs / ( 1.0 + df_count ) )"; ExpressionFunction tfidfExpression = new ExpressionFunction( tfidf, expression, Double.class ); Fields tfidfArguments = new Fields( "tf_count", "df_count", "n_docs" ); tfidfPipe = new Each( tfidfPipe, tfidfArguments, tfidfExpression, Fields.ALL ); fieldSelector = new Fields( "tf_token", "doc_id", "tfidf" ); tfidfPipe = new Retain( tfidfPipe, fieldSelector ); tfidfPipe = new Rename( tfidfPipe, tf_token, token ); Pipe wcPipe = new Pipe( "wc", tfPipe ); Fields count = new Fields( "count" ); wcPipe = new SumBy( wcPipe, tf_token, tf_count, count, long.class ); wcPipe = new Rename( wcPipe, tf_token, token ); wcPipe = new GroupBy( wcPipe, count, count ); FlowDef flowDef = FlowDef.flowDef() .setName( "tfidf" ) .addSource( docPipe, docTap ) .addSource( stopPipe, stopTap ) .addTailSink( tfidfPipe, tfidfTap ) .addTailSink( wcPipe, wcTap ); … https://github.com/Cascading/Impatient/blob/master/part5/src/main/java/impatient/Main.java p.71 3.1 TF-IDF 구현 tfidfPipe: (“doc_id”, “tf_token”, “tf_count”, “df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”) tfidfPipe: (“doc_id”, “tf_token”, “tf_count”, “df_token”, “df_count”, “lhs_join”, “rhs_join”, “n_docs”, “tfidf”) tfidfPipe: (“tf_token”, “doc_id”, “tfidf”) tfidfPipe: (“token”, “doc_id”, “tfidf”)
  • 25. p.71 3.1 TF-IDF 구현
  • 26. Programming Tips •Local Mode –Hadoop 사용하기 전에 로컬 파일을 이용해 개발/테스트/데이터 탐색 –Hadoop API를 사용하지 않고, 메모리에서만 동작(메모리에 제한) –로컬 테스트 가능하나 로컬과 Hadoop 미묘한 API 차이 있음 •cascading-hadoop-2.0.x.jar 대신 cascading-local-2.0.x.jar 사용 •FileTap, LocalFlowConnector 사용 •Test p.80 –CascadingTestCase –Debug http://docs.cascading.org/cascading/2.5/userguide/html/ch09s02.html –Assert •http://docs.cascading.org/cascading/2.5/userguide/html/ch08s02.html •http://docs.cascading.org/cascading/2.5/userguide/html/ch09s09.html –Trap http://docs.cascading.org/cascading/2.5/userguide/html/ch08s03.html –Sample http://docs.cascading.org/cascading/2.5/userguide/html/ch09s03.html –Checkpoint •http://docs.cascading.org/cascading/2.5/userguide/html/ch08s04.html •http://docs.cascading.org/cascading/2.5/userguide/html/ch08s05.html
  • 27. Programming Tips •작은 의미 구분으로 SubAssembly와 Flow를 만들고 Cascade 연결 •Flow 연결 –Head, Tail, Assembly들은 "이름" 통해서 연결되므로 이름 명시 중요 –DAG로 되어 있어 마지막 sink들로 부터 역으로 연결 여부 검사 –Pipe는 이전 Pipe의 이름 물려 받으므로 명시적 이름 구분이 runtime 오류 방지 •필드 이름은 _, 소문자, 숫자만 사용 –한글이나 –는 Janino compiler를 사용하는 Expression 함수에서 오류 발생 –"first-name“은 필드 이름에 적합하지만, Expression에 사용되면 first-name.trim() 처럼 인식하면서 Janino에서 runtime 오류 발생 –Expression function 보다 function 구현이 Janino 문제도 없고 재사용 쉬움 •GroupBy의 sort 필드는 class type 먼저 맞추기 –HDFS에 저장 후 다시 읽으면 무조건 String 타입으로 변경됨 •Operation 재사용을 위해 전역변수나 property 이용 최소화하고 operation의 constructor 에 인자 넘기기
  • 28. Programming Tips •Reducer 개수 지정 –중간 Reducer 개수 –최종 Reducer 개수 Properties properties = new Properties(); properties.put("mapred.reduce.tasks", “10”); properties.put("mapred.map.tasks.speculative.execution", "true"); properties.put("mapred.reduce.tasks.speculative.execution", "false"); properties.put("mapred.job.priority", “HIGH”); AppProps.setApplicationJarClass(properties, Main.class); FlowConnector flowConnector = new HadoopFlowConnector(properties); TextDelimited scheme = new TextDelimited(new Fields(“key“, “value”), true, "t"); scheme.setNumSinkParts(1); Tap sinkTap = new Hfs(scheme, outputPath, SinkMode.REPLACE);
  • 29. •http://docs.cascading.org/cascading/2.5/userguide/html/ch09.html 9. Built-In Operations –Identity Function –Text Functions –Regular Expression Operations –Java Expression Operations –Buffers •http://docs.cascading.org/cascading/2.5/userguide/html/ch10.html 10. Built-in Assemblies –AggregateBy (AverageBy, CountBy, SumBy, FirstBy) –Rename –Retain –Unique •http://docs.cascading.org/cascading/2.5/userguide/html/ch13.html 13. Cookbook Programming Tips
  • 31. public class DistinctCount extends BaseOperation<HashSet<String>> implements Aggregator<HashSet<String>> { public DistinctCount(Fields fieldDeclaration) { super(fieldDeclaration); } @Override public void start(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { if (aggregatorCall.getContext() == null) { aggregatorCall.setContext(new HashSet<String>()); } else { aggregatorCall.getContext().clear(); } } @Override public void aggregate(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { TupleEntry argument = aggregatorCall.getArguments(); HashSet<String> context = aggregatorCall.getContext(); context.add(argument.getTuple().toString()); } @Override public void complete(FlowProcess flowProcess, AggregatorCall<HashSet<String>> aggregatorCall) { aggregatorCall.getOutputCollector().add(new Tuple(aggregatorCall.getContext().size())); } }