처음 이 회사에 입사하여 매일 손으로 작업하던 업무들을 정리해가던 중 개인적인 시간을 내어

개발을 했던 것이 검색 로그분석기이다. 단순히, 인기검색어등의 분석만이 아니라

쿼리별 평균응답시간부터, remote client ip, 호출 클래스, 정렬조건, 페이지, 색인시간등 

검색 운영에 필요한 전반적인 정보들을 모두 분석해서 웹으로 보려고 했던 것이 이 개인 프로젝트 시작이었다.


제일 초기버전은 로그를 분석 할 파서를 개발하고

이렇게 분석된 정보들을 Java Programm에서 Map을 사용하여 일별로 집계하는 방식이었다.

그리고, 이렇게 집계된 데이터는 Lucene으로 색인하여 저장하고, 조회 또한 Lucene으로 검색하여

조회하는 방식이었다.


이렇게 약 1년을 사용하다보니 이 프로그램을 유지보수해야하는 다른 파트원들이 접근하기가 쉽지 않은 부분이 있었다.


Lucene 라이브러리 자체도 생소하고

통계를 내는 방식도, select sum group by~ 가 아니라 왠 Map에다 넣어놓고 loop로 돌면서 열개가 넘는 항목을 계산하고 있었으니... 


그래서 1년 후에 이 부분을 고쳐보았다.

우선 파서로 로그를 분석하여, 하나의 로그에 대한 모든 정보 (키워드,정렬조건,페이지,아이디,IP,캐시히트여부..)를 Oracle에 저장한다. 그러면 검색로그의 라인수 만큼의 데이터가 생성된다.


그리고 이것을 SQL을 사용하여 각 항목별로 데이터를 select하고 이 데이터를 Lucene으로 색인 - 조회하는 형태였다.


색인하는 부분의 인터페이스만 수정하였고, 데이터를 만드는 것 자체는 익숙한 SQL을 사용하여 마음대로 추가 할 수 있는 구조였다.


이러한 구조로 또 한 2년을 넘게 사용하였는데.. 이제 다른곳에서 좀 문제가 되기 시작했다.


일단 가장 중요한 것이 Lucene으로 색인된 데이터에 대한 핸들링이 어려운 부분이 가장 컸다.


일단 기본적인 CRUD만 해도 각각의 케이스에 대해서 Lucene 라이브러리로 개발하고

서버에 올려서 이걸 사용해서 java로 실행해야 하는 형태였고..

저장된 데이터를 보는 것도 어려웠다. 데이터가 많지 않을때는 인덱스 파일을 로컬로 내려서 

Luke를 사용하기도 했지만 기본적으로 인덱스 파일 자체가 서버에 있다보니, 이걸 local로 내리기도 쉽지 않았다.


전반적으로 관리할 수 있는 페이지를 만들려고도 했지만 왠지 배보다 배꼽이 더 큰 느낌이었다.


그리고 이러한 문제점은 최근에 한번 만들어보려고 했던 실시간 급상승 인기검색어를

추출하는 프로그램을 개발하는데도 많은 제약이 생겼다. 데이터를 좀 바꿔가면서 테스트하는 것 자체가 너무

어려운 상황..


그래서 한번 바꿔야겠다... 하고 생각하던 중 개발그룹에서 Hadoop Infra를 구축해주었고

마침 관심이 있던차에 이걸 한번 고쳐봐야겠다... 싶었다. 그래서 손을 댄것이 3주째.. 중간에 한 3번 정도 '아 내가 이걸 왜 손댔지...' 하고 심각히 고민했었음.. --;


큰 틀은 하둡으로 로그를 파싱하고 Map-Reduce를 사용해 분석한 다음 이걸 sqoop을 사용하여

MySQL DB에 각 분석 항목을 테이블별로 밀어넣는 방식으로 잡았고, 조회 페이지 또한 MySQL DB에 접근하여 

조회하는 형태로 잡았다.


현재 상태는 분석->MySQL까지 구현 및 셋팅은 다 되어서 분석을 하고 있고

조회페이지 및 원래 이 수정의 목적이었던.. (하마터면 까먹을뻔한 --) 실시간 급상승 인기검색어 로직을 만들고

구현하면 되는 상황..


작년에 하둡관련 서적을 한권 읽어보긴 하였으나 제대로 사용해보지 못하여 거의 머리에서 날아가 있는 상태에서 

