아직 HBASE에 쓸만한 client tool 이 없는 것 같네요. 

몇몇 오픈소스와 cloudera쪽의 몇개 툴들이 보이긴 합니다만, 무거움은 사람과 시스템을 지치게 만들죠.


찾아보니 HBASE에서 공식적으로 제공되는 API 툴이 있는 것 같습니다.

KVP, Json, XML 등 다양하게 지원하는 듯 하구요, Stargate라는 경량 Servlet container를 Jetty상에서 실행시켜야 사용할 수 있습니다.

 % ./bin/hbase rest start -p <port>  


아래는 실행 화면



자세한 내용은 아래 공식 페이지 참조

 https://wiki.apache.org/hadoop/Hbase/Stargate




InjectorJob

Crawling에 필요한 URL을 crawlDB에 적재하는 작업. 해당 Job을 구동시키기 위해서는 URL 리스트가 제공되어야 하며, 일반적으로 URL Directory를 생성하여 해당정보 파일을 넣어둔다. 다음은 Nutch에서 InjectorJob을 실행시키는 명령어,

#bin/nutch inject crawl/crawldb urls

urls는 crawling 대상 seed URL이 포함된 디렉토리이고, crawldb는 해당 url이 포함된 nutch의 자료구조에 해당된다.


GenerateJob

InjectorJob이 완료되었으며, CrawlDB에 저장된 URL을 fetch (다운로드 및 각종 operation) 해야 한다.

URL에 대해서 fetch작업 이전에 우선적으로 GenerateJob이 실행되어야 하며, 다음은 명령어 이다.

#bin/nutch generate crawl/crawldb crawl/segments

crwaldb는 URL이 생성된 db이며, segment는 crawling시에 필요한 정보를 fetch하는데 필요한 디렉토리이 이다.


FecherJob

GeneratorJob에 의해 생성된 URL을 실질적으로 fetch하는 역할로, GeneratorJob에 의해서 생성되는 input으로 fetch(consume)작업을 수행한다.

#bin/nutch fetch -all

-all 옵션은 Generator에 의해 생성된 모든 URL을 fetch하겠다는 의미이다.


ParserJob

Fetch가 완료된 이후에 URL에 대한 파싱작업을 수행하며, 명령어는 아래와 같다.

#bin/nutch parse -all


DbUpdateJob

일단 ParserJob이 완료되며, FetcherJob에 의해 제공되는 결과를 DB에 Update를 해야한다.이 작업으로 각자의 DB에 가장 최근에 Fetch된 URL의 정보를 update한다. 명령어는 다음과 같다.

#bin/nutch updatedb crawl/crawldb -all

이 작업이 완료되면 DB는 초기 페이지의 update된 정보와 신규 페이지 정보가 DB에 적재된다. 신규 페이지는 Link 정보를 포함된 새롭게 발견된 페이지를 의미한다.


Invertlinks

인덱스를 적용하기 이전에, 모든 링크에 대한 invert가 필요하다.이 작업을 통하여, 특정 페이지에 대해서 anchor text를 인덱스에 적용할 수 있다. 다음은 명령어이다.

#bin/nutch invertlinks crawl/linkdb -dir crawl/segments


Indexing with Apache Solr

크롤링이 완료되며, Nutch에 의해 완료된 URL 데이터에 대해서 Apache Solr로 인덱싱이 가능하다. 인덱싱이 완료되면 특정 URL을 쉽게 검색할 수 있다. 다음은 명령어 이다.

#bin/nutch solrindex http://127.0.0.1:8983/solr/ crawl/crawldb -linkdb crawl/linkdb crawl/segments/*


