루씬과 색인,검색 클래스 사용예(Java)

검색엔진로그 2011. 3. 8. 00:41


 

인덱싱 클래스 ATIndexer

인덱싱 데이터는 트위터에서 수집한 status 데이터를 별도 저장한 텍스트 파일을 사용하였으며, 

한건의 트윗글에 대해  status_id(글번호), text(내용), user_id(사용자번호), user_name(사용자이름)  

데이터만 사용하였다. 

루씬이 제공하는  필드에 따라 인덱싱하는 방법을 표현하기 각 데이터에 대해 다음과 같은 필드생성 옵션을 주었다. 

 

 

status_id : Field.UnStored 를 사용. 분석과 검색을 수행하지만, 저장되지 않기 때문에 검색결과에서 보여줄 수는 없음 

text : Field.Text 를 사용. 분석과 검색, 저장을 허용하여, 검색결과로 원문을 보여줄 수 있다. 
user_id : Field.UnIndexed 를 사용. 검색어로 사용할 수 없지만, 다른 필드의 검색결과에서 같이 보여질 수 있다. 

user_name : Field.Keyword 를 사용. 분석을 하지 않지만, 검색과 저장을 한다. 검색시 이 필드는 분석되면 않되기 

때문에 직접 텀쿼리를 만들어 IndexSearcher의 search 메소드에 전달해야한다. 

 

인데싱에 사용한 파일(crawled_text.data)의 포맷  

...

status_id:2147483648
text:@NicoleLapin so many buttons
user_id:12
user_name:Jack Dorsey

status_id:2147483648
text:In alaska for the longest day of the year with Delphine and eWee. Seaplanes. Sunshine.
user_id:14
user_name:noah glass

...

 

소스ATIndexer.java

      lucene-1.4.3.jar

       log4j-1.2.8.jar

  

package net.game.lucene.study;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.TermQuery;

// IndexSearcher
// Term
// Query
// TermQuery, RangeQuery, PrefixQuery, BooleanQuery, PharaseQuery, WildcardQuery, FuzzyQuery 
// Hits

public class ATSearcher {
        
        private String indexDir;
        private IndexSearcher indexSearcher;
        private Analyzer analyzer;
        
        private Logger log = Logger.getLogger(ATSearcher.class);
        
        public ATSearcher(String indexDir, Analyzer analyzer) throws IOException {
                BasicConfigurator.configure();
                
                this.indexDir = indexDir;
                this.analyzer = analyzer;
                this.indexSearcher = new IndexSearcher(this.indexDir);
        }
        
        public Hits search(String field, String searchWord) throws Exception {
                Hits hits;
                // user_name필드는 직접 텀쿼리를 생성하여 전달해야 올바른 검색결과를 얻을 수 있음 
                if (field.equals("user_name")) {
                        hits = this.indexSearcher.search(new TermQuery(new Term(field, searchWord)));
                } else {
                        Query query = QueryParser.parse(searchWord, field, this.analyzer);
                        hits = this.indexSearcher.search(query);
                }
                
                return hits;
        }
        
        public static void main(String[] args) throws Exception {
                BasicConfigurator.configure();
                
                ATSearcher searcher = new ATSearcher("/Users/hiddenviewer/index_lucene", new StandardAnalyzer());
                
                String line;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                
                System.out.println("<검색필드:검색어> 입력! (종료: quit)");
                
                while ((line = br.readLine()) !=  null) {
                        if (line.startsWith("quit")) {
                                System.out.println("ATIndexer Test 프로그램 종료!");
                                break;
                        } 
                        int delimIndex = line.indexOf(":");
                        if (delimIndex == -1) {
                                System.out.println("<검색필드:검색어> 포맷으로 입력해주세요");
                                continue;
                        }
                        
                        Hits hits = searcher.search(line.substring(0, delimIndex), line.substring(delimIndex+1));
                        
                        System.out.println("------------------------------------------");
                        System.out.format("검색결과 개수: %d \n", hits.length());
                        System.out.println("------------------------------------------");
                        
                        for (int i = 0; i < hits.length(); i++) {
                                Document d = hits.doc(i);
                                System.out.format("%20s: %s \n", "status_id", d.get("status_id"));
                                System.out.format("%20s: %s \n", "text", d.get("text"));
                                System.out.format("%20s: %s \n", "user_id", d.get("user_id"));
                                System.out.format("%20s: %s \n", "user_name", d.get("user_name"));
                        }
                }
                
        }
}

 


