2011년 7월 20일 수요일

lucene의 MoreLikeThis를 사용한 간단한 추천 시스템 만들기

 Lucene의 contrib중 queries 폴더에 보면 MoreLikeThis

 FuzzyLikeThisQuery등이 포함되어 있다.

 사실 추천 시스템이라 말하기 좀 민망하긴 하지만 어찌됐던

 MoreLikeThis를 이용하여 문서 추천시스템을 만드는 것도 가능하다.

 MoreLikeThis는 주어진 다큐먼트의 Term Frequency Vector를 만들고

 이를 통해서 새로운 쿼리를 만드는 기능을 한다.

 즉 인덱싱된 문서중 주어진 문서와 가장 유사한 문서를 찾을수 있도록

 만들어 준다.

 TF를 이용해 문서의 key term을 추출하는 방식은 매우 고전적인 방식이지만

 아직도 많이 쓰인다. 궁금한 분은 다음의 논문을 읽어보도록 하자.


  "Newman, M.E.J. and M. Girvan, 2004. Finding and evaluating community structure in networks. Phys. Rev. E., 69: 026113"



 Lucene In Action 1판, 2판에 모두 MoreLikeThis에 관한 내용이 포함되어

 있으니 책에 있는 코드의 핵심 부분만 간단히 살펴보자.

  IndexReader reader = IndexReader.open(directory);
  MoreLikeThis mlt = new MoreLikeThis(reader);

  ...

  for ( int docID = 0 ; docID < numDocs; docID++){
    ...
    Query query = mlt.like(docID);
   TopDocs similarDocs = searcher.search(query,10);
    ...
  }

  1. 우선 IndexReader를 인자로 주어 MoreLikeThis 객체를 생성한다.

  2. 인덱스된 전체 문서에 대해서 각 문서의 term frequency vector를
      생성하고 이를 통해 query를 만든다.

  3. 주어진 쿼리로 인덱싱된 문서에서 다시 검색을 한다.


 즉 위의 코드는 인덱스된 모든 문서에 대해서 가장 유사한 문서들을

 찾는 역할을 한다.

 MoreLikeThis 객체의 like 메소드는 overloading되어 있어서

 사실 4개의 인자를 받을수 있는데 다음과 같다.

 1. 인덱싱된 문서의 번호


 2. File 객체


 3. reader 객체


 4. url 객체

 2,3,4 번의 경우 직접 term frequency를 구하여 term frequency vector를 만들고

 1번의 경우에는 IndexReader의 getTermFreqVector() 메소드를 이용하여

 term frequency vector만든다.


 lucene 내부에서 사용하는 term frequency vector는 TermFreqVector

 인터페이스를 implements 하거나 implements한 클래스를

 상속하여 만들어진다.

 IndexReader의 종류에 따라 사용하는 TermVector 클래스가 다르므로

이는 나중에 다른 글에서 설명하겠다.


 그럼 org.apache.lucene.demo에 들어있는 SearchFiles를 약간 수정하여

 인덱스된 문서들중 주어진 URL의 문서와 가장 유사한 문서를 찾는 예제를

 간단히 만들어 보겠다.

 1. 우선 다음의 import 구문을 추가한다.

 import org.apache.lucene.search.similar.MoreLikeThis;
 import java.net.*;

 2.  Search시에 사용하는 Query 객체와 관련한 구문을 다음과 같이 수정해보자.

 MoreLikeThis mlt = new MoreLikeThis(reader);
 mlt.setMinTermFreq(2);
 mlt.setMinDocFreq(2);

 Query query = mlt.like(new URL("http://wittgena.blogspot.com/2011/07/lucene-incremental-indexing.html"));


 사용법이 매우 간단하다.

 나머지는 모두 동일하고 while(true){} 구문만 제거하면 될것이다.

 MoreLikeThis에 필드는 따로 지정해주지 않았는데 지정해주지

 않으면 "contents" 필드를 기본값으로 사용한다.

 나의 경우 위의 코드로 linux kernel의 documentation 폴더의 일부 문서를

 인덱싱한후 돌려보니 대략 15개의 문서가 검색이 된다.

 각자 코드를 수정하여 실행해보자. 코드를 첨부한다.

 다운로드


 ps. mahout을 이용하여 lucene에서 term vector를 추출하는 방법도 있다.
      이는 나중에 다른 글에서 설명하도록 하겠다.
      lucene의 TermVector 객체를 알아두면 textmining에
      lucene을 사용할수도 있고 여러모로 유용하다.

댓글 없음:

댓글 쓰기