1월에 3일동안 Hadoop 책 한권 읽고 개발을 진행한것이라 거의 초보적인 수준의 Map-Reduce 프로그램이고 

성능 또한 고려하지 않아.. 튜닝의 여지도 많은 상태임에는 분명..

그리고, 일별 데이터가 뭐 수백기가까지는 안되는 상황이라 분석 속도가 크게 빨라지지는 않았지만

일별,월별 그리고 사용자가 임의로 요청한 기간동안의 집계를 하둡을 사용해서 가져오도록 (정확히는 Pig나 뭐 그런거겠지만..) 고려를 하고 있어서 일단 Hadoop의 사용은 괜찮은 것 같다.


초보적인 관점에서 AS-IS, TO-BE의 느낌을 보면..


AS-IS (Oracle+Lucene)

1. 보관된 데이터의 핸들링이 어려움 (CRUD)

2. 일별로 집계되는 데이터를, 특정 기간동안 혹은 월별/ 년도별로 만들기가 조금 난해.

3. 특정 키워드등에 대한 검색은 굉장히 좋음 (원래 검색엔진이니..ㅋㅋ)

4. 스킴이 자유로워서 항목을 추가하기 쉬우나, 그만큼 관리도 어려워짐 (이건 설계가 잘못된 문제일수도..)

5. 파싱된 RAW 데이터가 Oracle DB에 있다보니, 운영을 위한 다른 데이터를 얻기가 쉬움 (N초 이상 쿼리등)

6. 분석되어 있는 데이터로부터 2차 가공된 데이터 혹은 2차 가공을 위한 데이터를 얻어내기가 번거로움


TO-BE (Hadoop+MySQL)

1. 분석 - 조회가 완전히 나눠짐.

2. 분석 항목이 약 2배정도 늘어남 (기존에는 성능문제등으로 하지 못 했던.. 의미있는 데이터인지에 대한 검증은 필요)

3. 하둡으로의 분석 속도도 괜찮으나, 분석된 항목이 많아 MySQL로 데이터를 export 할 때 Sqoop의 효율성이 좀 떨어짐. 분석은 몇분 안걸리는데 export 시간이..--; (다소 데이터가 작고 많은 테이블에 대해서는 효율이 좀 떨어지는듯.. 대량 데이터 전송은 속도가 아주 좋았음. 이건 각 sqoop 실행 shell을 백그라운드로 돌리면 좀 더 나을지 테스트 해보려고 함)

4. 조회 페이지에 대한 유지보수가 간단해짐 (일반적인 DB를 사용한 웹어플리케이션)

5. Map-Reduce 프로그래밍이 처음이라서 로그를 보거나 디버깅하는데 상당히 헤맸음.. 


개발자 입장에서는 꼭 필요한 업무를 사용하고 싶었던 라이브러리등을 사용하여 구축해봤던 부분에서는 만족...


저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop, Lucene

1. EXPORT_DIR은 하둡 hdfs:// URI로 접근할때 사용되는 전체 경로
2. --input-fields-terminated-by "\t" key, value간 구분자를 여기서 설정한다. 각 컬럼이 이걸로 구분됨
3. --outdir /data/hadoop/sqoop/generated \
--bindir /data/hadoop/sqoop/generated \

이게.. 설정을 보고 java 코드를 만들고 그걸 compile해서 실행하는 것이었다..
그때 사용되는 dir임.. outdir, bindir


4. jdbc driver는 sqoop_home/lib에 위치..


테스트로.. 컬럼 5개 11만 데이터 insert에 4초가 걸린다.. 테스트DB, 테스트 서버에서..


넣는것도 Map으로 쪼개서 넣는듯..?

저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop, sqoop


오늘 multipleoutputs를 사용해서 reducer를 개발하면서 한 삽질 두가지...


1. 로그파일이 euc-kr이라서, 이걸 간단하게 utf-8로 변환해주는 java 프로그램을 만들어서 컨버팅하고 이걸

hdfs에 올렸다. 그리고 분석을 했는데.. 600메가밖에 안되는데 java heap memory 오류가 발생한다.

별짓을 다하면서 옵션도 수정해보았는데 원인을 찾을 수가 없다.... 혹시나해서 로그파일을 열어보니..

600메가가 1줄이다. 1 row.... 1 line.... 컨버팅하면서 라인별로 개행문자를 안 붙여줬음 -_-

-> 이걸로 오전 2시간 날려먹음 (점심시간 포함)


2. Map Reduce 프로그램을 개발할때.. Mapper의 Output 타입과 Reducer의 Input타입이 맞지 않으면..