검색 클래스 ATSearcher

ATIndexer 가 인덱싱한 색인파일에서 검색을 하기 위해서 필드명:검색어 형태로 입력을 받는다. 필드명에 해당하는 필드에서

검색어가 포함된 도큐먼트를 찾아 검색결과를 출력해준다. 이때 중요한 것은 인덱싱 과정에서 Field.UnIndexed 로 지정한 user_id 필드는

검색어를 통해 검색할 수 없으며, 다른 필드를 통한 검색결과에만 포함되어 나온다. 또 Field.UnStored로 지정한 status_id 는 글번호로 검색은
가능하지만, 원문을 저장하고 있지 않기 때문에 결과에는 원문이 출력되지 않는다. Field.Keyword 로 지정한 user_name은 인덱싱과정에서

분석이 되지 않기 때문에, 검색과정에서도 분석기에 의해서 분석되면 안된다. 검색필드가 user_name 인 경우에는 텀쿼리를 직접생성하여

IndexSearcher의 search 메소드에 전달해줘야 올바른 결과를 얻을 수 있다.

 

 

소스 : ATSearcher.java

 

package net.game.lucene.study;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.TermQuery;

// IndexSearcher
// Term
// Query
// TermQuery, RangeQuery, PrefixQuery, BooleanQuery, PharaseQuery, WildcardQuery, FuzzyQuery 
// Hits

public class ATSearcher {
        
        private String indexDir;
        private IndexSearcher indexSearcher;
        private Analyzer analyzer;
        
        private Logger log = Logger.getLogger(ATSearcher.class);
        
        public ATSearcher(String indexDir, Analyzer analyzer) throws IOException {
                BasicConfigurator.configure();
                
                this.indexDir = indexDir;
                this.analyzer = analyzer;
                this.indexSearcher = new IndexSearcher(this.indexDir);
        }
        
        public Hits search(String field, String searchWord) throws Exception {
                Hits hits;
                // user_name필드는 직접 텀쿼리를 생성하여 전달해야 올바른 검색결과를 얻을 수 있음 
                if (field.equals("user_name")) {
                        hits = this.indexSearcher.search(new TermQuery(new Term(field, searchWord)));
                } else {
                        Query query = QueryParser.parse(searchWord, field, this.analyzer);
                        hits = this.indexSearcher.search(query);
                }
                
                return hits;
        }
        
        public static void main(String[] args) throws Exception {
                BasicConfigurator.configure();
                
                ATSearcher searcher = new ATSearcher("/Users/hiddenviewer/index_lucene", new StandardAnalyzer());
                
                String line;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                
                System.out.println("<검색필드:검색어> 입력! (종료: quit)");
                
                while ((line = br.readLine()) !=  null) {
                        if (line.startsWith("quit")) {
                                System.out.println("ATIndexer Test 프로그램 종료!");
                                break;
                        } 
                        int delimIndex = line.indexOf(":");
                        if (delimIndex == -1) {
                                System.out.println("<검색필드:검색어> 포맷으로 입력해주세요");
                                continue;
                        }
                        
                        Hits hits = searcher.search(line.substring(0, delimIndex), line.substring(delimIndex+1));
                        
                        System.out.println("------------------------------------------");
                        System.out.format("검색결과 개수: %d \n", hits.length());
                        System.out.println("------------------------------------------");
                        
                        for (int i = 0; i < hits.length(); i++) {
                                Document d = hits.doc(i);
                                System.out.format("%20s: %s \n", "status_id", d.get("status_id"));
                                System.out.format("%20s: %s \n", "text", d.get("text"));
                                System.out.format("%20s: %s \n", "user_id", d.get("user_id"));
                                System.out.format("%20s: %s \n", "user_name", d.get("user_name"));
                        }
                }
                
        }
}


ATSearcher 실행결과

결과를 보면 Field.UnStored로 지정된 필드 status_id는 원문이 출력되지 않는 걸 알수 잇다.