Lucene n-gram 테스트 코드와 간단 해설

Lucene이 예전엔 몇몇 언어들을 위한 단순 명사 추출, 어절 추출, 띄어쓰기 수준의 것들만 제공했기 때문에 한글같은 경우엔 검색 품질이 영 꽝이었다. "한글 검색하려면 어떻게 하나요?" 라는 문장에서 "검색" 만 추출해서 색인하는게 뭔가 별도의 한글 관련 library 가 없으면 불가능했다라는 얘기. 그러나 최근 버전은 (이것도 꽤 오래전 얘기지만) 한글 명사, 조사, 불용어 제거 등등 고급 parsing 까진 아니더라도 n-gram tokenization 방식으로 어느 정도 해결이 가능케 해놨다.

http://en.wikipedia.org/wiki/N-gram

아래의 코드는 3.0.1 을 다운받아서 sample로 구현한것인데 결과를 먼저 보자.
"아버지가방에들어가신다" 를 색인하면 단어 n개의 연쇄를 추출해서 색인하는데, 이 때문에 "아버지"를 검색하면 걸려든다. 물론 단점으로는 "가방"을 검색해도 걸려든다. (-_-;)

Optimizing index...
188 total milliseconds
Term: content:가방
Term: content:가신
Term: content:들어
Term: content:방에
Term: content:버지
Term: content:신다
Term: content:아버
Term: content:어가
Term: content:에들
Term: content:지가
Term: seqid:2
Searching for: 가방
1 total matching documents
My seq ID: 2

이것도 몇 년만이라 20분정도를 소요했다. (-_-;;)

public void testLucene() {
    try {
      File index = new File("index");
      Date start = new Date();

      IndexWriter writer = new IndexWriter(FSDirectory.open(index),
          new CJKAnalyzer(Version.LUCENE_30), true,
          new IndexWriter.MaxFieldLength(1000000));

      Document doc = new Document();
      doc
          .add(new Field("seqid", "2", Field.Store.YES,
              Field.Index.NOT_ANALYZED));
      doc.add(new Field("content", "아버지가방에들어가신다", Field.Store.YES,
          Field.Index.ANALYZED));
      writer.addDocument(doc);

      System.out.println("Optimizing index...");
      writer.optimize();
      writer.close();

      Date end = new Date();

      System.out.print(end.getTime() - start.getTime());
      System.out.println(" total milliseconds");

      IndexReader reader = IndexReader.open(
          FSDirectory.open(new File("index")), true);
      TermEnum termEnum = reader.terms();

      while (termEnum.next() == true) {
        Term term = termEnum.term();
        System.out.println("Term: " + term);
      }

      Searcher searcher = new IndexSearcher(reader);
      Analyzer analyzer = new CJKAnalyzer(Version.LUCENE_30);
      QueryParser parser = new QueryParser(Version.LUCENE_30, "content",
          analyzer);
      System.out.println("Searching for: 가방");
      Query query = parser.parse("가방");

      TopScoreDocCollector collector = TopScoreDocCollector.create(50, false);
      searcher.search(query, collector);
      ScoreDoc[] hits = collector.topDocs().scoreDocs;

      int numTotalHits = collector.getTotalHits();
      System.out.println(numTotalHits + " total matching documents");
      
      collector = TopScoreDocCollector.create(numTotalHits, false);
      searcher.search(query, collector);
      hits = collector.topDocs().scoreDocs;

      for (int i = 0; i < hits.length; i++) {

        Document docss = searcher.doc(hits[i].doc);
        String path = docss.get("seqid");
        System.out.println("My seq ID: " + path);
        
      }

    } catch (Exception e) {
      e.printStackTrace();
    }

  }
}

Problem with Zend Gdata and include path

Today, I spent a lot of time to install the Zend Gdata. I couldn't passed the InstallationChecker.php with below message:

Zend Framework Installation Errors :

Exception thrown trying to access Zend/Loader.php using 'use_include_path' = true. Make sure you include Zend Framework in your include_path which currently contains: .:/usr/share/php:/usr/local/src/Zend-Gdata/library

I thought that it's a problem related to configurations and 'include_path', but It was simply permission problem. Solution?

Make sure httpd can read Zend/Loader.php. That's all. :/

Challenges Of Life

Now i'm downloading the BBC Documentaries, titled "Challenges of life". I didn't watched yet but i knew, the life is an endless chain of challenges.

It is common to all life on earth. I also still challenge (just to survive), reading book called Status Anxiety (Alain de Botton). :/

Blogger 모바일 웹 꾸미기

Blogger 이놈들은 아직까지 Mobile Web 버전을 제공하지 않고 있습니다. 하지만 깔끔하게 정리할 수 있는 꽁수가 있지요. :)

바로 mobile feed reader 를 사용하는겁니다. Layout에 Edit HTML툴을 사용해서 header 태그 사이에 아래와 같이 입력합니다:

<script>
if(navigator.platform == 'iPhone') {
window.location="http://www.google.com/reader/m/view/feed/{$YOUR_FEED_URL}";
}
</script>

그러면 모바일에선 아래와 같이 출력됩니다.

Installing php5.2 on CentOS,

For enabling it run the following commands:

# vi /etc/yum.repos.d/utterramblings.repo

[utterramblings]
name=Jason's Utter Ramblings Repo
baseurl=http://www.jasonlitka.com/media/EL$releasever/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka

After just update your php

#yum update php

PHP caching

<?
$cachefile = 'cache/filename.cache';
$cachetime = 60; // 60 sec
// Serve from the cache if it is younger than $cachetime
if (file_exists($cachefile) && (time() - $cachetime < filemtime($cachefile))) {
 include($cachefile);
 echo "<!-- Cached ".date('jS F Y H:i', filemtime($cachefile))." -->";
 exit;
}
ob_start(); // start the output buffer
?>