예를 들면...


public class ScnCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>


public class ScnCountReducer extends Reducer<Text, DoubleWritable, Text, IntWritable>


위 두개...

최종 결과 파일이 Map된 상태로만 part-r-nnnnn에 떨어집니다..


오늘 multipleoutputs를 사용해서 reducer를 개발하고, 설계가 바뀌어서 기존에 DoubleWritable로 되어있던 것을 IntWritable로 변경하였다. 그리고 돌려보았는데.. multipleoutputs로 설정한 파일들은 생성되지 않고 part-r-nnnnn에 mapper로부터 출력된 결과만 보인다. reduce 자체가 실행이 안된것..


데이터노드 들어가서 reduce 로그를 봐도.. 에러 한줄없다..

"와 이건 또 왜이래.." 하면서 설계전으로 원복해서 돌려보면 또 잘된다.


어쩌다가 발결한 저거.. "어???" 하면서 뒷골이 싸함을 느끼며..

DoubleWritable -> IntWritable로 바꿔보니.. 잘 돈다.. ㅠㅠ

-> 이걸로 점심시간 이후 오후 3시간 날려먹음


그러면서 느낀거...

1. 로컬PC가 윈도우다보니.. map-reduce 프로그램 개발하고 실행하기가 좀 번잡스럽다.

2. 로그 좀.. 어떻게 한곳에 딱 모아서 보는 방법없나.. 데이터노드마다 찾아다니기도 어렵고..

log4j 사용하면 그나마 어디 찍히는지 보이지도 않는다 --; 분명 어딘가에 찍힐텐데...

저작자 표시 비영리 변경 금지
신고
Posted by 용식

hadoop dfsadmin -safemode leave



저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop
하둡 완벽 가이드 책에서는 Mockito와 hamcrest를 사용한 테스트 케이스의 예제와
Tool을 활용하여 Driver의 테스트를 하는 것이 나옵니다. 하지만 Tool을 사용 할 경우 윈도우에서는
cygwin을 설치해야 실제 output을 볼 수가 있는 것 같습니다. 에러 내용을 보면 말이죠...
그런점에서 보면 맥이면 Mockito와 Tool을 사용 한  예제가 더 유용 할 수도 있겠네요..

그리고 책에서 잠깐 언급되는 MRUnit이라는 것이 있는데 이 MRUnit을 사용한 테스트 케이스 예제를 소개하려
합니다.

Mockito를 사용한 예제도 새로운 Map/Reduce API에서 사용되는 Context를 활용하여
작성한 예제를 소개하려고 합니다.

 우선 Mapper, Reducer에 대한 테스트케이스를 메서드로 분리하여
작성해보았습니다. 보시면 두 방법의 차이점에 대해서 한번에 보실 수 있을 거에요..

테스트케이스의 샘플이 되는 예제는
Hadoop example로 들어있는 WordCount에 대한 테스트 케이스입니다.
그럼 우선 WordCountMapper를 보겠습니다.



Mapper에 대한 TestCase 입니다.


Mockito를 사용하기 위해서는 관련 라이브러리가 있어야 하는데 Hadoop을 다운받아 보시면
lib안에 Mockito관련 라이브러리를 받아 보실 수 있습니다.

하둡 완벽 가이드 책에서는 Mockito와 함께 hamcrest를 같이 사용하고 있기 때문에
Assert문이 일반적인 JUnit하고는 조금 다릅니다. 

testWithMockito 메서드를 보시면 mapper를 생성하고
입력의 역할을 할 value Text를 생성합니다.

하둡 완벽 가이드 책에서는 여기서 Collector를 사용하여 테스트케이스를 작성하였지만
최신 API에서는 Context를 사용하므로 이부분을 Context를 사용하여 테스트를 할 수 있도록 하였습니다.
그리고 이 과정에서 org.mockito.Mocktio.mock 메서드를 통해 mock 객체를 생성하여
테스트를 진행합니다.

최종 테스트문은 아래와 같습니다.

verify(context, times(2)).write(new Text("aab"), new IntWritable(1));



aab가 2번 output으로 작성되었다.. 정도로 보시면 될 것 같습니다.
Mapper의 일이 Tokenizer로 잘라서 Context로 넘기는 역할이다 보니
위와 같은 검증을 하는 것 같습니다. (aab가 두번 나오죠?)

