- 맵리듀스 타입
- map: (K1, V1) → list(K2, V2)
combine: (K2, list(V2)) → list(K2, V2)
partition: (K2, V2) → 정수
reduce: (K2, list(V2)) → list(K3, V3)
- 리듀스의 입력 타입은 맵의 출력 타입과 같아야 함
- 컴바인의 타입은 리듀스의 타입과 같은 경우가 많음
- 파티션은 중간 키와 값(K2, V2)에 대하여 파티션 번호를 반환하며 키에 의해서 결정됨
- 267P 맵리듀스 타입 설정 표 참조
- 기본적인 맵리듀스 잡 - input/ouput만 설정하는 최소 설정과 동일한 명시적인 JobConf 구현
- conf.setInputFormat(TextInputFormat.class)
- conf.setNumMapTasks(1)
- 실제 맵 태스크 개수는 입력 데이터의 크기, 파일의 블록 크기로 결정됨
- conf.setMapperClass(IdentityMapper.class)
- 입력키와 값을 변경 없이 그대로 출력함
- 맵 입력키/출력키, 입력값/출력값이 서로 같은 타입으로 설정되어야 정상적으로 동작함
- conf.setMapRunnerClass(MapRunner.class)
- MapRunnable의 기본 구현체
- 각 레코드를 순차적으로 읽어서 매퍼의 map()메소드를 호출함
- conf.setMapOutputKeyClass(LongWritable.class)
- conf.setMapOutputValueClass(Text.class)
- conf.setPartitionerClass(HashPartitioner.class)
- 레코드의 키를 해시해서 해당 레코드가 어떤 파티션에 속하는지 결정함
- 각 파티션은 리듀스 태스크에 의해 분산 처리됨
- 잡 내에서 파티션 개수는 리듀스 태스크 개수와 같음
- return (key.hashCode() & Integer.MAX_VALUE) % numPartitions
- conf.setNumReduceTasks(1)
- 최적의 리듀서 개수는 클러스터 내의 리듀서 슬롯의 총 개수와 연관이 있음
- 리듀서수를 슬롯의 총 개수보다 약간 작게 설정하는 것이 좋음
- 슬롯의 총 개수 = 클러스터 노드의 개수 * mapred.tasktracker.reduce.tasks.maximum속성값
- conf.setReducerClass(IdentityReducer.class)
- 입력키와 값을 변경 없이 그대로 출력함
- conf.setOutputKeyClass(LongWritable.class)
- conf.setOutputValue(Text.class)
- conf.setOutputFormat(TextOutputFormat.class)
- 기본 스트리밍 잡
- 입력포맷이 TextInputFormat이면 스트리밍 출력의 키와 값은 모두 Text이므로 기본 IdentityMapper를 사용하면 안되고 다른 mapper를 제공해야 함
- command 예시 :
hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-streaming.jar
-input input/ncdc/sample.txt
-output output
-mapper /bin/cat
-inputformat org.apache.hadoop.mapred.TextInputFormat
(-partitioner org.apache.hadoop.mapred.lib.HashPartitioner
-numReduceTasks 1
-reducer org.apache.hadoop.mapred.lib.IdentityReducer
-outputformat org.apache.hadoop.mapred.TextOutputFormat)
- 스트리밍 키와 값
- 키와 값은 구분자로 분리함 (기본 - ‘\t’)
- 구분자로 분리되는 필드들을 더하여 키로 정할 수 있음
- 입력포맷과 출력포맷을 구분하여 설정함
- 275P 스트리밍 분리자 속성 표 참조
- 입력 포맷
- 스플릿과 레코드는 논리적 개념이며 InputSplit 인터페이스의 구현체로 표현됨
- 맵리듀스 프로그래밍에서는 InputSplit을 다루는 (입력 스플릿 생성 및 레코드로의 분할하는) InputFormat 인터페이스 구현체를 사용함
- 크기가 큰 스플릿을 우선으로 순차적으로 처리함으로써 잡 수행시간을 최소화하도록 함
- MultithreadedMapRunner
- MapRunnable의 다른 구현체
- mapred.map.multithreadedrunner.threads 속성의 개수만큼 동시에 매퍼 실행
- 각 레코드를 처리하는 데에 시간이 드는 매퍼에 대하여 적용하면 효과적임
- InputSplit
- long getLength()
- 바이트 길이 반환
- String[] getLocations()
- 호스트네임 문자열로 된 저장소 위치 반환
- InputFormat
- InputSplit[] getSplits(JobConf job, int numSplits)
- hint로서 원하는 맵태스크 개수 설정
- 입력 데이터 크기와 파일 블록 크기로 계산된 임의 개수 반환
- RecordReader<K,V> getRecordReader(InputSplit split, JobConf job, Reporter reporter)
- 레코드의 Iterator 반환
- MapRunner 구현에서 reader로부터 map맵퍼의 입력을 얻음
- while(reader.next(key, value) { mapper.map(key, value, output, reporter); }
- FileInputFormat
- 입력파일 경로 지정 구현 (파일 지정, 파일 패턴 지정)
- addInputPath(s)(..), setInputPaths(..)
- mapred.input.dir 속성
- 특정 입력파일 배제 필터 구현
- setInputPathFilter(..)
- 필터 미설정시 기본 필터로 시스템 숨김 파일 배제 처리
- mapred.input.path.filter.class 속성
- 입력파일 스플릿 생성 구현
- 일반적으로 HDFS 블록보타 큰 파일을 블록 크기의 스플릿으로 분할
- 파일 스플릿의 최소(기본 - 1)/최대(기본 - Long.MAX_VALUE) 바이트 속성 설정 가능
- 최소크기 < 블록크기 < 최대크기
- 스플릿의 레코드 분할에 대한 자식 클래스 구현 강제
- CombineFileInputFormat
- HDFS 블록보다 작은 파일들을 처리할 때 하둡의 성능을 보완함
- 노드와 랙의 위치를 고려하여 블록들을 스플릿으로 묶음
- 추상 클래스이므로 하위 클래스에서 getRecordReader(..) 구현 필요
- SequenceFile을 이용하여 작은 파일을 더 큰 파일로 병합하여 저장하는 것을 권고함
- 스플릿 방지 기법
- 최소 스플릿 크기를 Long.MAX_VALUE로 설정
- FileInputFormat하위 클래스의 하위 클래스를 생성하여 isSplitable() 메소드를 false가 반환되도록 구현
- 매퍼의 파일 정보
- 매퍼는 잡 환경 설정 객체의 속성으로부터 스플릿에 대한 정보를 획득 가능
- 파일 스플릿 속성
- map.input.file - 처리될 입력 파일 경로
- map.input.start - 시작 지점 바이트 오프셋
- map.input.length - 바이트 길이
- 전체 파일을 하나의 레코드로 처리하는 방법
- 285P 예제 소스코드 참조
- FileInputFormat 하위 클래스 구현
- isSplitable() 메소드 오버라이드하여 false 반환
- key → NullWritable, value → BytesWritable로 타입 결정
- RecordReader 구현
- next(key, value) 메소드 내에서 연 파일을 바이트 배열에 넣고, ByteWritable 인스턴스에 바이트 배열을 할당하도록 구현
- TextInputFormat
- 키 → LongWritable - 파일 내에서 라인 시작 지점의 바이트 오프셋 주소
- 값 → Text - 라인의 내용(개행문자 제외)
- FileInputFormat이 정의하는 논리적인 레코드가 HDFS 블록에 정확히 들어맞지 않는 경우, 두 블록에 걸쳐진 레코드까지 포함하여 하나의 스플릿으로 간주함
- KeyValueTextInputFormat
- 키, 구분자, 값이 명시된 텍스트 파일이 입력인 경우 사용
- NLineInputFormat
- 매퍼가 고정된 개수의 입력 라인을 받고자 하는 경우(스플릿에 포함될 라인 수를 고정하는 경우) 사용
- mapred.line.input.format.linespermap 속성 - 입력 라인수 설정
- 시뮬레이션과 같이 작은 양의 입력을 취하고 많은 연산을 수행한 결과물을 내는 응용 프로그램에 적합
- 태스크 타임아웃 발생 방지를 위해 상태나 증가된 카운터를 주기적으로 보고해야 함
- StreamXmlRecordReader
- XML문서 내의 시작, 종료 태그에 대한 정규표현식 패턴을 지정하여 레코드로 나눌 수 있음
- stream.recordrerader.class 속성 - org.apache.hadoop.streamin.StreamXmlRecordReader로 설정
- 입력포맷 - StreamInputFormat
- 바이너리 입력
- SequenceFileInputFormat
- 시퀀스파일을 맵리듀스 입력으로 사용하는 경우 사용
- 파일경로가 디렉토리인 경우 MapFile을 읽는 것으로 간주하여 MapFile을 읽어들일 수도 있음
- SequenceFileAsTextInputFormat
- 시퀀스파일의 키와 값을 Text객체로 변환시키는 경우 사용
- 시퀀스파일을 Streaming을 위한 입력 데이터로 만드는 경우 사용
- SequenceFileAsBinaryInputFormat
- 시퀀스파일의 키와 값을 임의의 바이너리 객체로 변환시키는 경우 사용
- 키와 값은 BytesWritable 객체로 캡슐화됨
- MultipleInputs
- 서로 다른 포맷의 입력을 처리하여 동일한 맵 출력물을 생성하고자 하는 경우 사용
- FileInputFormat.addInputPath()를 오버라이드/오버로드한 메소드 제공
- DBInputFormat
- RDB에서 JDBC로 데이터를 읽는 입력 포맷
- 이 포맷에 대해서 sharding기능이 없으므로 너무 많은 매퍼를 실행해서 대상 DB에 과부하를 주지 않도록 해야 함
- MultipleInputs를 이용하여 HDFS 상의 더 큰 데이터셋과 조인할 작은 데이터셋을 올리는 데에 적합함
- DBOutputFormat으로 잡의 결과물을 DB에 전송함
- 대안으로 SQOOP을 고려할 수 있음
- TableInputFormat/TableOutputFormat - HBase용 입출력 모델
- 출력 포맷
- TextOuputFormat
- 레코드를 텍스트의 라인으로 기록
- toString() - 키, 값을 문자열로 변환
- 바이너리 출력
- SequenceFileOutputFormat
- 시퀀스파일로 출력
- 추가 맵리듀스 잡 존재시 유용함
- SequenceFileAsBinaryOutputFormat
- 바이너리 포맷으로 키, 값을 시퀀스파일 컨테이너로 출력
- MapFileOutputFormat
- MapFiles로 출력
- 리듀서에서 키를 정렬하여 MapFile의 키를 순서대로 추가해야 함
- MultipleOutputFormat / MulipleOutputs
- 리듀서 당 다수의 출력파일을 생성하는 경우 사용
- MultipleOutputs이 더 많은 기능을 가지며 MultipleOutputFormat은 출력 디렉토리 구조와 파일 이름을 제어할 때 유용함
- MultipleOutputFormat
- 파일과 디렉토리 이름에 대한 완벽한 제어 가능
- 하위 클래스 - MultipleTextOutputFormat, MultipleSequenceFileOutputFormat
- protected String generateFileNameForKeyValue(key, value, name) - 하위 클래스에서 재정의하여 사용함
- MultipleOutputs
- 다른 출력파일에서는 다른 타입의 키와 값 사용 가능
- 같은 잡에서 맵과 리듀스에 의해 사용
- 레코드 별 다중 출력파일 생성
- 어떤 OutputFormat도 사용 가능
- LazyOutputFormat
- 출력할 결과가 있을 경우에만 출력파일이 생성되도록 함
- jobconf.setOutputFormatClass(..)에 지정
댓글 없음:
댓글 쓰기