Lucene

1、Lucene相關java

Lucene是一個高性能、可伸縮的信息搜索(IR)庫。它能夠爲你的應用程序添加索引和搜索能力。Lucene是用java實現的、成熟的開源項目,是著名的Apache Jakarta你們庭的一員,而且基於Apache軟件許可 [ASF, License]。一樣,Lucene是當前很是流行的、免費的Java信息搜索(IR)庫。

突出的優勢

Lucene做爲一個全文檢索引擎,其具備以下突出的優勢:
(1)索引文件格式獨立於應用平臺。Lucene定義了一套以8位字節爲基礎的索引文件格式,使得兼容系統或者不一樣平臺的應用可以共享創建的索引文件。
(2)在傳統全文檢索引擎的 倒排索引的基礎上,實現了分塊索引,可以針對新的文件創建小文件索引,提高索引速度。而後經過與原有索引的合併,達到優化的目的。
(3)優秀的 面向對象的系統架構,使得對於Lucene擴展的學習難度下降,方便擴充新功能。
(4)設計了獨立於語言和文件格式的 文本分析接口, 索引器經過接受Token流完成 索引文件的創立,用戶擴展新的語言和文件格式,只須要實現文本分析的接口。
(5)已經默認實現了一套強大的查詢引擎,用戶無需本身編寫代碼便可使系統可得到強大的查詢能力,Lucene的查詢實現中默認實現了布爾操做、模糊查詢(Fuzzy Search[11])、分組查詢等等。
 
2、編寫簡單的demo

1.首先導入相關的jar包算法

 

2.編寫工具類數據庫

主要分爲3步:apache

第一步創建FSDirectory,指定文檔存放的路徑。架構

第二步獲取IndexWriter,經過這個來進行文檔的相關操做。less

第三步進行增刪改查。工具

package com.feng;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
import org.wltea.analyzer.lucene.IKAnalyzer;

public class LuceneUtil {

    public static Version version = Version.LUCENE_35;
    
    public static File indexPath = new File("F:/workspace/document");  
    
    public static Analyzer analyzer = new IKAnalyzer();
    
    private static FSDirectory fsDirectory;
    