실패 할 경우 아래와 같은 메시지가 나옵니다.
아래 메시지는 위 verify문을 아래처럼 고쳤을 때의 메시지입니다.

verify(context, times(3)).write(new Text("aab"), new IntWritable(1));



org.mockito.exceptions.verification.TooLittleActualInvocations: 
context.write(aab, 1);
Wanted 3 times:
-> at com.tistory.devyongsik.WordCountMapperTest.testWithMockito(WordCountMapperTest.java:29)
But was 2 times:
-> at com.tistory.devyongsik.WordCountMapper.map(WordCountMapper.java:23)

at com.tistory.devyongsik.WordCountMapperTest.testWithMockito(WordCountMapperTest.java:29)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)



aab가 3번 나오기를 원했는데 2번만 나왔다는거죠..

그럼 MRUnit은 어떨까요..

MRUnit은 클라우데라(cloudera)에서 배포하는 하둡(CDH)을 받아보시면
그안에 들어있는 라이브러리입니다.

testWithMRUnit 메서드를 보시면 이 메서드에서는 우선 Mapper 객체를 생성하고
MRUnit에서 제공되는 MapDriver 클래스를 사용하여 테스트를 진행합니다.

테스트 데이터는 withInput을 통해 넣고
검사는 withOutput으로 합니다.
검사문을 withInput, withOutput으로 정해놓고 실행은 runTest메서드로 실행을 합니다.

개인적으로 결과의 직관적인 모습으로는 MRUnit이 더 좋아보이네요..

그럼 MRUnit의 테스트케이스 실패는 어떤 모양일까요..
withOutput메서드를 아래와 같이 고쳤을 때의 결과입니다.

driver.withOutput(new Text("aab"), new IntWritable(1));
driver.withOutput(new Text("bbc"), new IntWritable(1));
        driver.withOutput(new Text("aab"), new IntWritable(2));


2011. 7. 31 오후 10:45:34 org.apache.hadoop.mrunit.TestDriver lookupExpectedValue
심각: Matched expected output (aab, 1) but at incorrect position 2 (expected position 0)
2011. 7. 31 오후 10:45:34 org.apache.hadoop.mrunit.TestDriver validate
심각: Missing expected output (aab, 2) at position 2


mapper의 일이 분석 할 데이터를 reduce 할 수 있도록 
분류하는 작업을 한다고 생각하면 MRUnit이 mapper 테스트의 중점을 postion으로 두고 있는 것도
어느정도 이해가 갑니다.

위에서 position 2 라는 것은 3번째 작성 된 driver.withOutput(new Text("aab"), new IntWritable(1));
이 문장을 뜻하는 것으로 보입니다. 제일 처음이 0이겠죠... 결국 심각: Missing expected output (aab, 2) at position 2
라는 것은 3번째 작성된 withOutput 문장에서 잘못된 output이 나왔다.. 라는 것이고.. 그 위에 있는 에러문장은 
실제적으로 1이 나와야하지만.. 뭔가 잘못나왔다.. 라고 하는 것 같죠...

검증자체는 MRUnit이 굉장히 타이트한 것 같습니다. ouput의 순서까지도 검증하니까요..

그러고보니, Mockito와 MRUnit이 테스트의 검증 데이터를 바라보는
관점이 조금 다른 것 같습니다.

다음엔 Reduce쪽을 써볼게요...
 

저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop
Hello World 수준의 Map Reduce 프로그램을 만들어보자.

StandAlone 모드.

우선 분석 할 데이터는
텍스트 파일로 아래와 같이 정의 되어있다.

S 20110712:000000 0 2 scna ....
S 20110712:000001 0 5 scnb ...

우린 여기서 scnX에 해당하는 것들의 카운트를 해 볼 예정이다.

딱 봐도 로그죠.. ~

우선 Mapper가 필요.

  ScnCountMapper.java

간단한 분석..
Mapper<Key, Value, Key, Value>를 상속해야 하는데
앞의 K,V는 파일로부터 입력되는 K,V이다.

나중에 실행하는쪽에서 InputType을 정할 수 있는데 텍스트파일일 경우 기본적으로 Line단위의 Read이고
앞에 Key는 LongWritable로 각  라인 시작지점의 바이트 오프셋 주소이며.. Value는 해당 Line의 Text가 된다.

뒤에 있는 K,V는 Reducer로 보낼 K,V이다.
즉, 이것이 Reducer의 입력 K,V가 된다.

