Lucene In Depth(1)--介紹

 

Lucene是apache軟件基金會jakarta項目組的一個子項目,是一個開放源代碼的全文檢索引擎工具包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎建立起完整的全文檢索引擎。
 
Lucene的原作者是Doug Cutting,他是一位資深全文索引/檢索專家,曾經是V-Twin搜索引擎的主要開發者,後在Excite擔任高級系統架構設計師,目前從事於一些Internet底層架構的研究。早先發布在作者自己的http://www.lucene.com/,後來發佈在SourceForge,2001年年底成爲apache軟件基金會jakarta的一個子項目:http://jakarta.apache.org/lucene/
 
引子
      Lucene作爲開源社區裏面大名鼎鼎的全文檢索系統被廣泛傳播,網上關於Lucene的資料可以說是俯首皆是,也有很多的其他全文檢索系統或多或少的借鑑了Lucene的設計思想,比如國內剛剛出現的FirTex項目。因爲一直非常信任Apache,也比較關注開源項目的發展,所以應該很好幾年前就知道了Lucene,但總感覺他離我很遠。也曾試圖去深入的學習一下,最終不了了之。
     直到最近,因爲要設計一個系統,當中會用到全文檢索技術,於是重拾Lucene,決定好好研究一下。搜遍了互聯網,看到的大部分資料是講解如何使用Lucene的,對Lucene深入講解的不多,包括比較流行的《Lucene In Action》,都讓我大失所望。我希望能深入的瞭解Lucene的設計思想,Lucene文件的數據結構,創建索引和檢索的過程,爲何可以做到如此高效。
       看來只能自己慢慢啃了,我知道這個系統的複雜性,但當看到源代碼時還是大吃一驚,竟然有4萬多行。雖然以前曾經有過研習ICTCLAS源代碼的經歷,但它大概只有1萬行左右,已經花費了我很長的時間才把各個細節部分搞清楚。看來這次又是一個攻堅戰!
 
初探

       雖然Lucene的源代碼很龐大,很複雜,但對於使用者來說還是非常簡單的,沒有幾行代碼就可以實現完整的創建索引和檢索的全過程。我們來看兩個例子:

//檢索數據
package org.apache.lucene.demo2;

import java.io.File;
import java.util.Date;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
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.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class Searcher {

    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        
try {
            File indexDir 
= new File("test2/index");
            String q 
= "mscomctl.ocx";
            
if (!indexDir.exists() || !indexDir.isDirectory()) {
                
throw new Exception(indexDir + " does not exist or is not a directory.");
            }

            search(indexDir, q);
        }
 catch (Exception e) {
            e.printStackTrace();
        }

    }


    
public static void search(File indexDir, String q) throws Exception {
        Directory fsDir 
= FSDirectory.getDirectory(indexDir, false);
        IndexSearcher is 
= new IndexSearcher(fsDir);
        QueryParser parser 
= new QueryParser("contents"new StandardAnalyzer());
        Query query 
= parser.parse(q);
        
long start = new Date().getTime();
        Hits hits 
= is.search(query);
        
long end = new Date().getTime();
        System.err.println(
"Found " + hits.length() + " document(s) (in " + (end - start) + " milliseconds) that matched query '" + q + "':");
        
for (int i = 0; i < hits.length(); i++{
            Document doc 
= hits.doc(i);
            System.out.println(doc.get(
"filename"));
        }

    }

}

 

//創建索引
package org.apache.lucene.demo2;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;

public class Inderer {
 
    
public static void main(String[] args) {
        
try {
            File dataDir 
= new File("test2/data");
            File indexDir 
= new File("test2/index");
            
long start = new Date().getTime();
            
int numIndexed = index(indexDir, dataDir);
            
long end = new Date().getTime();
            System.out.println(
"Indexing " + numIndexed + " files took " + (end - start) + " milliseconds");
        }
 catch (IOException e) {
            e.printStackTrace();
        }

    }


    
// open an index and start file directory traversal
    public static int index(File indexDir, File dataDir) throws IOException {
        
if (!dataDir.exists() || !dataDir.isDirectory()) {
            
throw new IOException(dataDir + " does not exist or is not a directory");
        }

        IndexWriter writer 
= new IndexWriter(indexDir, new StandardAnalyzer(), true);
        writer.setUseCompoundFile(
false);
        indexDirectory(writer, dataDir);
        
int numIndexed = writer.docCount();
        writer.optimize();
        writer.close();
        
return numIndexed;
    }


    
// recursive method that calls itself when it finds a directory
    private static void indexDirectory(IndexWriter writer, File dir) throws IOException {
        File[] files 
= dir.listFiles();
        
for (int i = 0; i < files.length; i++{
            File f 
= files[i];
            
if (f.isDirectory()) {
                indexDirectory(writer, f);
            }
 else if (f.getName().endsWith(".txt")) {
                indexFile(writer, f);
            }

        }

    }


    
// method to actually index a file using Lucene
    private static void indexFile(IndexWriter writer, File f) throws IOException {
        
if (f.isHidden() || !f.exists() || !f.canRead()) {
            
return;
        }

        System.out.println(
"Indexing " + f.getCanonicalPath());
        Document doc 
= new Document();
        doc.add(
new Field("contents"new FileReader(f)));
        doc.add(
new Field("filename", f.getCanonicalPath(), Field.Store.YES, Field.Index.NO));
        
// System.out.println(doc);
        writer.addDocument(doc);
    }

}

參考
1.       FirTex:www.firtex.org
2.       lucene中國:www.lucene.com.cn
發佈了65 篇原創文章 · 獲贊 5 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章