메뉴 건너뛰기

Cloudera, BigData, Semantic IoT, Hadoop, NoSQL

Cloudera CDH/CDP 및 Hadoop EcoSystem, Semantic IoT등의 개발/운영 기술을 정리합니다. gooper@gooper.com로 문의 주세요.


1. data준비

(각 File1, File2는 hdfs상에 존재해야한다,

 즉, hadoop fs -put UserDetails.txt  DeliveryDetails.txt /data1/hadoop/mr/in을 실행한다)

File 1 – UserDetails.txt(mobile#, 사용자이름)
123 456, Jim
456 123, Tom
789 123, Harry
789 456, Richa
 
File 2 – DeliveryDetails.txt(mobile#, 상태코드)
123 456, 001
456 123, 002
789 123, 003
789 456, 004
 
File 3 – DeliveryStatusCodes.txt(상태코드, 상태코드명)
001, Delivered
002, Pending
003, Failed
004, Resend
 
* File3은 os 파일시스템에 존재해야한다.
(예, /home/hadoop/hadoop/working/DeliveryStatusCodes.txt)
2. 예상되는 최종 결과 포맷
Jim, Delivered
Tom, Pending
Harry, Failed
Richa, Resend
 
3. UserFileMapper.java
package com.gooper.join;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
public class UserFileMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text> {
 private String cellNumber, customerName, fileTag="CD~";
 public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {
  String line = value.toString();
  
  String splitarray[] = line.split(",");
  cellNumber = splitarray[0].trim();
  customerName = splitarray[1].trim();
  // reducer에서의 구분을 위해서 value값 앞에 "CD~"를 붙여준다.
  output.collect(new Text(cellNumber),  new Text(fileTag+customerName));
  }
 }
 
4. DeliverFileMapper.java
package com.gooper.join;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reporter;
public class DeliverFileMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, Text> {
private String cellNumber, deliveryCode, fileTag="DR~";
public void map(LongWritable key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {
 String line = value.toString();

 String splitarray[] = line.split(",");
 cellNumber = splitarray[0].trim();
 deliveryCode = splitarray[1].trim();
 // reducer에서의 구분을 위해서 value값 앞에 "DR~"를 붙여준다.
 output.collect(new Text(cellNumber),  new Text(fileTag+deliveryCode));
 }
}
 
5. SmsDriver.java
package com.gooper.join;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
public class SmsReducer extends MapReduceBase implements Reducer<Text, Text, Text, Text> {
 private String customerName, deliveryReport;
 private static Map<String,String> DeliveryCodesMap = new HashMap<String,String>();
 
 public void configure(JobConf job) {
  loadDeliveryStatusCodes();
 }
 
 public void reduce(Text key, Iterator<Text> values, OutputCollector<Text,Text> output, Reporter reporter) throws IOException {
  while(values.hasNext()) {
   String currValue = values.next().toString();
   String valueSplitted[] = currValue.split("~");
   String keyValue = key.toString();
   
   System.out.println("키값 , 라인값 : "+keyValue+","+currValue);
   //System.out.println("reporter값 : "+reporter.toString());
   
   // CD로 시작되면 고객명을 그대로 사용하고..
   if(valueSplitted[0].equals("CD")) {
    customerName = valueSplitted[1].trim();
   // DR로 시작되면 code값이므로 code에 대한 값을 찾아서 그 명칭을 출력한다.
   } else if(valueSplitted[0].equals("DR")) {
    deliveryReport = DeliveryCodesMap.get(valueSplitted[1].trim());
   }
  }
  if(customerName != null && deliveryReport != null) {
   output.collect(new Text(customerName+"("+key+")"), new Text(deliveryReport));
  } else if(deliveryReport == null) { // codeㅇ mapping되는 값이 없으면 "deliveryReport"라는 문자열 자체를 출력한다.   
   output.collect(new Text(customerName+"("+key+")"),  new Text("deliveryReport"));
  }
 }
 
 private void loadDeliveryStatusCodes() {
  String strRead;
  try {
                       
    //BufferedReader reader = new BufferedReader(new FileReader("/data1/hadoop/mr/in/DeliveryStatusCodes.txt"));
       // 여기는 로컬 os파일 위치를 지정해야 함..
    BufferedReader reader = new BufferedReader(new FileReader("/home/hadoop/hadoop/working/DeliveryStatusCodes.txt"));
    
    while((strRead = reader.readLine() ) != null) {
     String splitarray[] = strRead.split(",");
     DeliveryCodesMap.put(splitarray[0].trim(), splitarray[1].trim()) ;
     
    }
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch(IOException e) {
   e.printStackTrace();
  }
 }
}

6. 설명
가. SmsDriver.java에서
MultipleInputs.addInputPath(conf, new Path(args[0]), TextInputFormat.class, UserFileMapper.class);
MultipleInputs.addInputPath(conf, new Path(args[1]), TextInputFormat.class, DeliverFileMapper.class);
을 이용하여 각각의 파일을 읽어 들인다.
이때 읽어들이는 처리는 UserFileMapper와 DeliverFileMapper가 각각 맡는다
이때 join key는 mobile phone no가 된다.
 
나. 두개의 input파일을 reduce에게 보내면 reducer에서는 key를 기준으로 value가 각각의 값을 가지고 있으므로
code값인 경우는 HashMap에 저장된 code정보를 mapping하여 code에 대한 명칭을 output하게 만든다.
최종적으로는 이름과 상태값을 가지는 결과 파일이 만들어진다.
 
다. Reducer에슨 각각의 구분이 필요하므로 Mapper에서 각각의 값에 "CD~" 혹은 "DR~"을 붙여 구분할 수 있도록 선처리를 한다
 
라. 파일을 build하고 jar로 만들고 다음과 같이 실행한다.
hadoop@bigdata-host:~/hadoop/working$ hadoop jar gooper-hadoopexamples.jar com.gooper.join.SmsDriver /data1/hadoop/mr/in/UserDetails.txt /data1/hadoop/mr/in/DeliveryDetails.txt /data1/hadoop/mr/out/join/d
마. 실행 결과 확인
hadoop@bigdata-host:~/hadoop/working$ hadoop fs -cat /data1/hadoop/mr/out/join/d/part-00000
Jim(123 456) Delivered
Tom(456 123) Pending
Harry(789 123) Failed
Richa(789 456) Resend
 
바. reducer에 인입되는 key와 value를 확인하면 아래와 같다.
키값 , 라인값 : 123 456,CD~Jim
키값 , 라인값 : 123 456,DR~001
키값 , 라인값 : 456 123,DR~002
키값 , 라인값 : 456 123,CD~Tom
키값 , 라인값 : 789 123,CD~Harry
키값 , 라인값 : 789 123,DR~003
키값 , 라인값 : 789 456,DR~004
키값 , 라인값 : 789 456,CD~Richa

번호 제목 날짜 조회 수
381 impala테이블 쿼리시 max_row_size 관련 오류가 발생할때 조치사항 2020.02.12 464
380 Class.forName을 이용한 메서드 호출 샘플소스 2016.12.21 465
» 2개 data를 join하고 마지막으로 code정보를 join하여 결과를 얻는 mr 프로그램 2014.06.30 466
378 Apache Toree설치(Jupyter에서 Scala, PySpark, SparkR, SQL을 사용할 수 있도록 하는 Kernel) 2018.04.17 466
377 kafka에서 메세지 중복 consume이 발생할 수 있는 상황 2018.10.23 466
376 impala2를 Cloudera Manager가 아닌 수동으로 설치하는 방법 2018.05.30 468
375 halyard 1.3을 다른 서버로 이전하는 방법 2017.07.05 470
374 Hue Load Balancer를 L4로 L/B하는 경우는 L4쪽 도멘인으로 발행된 인증서를 TLS/SSL항목에 설정해주어야 한다. 2021.10.08 471
373 HiveServer2인증을 PAM을 이용하도록 설정하는 방법 2018.07.21 472
372 [Kudu] tablet server 혹은 kudu master가 어떤 원인에 의해서 replica가 failed상태인 경우 복구하는 방법 2021.05.24 473
371 console명령과 API비교 2015.12.21 475
370 Windows7 64bit 환경에서 ElasticSearch 5.6.3설치하기 2017.10.13 480
369 RHEL 7.4에 zeppelin 0.7.4 설치 2018.07.31 480
368 Permission denied: user=hadoop, access=EXECUTE, inode="/tmp":root:supergroup:drwxrwx--- 오류해결방법 2015.05.17 484
367 Hue impala에서 query결과를 HDFS 파일로 export시 AuthorizationException: User 'gooper1234' does not have privileges to access: db명.query_impala_123456 2022.03.17 484
366 VisualVM 1.3.9을 이용한 JVM 모니터링 file 2016.10.27 486
365 sentry설정후 beeline으로 hive2server에 접속하여 admin계정에 admin권한 부여하기 2018.07.03 486
364 beeline으로 접근시 "User: gooper is not allowed to impersonate anonymous (state=08S01,code=0)"가 발생하면서 "No current connection"이 발생하는 경우 조치 2018.04.15 488
363 namenode오류 복구시 사용하는 명령 2016.04.01 489
362 ontology, jena, sparql등 전반에 대한 설명및 예제를 제공하는 사이트 2015.12.08 490
위로