여기서는 scnX의 카운트를 분석 할 것이 때문에 K는 Text가 V는 IntWritable이 되겠다.

  ScnCountReducer.java

Reducer의 간단한 분석.

마찬가지로 Reducer<K , V, K, V>를 상속하는데
앞의 K,V는 Mapper의 출력 K,V로써 타입을 맞춰주면 된다.

뒤의 K,V는 실제 분석 후 output을 작성 할 때 사용되는 K,V로 여기서는 scnX와 카운트가 될 것이므로
역시 Text, IntWritable로 선언하였다.

  ScnCountDriver.java 간단한 분석..

실제로 하둡에 의해서 실행 될 클래스이다.
FileInputFormat에 의해서 입력 받을 파일 경로가 지정되며
FileOutputFormat에 의해서 출력이 써질 경로가 지정된다.

setOutPutKeyClass, setOutputKeyVlaueClass는 Reducer의 출력형태이다.
(일반적으로 같게 한다.)


실행.
컴파일 된 class들을 하둡이 있는 서버로 옮기고
HADOOP_HOME/conf/hadoop-env.sh 파일에 HADOOP_CLASSPATH를 지정한다.

그리고 HADOOP_HOME/bin에서 아래와 같이 실행


./hadoop com.tistory.devyongsik.search.log.ScnCountDriver 분석파일경로/분석파일명 output_scnario


 아래와 같이 실행된다.

11/07/15 13:05:04 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
11/07/15 13:05:04 WARN mapred.JobClient: No job jar file set.  User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
11/07/15 13:05:04 INFO input.FileInputFormat: Total input paths to process : 1
11/07/15 13:05:04 INFO mapred.JobClient: Running job: job_local_0001
11/07/15 13:05:04 INFO mapred.MapTask: io.sort.mb = 100
11/07/15 13:05:04 INFO mapred.MapTask: data buffer = 79691776/99614720
11/07/15 13:05:04 INFO mapred.MapTask: record buffer = 262144/327680
11/07/15 13:05:05 INFO mapred.JobClient:  map 0% reduce 0%
11/07/15 13:05:06 INFO mapred.MapTask: Starting flush of map output
11/07/15 13:05:06 INFO mapred.MapTask: Finished spill 0
11/07/15 13:05:06 INFO mapred.Task: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
... 중략 
11/07/15 13:05:57 INFO mapred.LocalJobRunner:
11/07/15 13:05:57 INFO mapred.Task: Task 'attempt_local_0001_m_000016_0' done.
11/07/15 13:05:57 INFO mapred.LocalJobRunner:
11/07/15 13:05:57 INFO mapred.Merger: Merging 17 sorted segments
11/07/15 13:05:57 INFO mapred.Merger: Merging 8 intermediate segments out of a total of 17
11/07/15 13:05:57 INFO mapred.Merger: Down to the last merge-pass, with 10 segments left of total size: 26071733 bytes
11/07/15 13:05:57 INFO mapred.LocalJobRunner:
11/07/15 13:05:58 INFO mapred.Task: Task:attempt_local_0001_r_000000_0 is done. And is in the process of commiting
11/07/15 13:05:58 INFO mapred.LocalJobRunner:
11/07/15 13:05:58 INFO mapred.Task: Task attempt_local_0001_r_000000_0 is allowed to commit now
11/07/15 13:05:58 INFO output.FileOutputCommitter: Saved output of task 'attempt_local_0001_r_000000_0' to output_scnario
11/07/15 13:06:00 INFO mapred.LocalJobRunner: reduce > reduce
11/07/15 13:06:00 INFO mapred.LocalJobRunner: reduce > reduce
11/07/15 13:06:00 INFO mapred.Task: Task 'attempt_local_0001_r_000000_0' done.
11/07/15 13:06:00 INFO mapred.JobClient:  map 100% reduce 100%
11/07/15 13:06:00 INFO mapred.JobClient: Job complete: job_local_0001
11/07/15 13:06:00 INFO mapred.JobClient: Counters: 16
11/07/15 13:06:00 INFO mapred.JobClient:   File Output Format Counters
11/07/15 13:06:00 INFO mapred.JobClient:     Bytes Written=360
11/07/15 13:06:00 INFO mapred.JobClient:   FileSystemCounters
11/07/15 13:06:00 INFO mapred.JobClient:     FILE_BYTES_READ=5696680093
11/07/15 13:06:00 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=282276018
11/07/15 13:06:00 INFO mapred.JobClient:   File Input Format Counters
11/07/15 13:06:00 INFO mapred.JobClient:     Bytes Read=547403887
11/07/15 13:06:00 INFO mapred.JobClient:   Map-Reduce Framework
11/07/15 13:06:00 INFO mapred.JobClient:     Reduce input groups=17
11/07/15 13:06:00 INFO mapred.JobClient:     Map output materialized bytes=26071815
11/07/15 13:06:00 INFO mapred.JobClient:     Combine output records=0
11/07/15 13:06:00 INFO mapred.JobClient:     Map input records=1312718
11/07/15 13:06:00 INFO mapred.JobClient:     Reduce shuffle bytes=0
11/07/15 13:06:00 INFO mapred.JobClient:     Reduce output records=17
11/07/15 13:06:00 INFO mapred.JobClient:     Spilled Records=3207007
11/07/15 13:06:00 INFO mapred.JobClient:     Map output bytes=23446277
11/07/15 13:06:00 INFO mapred.JobClient:     Combine input records=0
11/07/15 13:06:00 INFO mapred.JobClient:     Map output records=1312718
11/07/15 13:06:00 INFO mapred.JobClient:     SPLIT_RAW_BYTES=1768
11/07/15 13:06:00 INFO mapred.JobClient:     Reduce input records=1312718


