Map & Reduce 함수 형식은 다음과 같다.
입력 -> 중간 -> 출력
map : (K1, V1) -> list(K2, V2)
combine : (K2, list(V2)) -> list(K2, V2)
reduce : (K2, list(V2)) -> list(K3, V3)
partition : (K2, V2) -> 정수 * 적어도 나는 쓸 일이 없었다.
[STUDY:예제 7-1]
MinimalMapReduceWithDedaults.java
public class MinimalMapReduceWithDedaults extends Configured implements Tool {
public int run(String[] args) throws Exception {
JobConf conf = new JobConf(getConf(), this.getClass());
if (conf == null) {
return -1;
}
FileInputFormat.addInputPath(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
conf.setInputFormat(TextInputFormat.class);
/* 맵 타스크 수를 1로 설정하지 않으며 단지 힌트임.
* 실제로는 입력 데이트 크기, 파일 블록 크기에 의해 결정됨.
*/
conf.setNumMapTasks(1);
/*
* 맵 입력키와 출력키가 같은 타입이고, 맵 입력값과 출력값이 같은 타입이면
* 키와 값의 타입에 상관없이 잘 동작한다.
*/
conf.setMapperClass(IdentityMapper.class);
conf.setMapRunnerClass(MapRunner.class); // 각 레코드를 순차적으로 읽어서 매퍼의 map()호출
conf.setMapOutputKeyClass(LongWritable.class); // 맵 출력키
conf.setMapOutputValueClass(Text.class); // 맵 출력값
/*
* 레코드 키를 해시해서 레코드가 어떤 파티션에 속하는 지 결정.
* 각 파티션은 reduce task에 의해 처리.
* Job 내 파티션 개수는 reduce task 개수와 같다.
*/
conf.setPartitionerClass(HashPartitioner.class);
conf.setNumReduceTasks(1);
conf.setReducerClass(IdentityReducer.class); // 변경없이 모든 입력데이터를 출력으로 보냄
conf.setOutputKeyClass(LongWritable.class); // 리듀스 출력키
conf.setOutputValueClass(Text.class); // 리듀스 출력값
/*
* 기본 출력 포맷
* 키/값을 문자열로 변환하고 구분자는 탭을 쓰면서 레코드를 라인단위로 기록.
*/
conf.setOutputFormat(TextOutputFormat.class);
JobClient.runJob(conf);
return 0;
}
}
키의 해시함수가 잘 동작한다면,
1) 모든 레코드가 전체 리듀스 타스크에 고르게 분산되며
2) 같은 키를 갖는 모든 레코드는 같은 리듀스 타스크가 처리한다.
이건 언제 쓰나?
입력 데이터를 정렬하는 효과를 낸다.
스트리밍 응용 프로그램은 구분자를 제어할 수 있다.
[STUDY:표 7-2] 스트리밍 분리자 속성 참조
기본은 탭 문자, 키와 값에 탭 문자가 있을 때 변경하는 것이 바람직하다.
첫 번째 필드에 다른 필드를 더하여 키를 만들어 출력할 수 있다.
Java Interface인 InputSplit에 의해 표현되며, 두 개의 멤버변수를 가진다.
! 데이터에 대한 참조 객체이지 입력 데이터를 포함하지 않는다.
public interface InputSplit extends Writable {
long getLength() throws IOException; // 바이트로 된 길이
String[] getLocations() throws IOException; // 호스트네임 문자열로 된 저장소 위치
}
public interface InputFormat<K, V> {
// numSplits 로 원하는 맵타스크 개수를 설정한다. 임의의 수를 반환하기 때문에 힌트로서만 사용된다.
InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
RecordReader<K, V> getRecordReader(InputSplit split,
JobConf job,
Reporter reporter) throws IOException;
}
매퍼를 실행시키는 유일한 방법.
MultithreadedMapRunner 는 매퍼를 설정된 개수의 thread 개수만큼 동시에 실행시킨다.
원본 데이터로(p.279 [STUDY:그림 7-2]) 파일을 사용하는 모든 InputFormat구현의 기본 클래스이다.
1) Job의 입력 파일 경로
2) 입력 파일의 스플릿을 생성하는 구현체
를 제공한다.
JobConf에 입력 경로를 지정할 수 있도록 4개의 정적 메소드를 제공한다.
public static void addInputPath(JobConf conf, Path path)
public static void addInputPaths(JobConf conf, String commaSeparatedPaths)
public static void setInputPath(JobConf conf, Path... inputPaths)
public static void setInputPath(JobConf conf, String commaSeparatedPaths)
위에서 본 2번 FileInputFormat이 어떻게 스플릿을 만들어 낼까?
max( 최소크기, min(최대크기, 블록크기 ) )
최소크기 < 블록크기 < 최대크기
그래서 스플릿 크기는 블록크기이다.
필요한 시점
e.g. 파일의 모든 레코드가 정렬되었는지 확인해야 할 때 하나의 맵이 파일 전체를 처리할 때 동작할 것이다.
WholeFileInputFormat Code 참조
파일 스플릿을 취해서 단일 레코드로 변환하는 일을 하며,
키는 null, 값은 전체 파일 내용이다.
기본 OutputFormat인 TextOutputFormat에 의해 만들어지는 출력물이 있는데
정확하게 해석하기 위해서는 KeyValueTextInputFormat이 적절하다.
(line1, On the top of the Crumpetty Tree)
(line2, The Quangle Wangle set,)
(line3, But his face you could not see,)
(line4, On account of his Beaver Hat.)
연속돈 레코드(XML문서 조작들)로 구성된 큰 XML문서는 문자열이나 정규표현식을 이용하여
레코드의 시작과 종료 태그를 찾아서 부분 레코드로 나눌 수 있다
StreamXmlRecordReader 를 사용하면 페이지 요소는 매퍼에 의해 처리될 레코드로서 인식될 수 있다.
sequence파일의 키와 값을 Text객체로 변환시킨다.
sequence파일의 키와 값을 임의의 바이너리 객체로 가져온다.
하나는 탭으로 분리된 평범한 텍스트이고 다른 하나는 바이너리 순차 파일이다.
같은 포맷이지만 다른 외형을 가지고 있어서 다른 방식으로 해석해야 한다.
이런 경우, MultipleInput클래스를 사용한다.
MultipleInputs.addInputPath(conf, ncdcInputPath,
TextInputFormat.class, MaxTemperaturerMapper.class);
MultipleInputs.addInputPath(conf, metOfficeInputPath,
TextInputFormat.class, MetOfficeMaxTemperatuerMapper.class);
DBInputFormat 은 관계형 데이터베이스에서 JDBC를 이용하여 데이터를 읽는 입력 포맷이다.
관계형 데이터베이스와 HDFS간 데이터를 옮기는 또 다른 방법으로 스쿱(15장에서)을 고려해 볼 수 있다.
데이터를 여러 개의 파일에 쓸 수 있도록 해 주며 파일명은 출력키와 값으로부터 파생될 수 있다.
| 기능 | MultipleOutputFormat | MultipleOutputs |
|---|---|---|
| 파일과 디렉토리 이름에 대한 완력한 제어 | Yes | No |
| 다른 산출물에서는 다른 타입의 키와 값 사용 가능 | No | Yes |
| 같은 잡에서 맵과 리듀스에 의해 사용 | No | Yes |
| 레코드별 다중 출력물 생성 | No | Yes |
| 어떤 Outputformat도 사용가능 | No(SubClass화) | Yes |
TableOutputFormat은 맵리듀스 결과물을 HBase 테이블로 쓰기 위한 출력 포맷이다.
p.296참조