your HTML / normal php code here.

<?
$fp = fopen($cachefile, 'w'); // open the cache file for writing
fwrite($fp, ob_get_contents()); // save the contents of output buffer to the file
fclose($fp); // close the file
ob_end_flush(); // Send the output to the browser
?> 

Problems of Tomcat Session Clustering

Today, I tryied to session clustering between two tomcat servers, reading cluster-howto document for tomcat-6.0.

My system is as below:
Server1: (HTTPD + tomcat1)
Server2: (only tomcat2 w/o HTTPD)

    Apache HTTPD
        /          \
      /              \
 tomcat1      tomcat2

However, I'm not familiar with web programs, so it was difficult and spent a lot of time. (-_-;;) But, I finally succeed in configuring. There was some problems with firewall settings and route configurations. I'd like to share them with you.

1) firewall settings

Check that multicast port is on your UDP open list and the receiver TCP port is also for both machines open! I added below list to iptables.

-A RH-Firewall-1-INPUT -p udp --dport 45564 -d 228.0.0.4 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp --dport 4000 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 4000 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 45564 -j ACCEPT

2) network interface for multicast

# route add -host 228.0.0.4 dev eth0
# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
228.0.0.4       0.0.0.0         255.255.255.255 UH        0 0          0 eth0
192.168.123.0   0.0.0.0         255.255.255.0   U         0 0          0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 eth0
0.0.0.0         192.168.123.254 0.0.0.0         UG        0 0          0 eth0

Driving on Bundang-Suseo highway

Recently, I'm on vacation. The video was recorded when I went to a mart and bought some computer stuff.

The scene looked like a road of cherry blossoms. The computer was in my trunk but, I couldn't control my speeding instinct. :)

장자의 진인(眞人) 철학 - 목계지덕

어느 왕이 투계를 몹시 좋아하여 뛰어난 싸움닭을 들고 기성자란 당시 최고의 투계 사육사를 찾아가 최고의 투계로 만들어 달라고 부탁했다. 열흘이 지난 뒤 왕이 기성자에게 물었다. “닭이 충분히 싸울 만한가?” 기성자는 이렇게 대답하였다. “아닙니다. 아직 멀었습니다. 닭이 강하긴 하나 교만하여 아직 자신이 최고인 줄 알고 있습니다. 그 교만을 떨치지 않는 한 최고의 투계라 할 수 없습니다.”

열흘 뒤 왕이 또 물었을 때 기성자는 이렇게 대답하였다. “아직 멀었습니다. 교만함은 버렸으나 상대방의 소리와 그림자에도 너무 쉽게 반응합니다. 태산처럼 움직이지 않는 진중함이 있어야 최고라 할 수 있습니다.”

열흘이 지난 뒤 왕이 다시 묻자 그는 “아직 멀었습니다. 조급함은 버렸으나 상대방을 노려보는 눈초리가 너무 공격적입니다. 그 공격적인 눈초리를 버려야 합니다.”

또 열흘이 지난 뒤 왕이 묻자 “이제 된 것 같습니다. 상대방이 소리를 질러도 아무 반응을 보이지 않고 완전히 마음의 평정을 찾았습니다. 나무와 같은 목계(木鷄)가 되었습니다. 닭의 덕이 완전해졌기에 이제 다른 닭들은 그 모습만 봐도 도망갈 것입니다.”

장자는 이야기에서 최고의 투계는 목계(木鷄)라는 것을 말하고자 한다. 그리고 목계가 되려면 세 가지 조건이 있다.

첫째, 자신이 제일이라는 교만함을 버려야 한다. 자신이 최고라고 으스대는 사람이 배워야 한다.
둘째, 남의 소리와 위협에 쉽게 반응하지 않아야 한다. 누가 뭐라고 하면 쉽게 반응하고 화를 내는 사람이 배워야 한다.
셋째, 상대방에 대한 공격적인 눈초리를 버려야 한다. 누구든 싸우고 경쟁하려고 하는 사람이 배워야 한다.

목계는 인간으로 말하면 완전한 자아의 성취와 평정심을 이룬 사람의 모습이라 할 수 있다. 내가 가지고 있는 특별한 광채와 능력을 상대방에게 드러내지 않기에 그 빛은 더욱 빛날 수 있다. 나무로 만든 닭처럼 평정을 유지할 수 있기에 남들이 쉽게 도발하지 못한다. (박재희 글)

엎질러진 물

옛날...
중국에 공부는 좋아하지만
일은 전혀 않는 여상이라는 남자가 있었단다.

여상에겐 아내가 있었는데 정작 그 여상이란놈은 책만 읽지,
일은 하나도 안해 집은 찢어지게 가난했던거야.

정나미가 떨어진 마누라는 결국 집을 나가고 말았지.
그로부터 얼마 후...,

여상은 왕에게 능력을 인정받아 곧 크게 출세하게 돼.
그때 홀연히 가출했던 마누라가 돌아오지.
다시 인연을 회복하고 싶다면서...,

그런데 여상은 묵묵히 그릇에 물을 퍼 갖고 나와 뜰 앞에다 쏟았어.
그리고, ... '그럼 그 물을 그릇에 다시 돌려놓아 보시오' 라고 했어.
하지만 물은 이미 땅에 스며들어 퍼담을 수 없었지...

그러자 여상은 말했어.
'한번 엎질러진 물은 원래 그릇에 되담을 수 없는 법이오.' 라고.

권력

슈퍼클래스라는 조나단 '재미없는' 책을 조용히 읽다가, 간만에 마음에 드는 문구를 발견한다.

한 인간의 됨됨이를 시험해 보려거든 그에게 권력을 줘 보라 - 링컨