결과를 보기위해 output으로 지정된 곳으로가서..
파일을 열어보면 끝,,

위 예제는 standalone 모드 기준입니다.

그래도 뭔가 되긴 하는구나.


 
저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop
참고 : http://blog.softwaregeeks.org/archives/category/develop/hadoop


하둡을 써보자.

하둡에 대한 책을 읽고 있긴한데 이게 태어난 목적이
분산파일 시스템으로서 더 큰 용량의 파일들을 저장하기 위함인지
그러한 데이터들을 빠르게 분석하기 위함인지 잘 모르겠다.

Standalone 모드에서의 예제가 map reduce가 딱 실행되는걸로 봐서는
후자인 것 같기도하고.. 어쩌면 둘 다겠지.. hadoop이 기본적으로
수정되지 않는 파일만 저장이 된다고 하니 분석에 대한 목적이 더 클지도 모르겠다..

아무튼 더 공부를 해봐야 할 것 같고...

우선 Hadoop 라이브러리를 다운 받는다. (http://hadoop.apache.org/)
나는 0.20 버전을 사용했다.

일단 Mac에서 ...

적당한 디렉토리에 받은 파일을 넣고 압축을 해제한다.

need4spdui-MacBook-Air:Java need4spd$mkdir hadoop
need4spdui-MacBook-Air:Java need4spd$gzip -d hadoop-0.20.203.0rc1.tar.gz
need4spdui-MacBook-Air:Java need4spd$tar -xvf hadoop-0.20.203.0rc1.tar



그러면 이 상태.. 그러니까 풀고 아무것도 안 한 상태가 standalone모드로 실행 할 수 있는
confing상태이다.

 우선 JAVA_HOME을 설정해주자.

HADOOP_HOME에 conf디렉토리를 보면 hadoop-env.sh 파일이 있는데 열어서
JAVA_HOME을 찾아서 설정해준다.

export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home



테스트는.. 아래와 같이.. example jar안에 
이런저런 샘플코드들이 있는 듯 하다. 다만 실행하기 위해서 jar를 풀어서 
META-INF를 제거해줘야 한다. (위 링크한 성주님 블로그 참고)

1. Jar를 풀고 다시 Packaging

need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$cd /Users/need4spd/Java/hadoop/hadoop-0.20.203.0
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$mkdir temp
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$cp hadoop-examples-0.20.203.0.jar ./temp
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$cd temp
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$jar -xvf *.jar
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$rm -rf META-INF
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$rm *.jar
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$jar cvf ../hadoop-examples.jar *



2. Test파일 생성

need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$cd ..
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$vi input.txt

R
R
R
r
r
r
r
r



3. 실행

need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$ cd bin

./hadoop jar ../hadoop-examples.jar org.apache.hadoop.examples.WordCount ../input.txt output



4. 결과조회

need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$cd ouput
need4spdui-MacBook-Air:hadoop-0.20.203.0 need4spd$vi part-r-00000

R 3
r 5



샘플코드를 보니 HFS를 사용하여 여러가지 분석을 할 수 있는 코드도 개발이 가능 할 것 같다

이제 첫 걸음이니... 욕심내지말고 차분히 가봐야지...


 
저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG hadoop, 하둡