** 의역 문서 입니다.  (참고 http://www.scala-lang.org/node/107)


Case class는 일반적은 Parameter를 포함하는 생성자를 제공하는 일반적은 클래스와 패턴매칭을 통해 재귀적 객체 추출구성(recursive decomposition)을 제공한다.

아래는 clase class의 예제

abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term


사용상의 편의를 위해서 calse class의 생성시 new 키워드를 사용하지 않아도 된다. 클래스 명을 함수같이 쓰면 된다.

아래의 예제 참고

Fun("x", Fun("y", App(Var("x"), Var("y"))))


생성자의 parameter는 모두 public 변수로 간주되며, 아래와 같이 직접 접근이 가능하다.

val x = Var("x")
Console.println(x.name)

 

모든 case class는 equal method(내부적으로 equality 규칙과 toString method가 재정의 된)가 컴파일러에 의해 자동 생성되어 아래와 같이 사용할 수 있다. 

val x1 = Var("x")
val x2 = Var("x")
val y1 = Var("y")
println("" + x1 + " == " + x2 + " => " + (x1 == x2))
println("" + x1 + " == " + y1 + " => " + (x1 == y1))


위의 실행 결과는 아래

Var(x) == Var(x) => true
Var(x) == Var(y) => false


case class는 아래와 같이 data structure를 구분하는데 사용될 수 있다.

object TermTest extends Application {
  def printTerm(term: Term) {
    term match {
      case Var(n) =>
        print(n)
      case Fun(x, b) =>
        print("^" + x + ".")
        printTerm(b)
      case App(f, v) =>
        Console.print("(")
        printTerm(f)
        print(" ")
        printTerm(v)
        print(")")
    }
  }
  def isIdentityFun(term: Term): Boolean = term match {
    case Fun(x, Var(y)) if x == y => true
    case _ => false
  }
  val id = Fun("x", Var("x"))
  val t = Fun("x", Fun("y", App(Var("x"), Var("y"))))
  printTerm(t)
  println
  println(isIdentityFun(id))
  println(isIdentityFun(t))
}

위의 예제이서, print 함수는 각 matching 상태를 나타내며, match 키워드에 해당 case의 구현체(body)에 matching 되는 형태를 취하고 있다.

isIdentityFun은 주어진 term이 simple identity 조건에 부합하는지를 검사하는 함수이다. 주어진 값이 패턴에 matching된 이후에 if 함수가 실행(evaluate)된다. 성공적으로 매칭된 경우 true를 return 하고 fail인 경우 다음 pattern matching을 시도하게 된다.

실행 결과는 아래와 같다.

^x.^y.(x y)
true
false
x == y는 scala 컴파일러에 의해 구현된 equal 함수에 의해 자동적으로 처리되었음을 확인 할 수 있다.


학창시절 Swing을 정말 열심히 공부했던 기억이 난다.. 그러고 보니 그때가 이미 10년전인가..

Swing은 MVC기반의 Java의 UI Framework으로 기존의 AWT 제약을 탈피하고, 탄생한 Java GUI를 위한 회생의 역작이라고도 할 수 있다..

물론 그 이면에는 MS의 아성을 띄어넘기 위해 PC Client 시장을 장악하기 위한 Sun의 초대회장 Scott Mcnealy의 야심의 결과물인지도 모르겠다..

어찌되었건,

학창시절 정말 열심히 Swing을 공부했다.. Swing은 철저희 MVC의 기본 원칙을 내세우며 완벽에 가까운 객체지향 기반의 API를 제공한다. Swing 한번 정도 해본 사람들이라면 JTable의 악몽을 기억할 것이다. 엑셀같은 간단한 Sheet를 표현하기 위해서 얼마나 많은 Interface와 Class간 의존구조를 알아야 하는지..

그리고 사실상 디자인 패턴이나 중고급이상의 S/W 설계 지식이 없으면 제대로 사용할 수 도 없는, 지금 생각해보면 극악의 어려움을 제공하는 구조임에는 틀림없었으나,

Swing의 사용 경험을 통해 객체지향 설계의 많은 부분을 경험할 수 있었고, 이후에 많은 프로그래밍 설계에 있어서 경험적 지식의 기반이 되었다는 점에서 공부한것에 대해 그리 나쁘지 않았다고 생각된다..


이후, Swing은 거의 사장되고, 아무도 쓰지 않는 상황이 되버렸지만,

어찌보면 Swing을 공부했던 사람들에게 Android는 정말 하늘에서 내려준 선물이 아닐까 생각이 들 정도로, 구조적인 측면 사용성의 측면에서 Swing의 것을 닮아있다..

물론 결국 둘다 GUI 프로그래밍을 위한 것이다 보니 설계의 구조적으로 비슷해 질 수 밖에는 없겠지만..


Android는 Swing 혹은 AWT에서 사용하던 LayoutManager들과 거의 유사한 기능을 제공하며, Swing 코드 작성시 많이 생성되는 반복적이고 Tree 구조의 특성을 xml로 분리하여, 개발 효율을 극대화 시켰다고 봐도 무방할 것 같다.

EventListener를 이용한 이벤트 Handling 방식은 Swing이나 AWT에서 사용했던 방식과 거의 동일하며, 모듈의 Life Cycle 관리나 Paint 메카니즘은등은 Applet의 그것과 매우 유사하다. (이건 뭐 다른 유사 시스템에서 비슷할 것으로 보인다)


Android Platform 초기에는 OSGi 가 탑재될뻔 했던적이 있었던 것으로 생각난다. OSGi 가 탑재되면 개발측면에서 많은 부분 Application 간의 의존성 관리나 App - Service 사용 측면에서 유리한 점이 많아 질 것 같지만, 현 분위기상 쉽지는 않아 보인다.

하둡 MapReduce 개발시, 개발환경을 어떻게 설정해야하는 것이 최선인지는 아직도 고민중입니다.

jar로 배포되어 Hadoop에 의해 로드되어 구동되는 구조적 특성상, 이클립스에 개발환경을 설정해서 뭔가를 해본다는 것이 상당한 제약이 많은 것이 사실이며, 이러한 이유 때문인지는 몰라도 아직 쓸만한 Eclipse Plugin하나 없는 실정입니다. 

Hadoop 정식 배포버전의 contrib 폴더에는 누군가에 의해 개발된 hadoop plugin이 있는데, 어떻게 설치라도 해볼려고 하니 쉽지가 않네요, ant 빌드를 해야하는데 한번에 될리가 없고, 설정상 수정이나 추가가 필요한 부분이 있습니다.

그래서 대략 일주일 삽질끝에 정상 동작하는 이클립스 플러그인으로 빌드하는데 성공하였습니다.

아래의 파일은 이클립스 Indigo(3.7), Hadoop 1.1.0 기준으로 빌드되어 정상동작이 확인되었습니다.


hadoop-eclipse-plugin-1.1.0.jar



타버전의 빌드가 필요하신 분들은 아래 링크를 참고하세요. 

(library 버전이 상위버전인 경우 정상동작 하지 않습니다.)

http://cloudfront.blogspot.kr/2012/07/how-to-run-mapreduce-programs-using.html

http://creatorw.tistory.com/entry/%EC%9D%B4%ED%81%B4%EB%A6%BD%EC%8A%A4%EC%97%90-%ED%95%98%EB%91%A1-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0




'Expired > Hadoop Hbase Nutch2' 카테고리의 다른 글

Hbase를 활용한 로그 모니터링 시스템 개발  (0) 2017.04.15
Hbase JSON API 사용하기  (0) 2015.01.04
Nutch Cycle Step  (0) 2015.01.03
결론부터 말하면 NonBlocking의 원리, Network 프로그래밍일 경우 OS에서 동작하는 Socket의 동작 방식을 모르기 때문이다.

Java의 Standard IO의 경우 사실 단순하다.
하나의 Connection에 대해서 하나의 Thread가 1:1로 대응되어,
개발시 하나의 Connection에 대한 처리 로직이 명확하고, 다른 Connection에 대해 독립적이기 때문이다.

쉽게 말해 개발자가 개발하기 쉬운 구조다.

하지만 NIO의 경우 다수의 Client Connection을 극단적인 경우 하나의 Thread 만으로도 처리할 수 있는 구조이다.

NonBlocking에 대한 심도 깊은 이해가 필요하다.
사실 NonBlocking은 의미적으로는 간단하다.
NonBlocking Method를 호출할때 일반 IO와 달리 Blocking 되지 않고 즉시 Return됨을 의미한다.

하지만 Blocking IO만 접해왔던 개발자들에게 즉시 Return이라는 것은 쉽게 이해할 수 없는 부분이다.

왜냐하면 read(buffer) 라는 method를 call해서 int형으로 넘겨받은 값이, 실질적으로 client에 전송된 byte의 수를 의미하는 것인데, 이것은 달리 해석하면, data 전송이후 실질적으로 client가 해당 data를 consume한 것이 확인 되었을때 알 수 있는 값이기 때문이다.

쉽게 말해서 blocking method 호출시 최소한 작업 완료에 대한 응답값이 필요하다.
서버가 특정 data를 전송했을때, client로 부터 data가 consume되었다는 프로토콜 구조적인 확인이 필요하고, 이때 client의 처리가 지연될 경우 method 호출로 인해 blocking 되는 시간은 길어진다고 볼 수 있다.

다시 본론으로 돌아와서,
그렇다면 NIO 의 write(buffer) 를 호출했을때 어떠한 원리로 blocking 없이 즉시 return 값을 받을수 있을까?

이것을 이해하기 위해서는 OS의 Socket에 대한 이해가 필요하다.
더 자세히 말해 Socket Buffer에 대한 이해가 절대적으로 필요하다. 

결론부터 얘기하면,
Kernel Level의 모든 Socket Object는 자체적인 Read/Write Buffer를 가진다.
Socket Buffer로 넘겨진 data는 실질적으로 OS의 Kernel로 그 제어권이 넘어간 것이라 할 수 있다.
Application Level에서 Socket Buffer의 Data가 넘어가는 순간 실질적인 Data 전송의 스케쥴링은 Socket을 컨트롤 하는 OS에 달렸다고 볼수 있다. (물론 Application Level에서 Socket Buffer의 크기를 조절하여, 간접적인 Data 전송 스케쥴도 가능하긴 하다)
NIO의 핵심 메카니즘은 Socket Buffer에 단순히 Data를 Write하고 Read하는 역할 밖에는 하지 않는다.

단순히 메모리상의 특정 영역(Java Memory Area)에서 OS의 영역(Socket Buffer in Kernel)으로 데이터를 Write/Read하는 작업만을 하기때문에, 실질적으로 Blocking이 없다고 볼 수 있다.

예측할 수 없는 Data가 불규칙적으로 오고가는, Socket Buffer의 Data를 효과적으로 감시하기 위해서는, Polling이 아닌 Event기반의 감시자(Monitor Object)가 필요한데, 그 역할을 하는 것이 NIO의 Selector Object이다.

Selector에 대한 자세한 설명은 다음 강좌에 연재하겠다.

어찌되었건, NIO의 핵심은 구현 관점에서 NonBlocking Call과 Event기반의 처리라 볼 수 있다.
특징은 기존 IO에 비해 구현은 훨씬 복잡해지면서 Thread의 수를 최소화 할 수 있어서 대량접속에 대한 처리에 대해 쓰레드의 Context Switching 비용의 부담에서 벗어 날 수 있다.

물론 구현이 복잡해 지는 만큼, Design(설계)시 고려사항이 많아지며, 필수적이고 잘 알려진, Network, Thread,  I/IO 관련 Design Pattern에 대한 이해가 필수적이다.

-글 : 김영곤(gonni21c@gmail.com)
다음편에 계속..

+ Recent posts