    private static void initFSDirectory(){
        try {
            fsDirectory = FSDirectory.open(indexPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static FSDirectory getFSDirectory(){
        if(fsDirectory == null)
            initFSDirectory();
        
        if(!LuceneUtil.indexPath.isDirectory())   
            LuceneUtil.indexPath.mkdirs();
        
        return fsDirectory;
    }
    
    public static void addDoc(Document doc){
        try {
            IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer);  
            iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
            IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc);
            indexWriter.addDocument(doc); 
            indexWriter.close();
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (LockObtainFailedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void updateDoc(String id, Document doc) {
        try {
            IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer);  
            iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
            IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc); 
            indexWriter.updateDocument(new Term("id", id), doc); 
            indexWriter.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void deleteDoc(String id){
        try {
            IndexWriterConfig iwc = new IndexWriterConfig(LuceneUtil.version, LuceneUtil.analyzer);  
            iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
            IndexWriter indexWriter = new IndexWriter(LuceneUtil.getFSDirectory(), iwc); 
            indexWriter.deleteDocuments(new Term("id", id));
            indexWriter.close();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static List<Document> query(String id, String name, String sex){
        try {
            QueryParser parser = new QueryParser(LuceneUtil.version, "problem", new IKAnalyzer()); 
            parser.setAllowLeadingWildcard(true);
            String s = "";
            if(id != null){
                s += "+(id:*"+id+"*)";
            }
            if(name != null)
                s += "+(name:*"+name+"*)";
            if(sex != null)
                s += "+(sex:*"+sex+"*)";
            
            Query query1 = parser.parse(s);
            
            IndexReader r = IndexReader.open(LuceneUtil.getFSDirectory());  
            IndexSearcher indexSearcher = new IndexSearcher(r);  
            
            TopDocs docs = indexSearcher.search(query1, 100);  
            int totalHits = docs.totalHits;  
            System.out.println("查詢文檔總數 :"+totalHits);
            
            List<Document> result = new ArrayList<Document>();
            for (ScoreDoc doc : docs.scoreDocs) {  
                Document document = indexSearcher.doc(doc.doc);  
                result.add(document);
            }
            
            indexSearcher.close();
            r.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } 
        
        return new ArrayList<Document>();
    }
}

 

這裏要注意的是上面IndexWriterConfig.setOpenMode(OpenMode);的方法是指定IndexWriter的操做模式,分別有三種性能

OpenMode.CREATE: 建立或覆蓋 
OpenMode.APPEND: 追加
OpenMode.CREATE_OR_APPEND: 若是不存在則建立,不然追加


3.測試學習

Lucene的增刪改查都是以DOCUMENT的形式交互的測試

3.1添加

    @org.junit.Test
    public void add(){
        Document doc = new Document();
        /**
         * field的構造屬性
         * 1.field的名稱,查詢時就是經過這個名稱來查找
         * 2.field的值
         * 3.是否存儲該field
         * 4.是否分詞,是否創建索引
         *         NOT_ANALYZED_NO_NORMS:不分詞,不創建索引
         *         NOT_ANALYZED:不分詞,創建索引
         */
        doc.add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
        doc.add(new Field("name", "fengzp", Field.Store.YES, Field.Index.NOT_ANALYZED));
        doc.add(new Field("sex", "man", Field.Store.YES, Field.Index.NOT_ANALYZED));
        LuceneUtil.addDoc(doc);
    }

添加後本地就會生成相應的文件:

 

3.2查詢

    @org.junit.Test
    public void query(){
        List<Document> list = LuceneUtil.query("1", null, null);
        for(Document document : list){
            System.out.println("id : "+document.get("id"));
            System.out.println("name : "+document.get("name"));
            System.out.println("sex : "+document.get("sex"));
        }
    }

返回結果

 

3.3更新

    @org.junit.Test
    public void update(){
        Document doc = new Document();
        doc.add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
        doc.add(new Field("name", "fengzp123", Field.Store.YES, Field.Index.NOT_ANALYZED));
        doc.add(new Field("sex", "man123", Field.Store.YES, Field.Index.NOT_ANALYZED));
        LuceneUtil.updateDoc("1", doc);
    }

查詢結果:

 

3.4刪除

    @org.junit.Test
    public void delete(){
        LuceneUtil.deleteDoc("1");
    }

查詢結果:

 

這樣看下來,是否是跟數據庫的操做好類似呢。

 

3、lucene的查詢詳解

lucene 的搜索至關強大,它提供了不少輔助查詢類,每一個類都繼承自Query類,各自完成一種特殊的查詢,你能夠像搭積木同樣將它們任意組合使用,完成一些複雜操做;另外lucene還提供了Sort類對結果進行排序,提供了Filter類對查詢條件進行限制。你或許會不自覺地拿它跟SQL語句進行比較: 「lucene能執行and、or、order by、where、like ‘%xx%’操做嗎?」回答是:「固然沒問題!」 

3.1 各類各樣的Query 
下面咱們看看lucene到底容許咱們進行哪些查詢操做: 

3.1.1 TermQuery 
首先介紹最基本的查詢,若是你想執行一個這樣的查詢:「在content域中包含‘lucene’的document」,那麼你能夠用TermQuery: 

Term t = new Term("content", " lucene"; 
Query query = new TermQuery(t); 

3.1.2 BooleanQuery 
若是你想這麼查詢:「在content域中包含java或perl的document」,那麼你能夠創建兩個TermQuery並把它們用BooleanQuery鏈接起來: 

TermQuery termQuery1 = new TermQuery(new Term("content", "java"); 
TermQuery termQuery 2 = new TermQuery(new Term("content", "perl"); 
BooleanQuery booleanQuery = new BooleanQuery(); 
booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD); 
booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD); 

3.1.3 WildcardQuery 
若是你想對某單詞進行通配符查詢,你能夠用WildcardQuery,通配符包括’?’匹配一個任意字符和’*’匹配零個或多個任意字符,例如你搜索’use*’,你可能找到’useful’或者’useless’: 

Query query = new WildcardQuery(new Term("content", "use*"); 

3.1.4 PhraseQuery 
你可能對中日關係比較感興趣,想查找‘中’和‘日’捱得比較近(5個字的距離內)的文章,超過這個距離的不予考慮,你能夠: 

PhraseQuery query = new PhraseQuery(); 
query.setSlop(5); 
query.add(new Term("content ", 「中」)); 
query.add(new Term(「content」, 「日」)); 

那麼它可能搜到「中日合做……」、「中方和日方……」,可是搜不到「中國某高層領導說日本欠扁」。 

3.1.5 PrefixQuery 
若是你想搜以‘中’開頭的詞語,你能夠用PrefixQuery: 

PrefixQuery query = new PrefixQuery(new Term("content ", "中"); 

3.1.6 FuzzyQuery 
FuzzyQuery用來搜索類似的term,使用Levenshtein算法。假設你想搜索跟‘wuzza’類似的詞語,你能夠: 

Query query = new FuzzyQuery(new Term("content", "wuzza"); 

你可能獲得‘fuzzy’和‘wuzzy’。 

3.1.7 RangeQuery 
另外一個經常使用的Query是RangeQuery,你也許想搜索時間域從20060101到20060130之間的document,你能夠用RangeQuery: 

RangeQuery query = new RangeQuery(new Term(「time」, 「20060101」), new Term(「time」, 「20060130」), true); 

最後的true表示用閉合區間。 

3.2 QueryParser 
看了這麼多Query,你可能會問:「不會讓我本身組合各類Query吧,太麻煩了!」固然不會,lucene提供了一種相似於SQL語句的查詢語句,咱們姑且叫它lucene語句,經過它,你能夠把各類查詢一句話搞定,lucene會自動把它們查分紅小塊交給相應Query執行。下面咱們對應每種 Query演示一下: 
TermQuery能夠用「field:key」方式,例如「content:lucene」。 
BooleanQuery中‘與’用‘+’,‘或’用‘ ’,例如「content:java contenterl」。 
WildcardQuery仍然用‘?’和‘*’,例如「content:use*」。 
PhraseQuery用‘~’,例如「content:"中日"~5」。 
PrefixQuery用‘*’,例如「中*」。 
FuzzyQuery用‘~’,例如「content: wuzza ~」。 
RangeQuery用‘[]’或‘{}’,前者表示閉區間,後者表示開區間,例如「time:[20060101 TO 20060130]」,注意TO區分大小寫。 
你能夠任意組合query string,完成複雜操做,例如「標題或正文包括lucene,而且時間在20060101到20060130之間的文章」能夠表示爲:「+ (title:lucene content:lucene) +time:[20060101 TO 20060130]」。代碼以下: 

Directory dir = FSDirectory.getDirectory(PATH, false); 
IndexSearcher is = new IndexSearcher(dir); 
QueryParser parser = new QueryParser("content", new StandardAnalyzer()); 
Query query = parser.parse("+(title:lucene content:lucene) +time:[20060101 TO 20060130]"; 
Hits hits = is.search(query); 
for (int i = 0; i < hits.length(); i++) 

Document doc = hits.doc(i); 
System.out.println(doc.get("title"); 

is.close(); 

首先咱們建立一個在指定文件目錄上的IndexSearcher。 
而後建立一個使用StandardAnalyzer做爲分析器的QueryParser,它默認搜索的域是content。 
接着咱們用QueryParser來parse查詢字串,生成一個Query。 
而後利用這個Query去查找結果,結果以Hits的形式返回。 
這個Hits對象包含一個列表,咱們挨個把它的內容顯示出來

 

3.3 排序:Sort 有時你想要一個排好序的結果集,就像SQL語句的「order by」,lucene能作到:經過Sort。 Sort sort = new Sort(「time」); //至關於SQL的「order by time」 Sort sort = new Sort(「time」, true); // 至關於SQL的「order by time desc」 

相關文章
相關標籤/搜索