標籤:官方 com 過程 重構 reader script har 鏈表 strong
一、Lucene基本介紹:
- 基本資料:Lucene 是 Apache 軟體基金會的一個開放原始碼的全文檢索索引引擎工具包,是一個全文檢索索引引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎。Lucene 的目的是為軟體開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索索引的功能,或者是以此為基礎建立起完整的全文檢索索引引擎。
- 檔案結構:自上而下樹形展開,一對多。
- 索引Index:相當於庫或者表。
- 段Segment:相當於分庫或者分表。
- 文檔Document:相當一條資料 ,如小說吞噬星空
- 域Field:一片文檔可以分為多個域,相當於欄位,如:小說作者,標題,內容。。。
- 詞元Term:一個域又可以分為多個詞元,詞元是做引搜尋的最小單位,標準分詞下得詞元是一個個單詞和漢字。
- 正向資訊:
- 反向資訊:
二、Lucene全文檢索索引:
1、資料分類:
- 結構化資料:資料庫,固定長度和格式的資料。
- 半結構化資料:如xml,html,等..。
- 非結構化資料:長度和格式都不固定的資料,如文本...
2、檢索過程:Luncene檢索過程可以分為兩個部分,一個部分是左側結構化,半結構化,非結構化資料的索引建立過程,另一部分是右側索引查詢過程。
- 索引過程:
- 有一系列被索引檔案
- 被索引檔案經過文法分析和語言處理形成一系列詞(Term)。
- 經過索引建立形成詞典和反向索引表。
- 通過索引儲存將索引寫入硬碟/記憶體。
- 搜尋過程:
- 使用者輸入查詢關鍵字。
- 對查詢語句經過文法分析和語言分析得到一系列詞(Term)。
- 通過文法分析得到一個查詢樹。
- 通過索引儲存將索引讀入到記憶體。
- 利用查詢樹搜尋索引,從而得到每個詞(Term)的文檔鏈表,對文檔鏈表進行交,差,並得到結果文檔。
- 將搜尋到的結果文檔對查詢的相關性進行排序。
- 返回查詢結果給使用者。
3、反向索引:
luncene檢索關鍵詞,通過索引可以將關鍵詞定位到一篇文檔,這種與哦關鍵詞到文檔的映射是文檔到字串映射的方向過程,所以稱之為方向索引。
4、建立索引:
- document:索引文檔,
- 分詞技術:各種分詞技術,標準分詞:中文分成單個漢字,英文單個單詞。
- 索引建立:得到一張索引表。
5、索引檢索:
- 四個步驟:關鍵詞(keyword)->分詞方法(analyzer)->檢索索引(searchIndex)->返回結果(result)
- 詳細步驟:輸入一個關鍵詞,使用分詞方法進行分詞得到詞元,到索引表中去檢索這些詞元,找到包含所有詞源的文檔,並將其返回。
三、Lucene的數學模型:
1、關鍵名詞:
- 文檔:一篇文章是一篇文檔。
- 域:文檔有可以分錯多個域:如文檔名,文檔作者,文檔時間,文檔內容。
- 詞元:一個域可以分為多個詞元,比如說文檔名為中華古詩詞簡介,通過分詞可以得到詞元:中,華,古,詩,詞,簡,介。這個是用標準分詞得到,詞元是搜尋的最小單位。
2、權重計算:
- TF:Term Frequency,詞元在這個文檔中出現的次數,tf值越大,詞越重要。
- DF:Document Frequency,有多少文檔包含這個詞元,df越大,那麼詞就越不重要。
- 權重計算公式:Wt,d=TFt,d * log(n/DFt),TFt,d表示詞元t在文檔d出現的次數,n表示文檔數,DFt表示包含詞元t的文檔數。
3、空間向量模型:
- 用一篇文檔的每次詞元的權重構成一個向量(每個詞元的權重值作為向量的維度)來表示這篇文檔,這樣所有的文檔都可以表示成一個N維的空間向量。N表示所有文檔分詞後的詞元集合的詞元總數。執行個體如下:
- 檢索過程:m篇文檔我們得到了m個N維的空間向量,搜尋字詞我們分詞得到x個詞元,計算這x個詞元的權重,得到一個N維的向量XV,通過計算XV和m個N維向量的相似性(餘玄夾角)來表示相關性。Lucene通過這個相關性打分機制來得到返回的文檔。
四、官方樣本Demo:
- 下載原始碼和jar:http://lucene.apache.org/core/
- 核心jar包如下:
運行原始碼中的demo執行個體檔案和LucenecoreAPI中樣本,來看看luncene是如何建立Index和檢索的。
- 用Idea構建了一個java項目:如下所示添加這6個核心包,和樣本檔案。
- IndexFiles,SearchFiles分別是遍曆一個檔案目錄建立索引和手動輸入關鍵詞檢索返回命中檔案。CindexSrarch是執行個體一個記憶體索引建立並添加文檔,最終檢索的過程。
package Test;import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.standard.StandardAnalyzer;import org.apache.lucene.document.Document;import org.apache.lucene.document.Field;import org.apache.lucene.document.TextField;import org.apache.lucene.index.DirectoryReader;import org.apache.lucene.index.IndexWriter;import org.apache.lucene.index.IndexWriterConfig;import org.apache.lucene.queryparser.classic.QueryParser;import org.apache.lucene.search.IndexSearcher;import org.apache.lucene.search.Query;import org.apache.lucene.search.ScoreDoc;import org.apache.lucene.store.Directory;import org.apache.lucene.store.RAMDirectory;import java.io.IOException;/** * Created by rzx on 2017/6/1. */public class CindexSearch { public static void createIndexANDSearchIndex() throws Exception{ Analyzer analyzer = new StandardAnalyzer();//標準分詞器 //RAMDirectory記憶體字典儲存索引 Directory directory = new RAMDirectory(); //Directory directory = FSDirectory.open("/tmp/testindex");磁碟儲存索引 IndexWriterConfig config = new IndexWriterConfig(analyzer); IndexWriter writer = new IndexWriter(directory,config); Document document = new Document(); String text = "hello world main test"; document.add(new Field("filetest",text, TextField.TYPE_STORED)); //將域field添加到document中 writer.addDocument(document); writer.close(); DirectoryReader directoryReader = DirectoryReader.open(directory); IndexSearcher isearch = new IndexSearcher(directoryReader); QueryParser parser = new QueryParser("filetest",new StandardAnalyzer()); Query query = parser.parse("main");//查詢main關鍵詞 ScoreDoc [] hits = isearch.search(query,1000).scoreDocs; for (int i = 0; i <hits.length ; i++) { Document hitdoc =isearch.doc(hits[i].doc); System.out.print("命中的檔案內容:"+hitdoc.get("filetest")); } directoryReader.close(); directory.close(); } public static void main(String[] args) { try { createIndexANDSearchIndex(); } catch (Exception e) { e.printStackTrace(); } }}運行結果:
input目錄中建立了兩個檔案test1.txt,test2.txt,內容分別是:hello world和hello main man test。運行IndexFiles讀取input目錄,並自動建立一個testindex索引目錄,結果如下:
目錄中建立了testindex檔案,裡面儲存索引相關資訊。運行SearchFiles如下:分別在控制台輸入檢索關鍵字:hello,min
五、核心類:
建立索引:Analyzer,Director(RAMDirectory,FSDirectory),IndexWriterConfig,IndexWriter,Document
* Analyzer analyzer = new StandardAnalyzer(); //執行個體化分詞器* Directory directory = new RAMDirectory(); //初始化記憶體索引目錄* Directory directory = FSDirectory.open("indexpath");//初始化磁碟儲存索引* IndexWriterConfig config = new IndexWriterConfig(analyzer); //索引器配置* IndexWriter writer = new IndexWriter(directory,config); //索引器* Document document = new Document(); //初始化Document,用來存資料。
- 查詢索引:DirectoryReader,IndexSearch,QueryParser,MutilFieldQueryParser,
* DirectoryReader directoryReader = DirectoryReader.open(directory); //索引目錄讀取器* IndexSearcher isearch = new IndexSearcher(directoryReader); //索引查詢器*多種檢索方式:* QueryParser單欄位<域>綁定: QueryParser qparser = new QueryParser("filed",new StandardAnalyzer()); //查詢解析器:參數Field域,分詞器 Query query = qparser.parse("main") //查詢關鍵詞* MultiFieldQueryParser多欄位<域>綁定(): QueryParser qparser2 = new MultiFieldQueryParser(new String[]{"field1","field2"},new StandardAnalyzer());//多欄位查詢解析器 Query query = qparser2.parse("main") //查詢關鍵詞* Term綁定欄位<域>查詢:new Term(field,keyword); Term term =new Term("content","main"); Query query = new TermQuery(term);*更多方法:參照http://blog.csdn.net/chenghui0317/article/details/10824789* ScoreDoc [] hits = isearch.search(query,1000).scoreDocs; //查詢你命中的文檔以及評分和所在分區
- 高亮顯示:SimpleHTMLFormatter,Highlighter,SimpleFragmenter
SimpleHTMLFormatter formatter=new SimpleHTMLFormatter("<b><font color=‘red‘>","</font></b>"); Highlighter highlighter=new Highlighter(formatter, new QueryScorer(query)); highlighter.setTextFragmenter(new SimpleFragmenter(400)); String conten = highlighter.getBestFragment(new StandardAnalyzer(),"contents","hello main man test");
- 內建分詞器:Lucene中實現了很多分詞器,有針對性的應用各個情境和各種語言。
QueryParser qparser = new QueryParser("content",new SimpleAnalyzer());QueryParser qparser = new QueryParser("content",new ClassicAnalyzer());QueryParser qparser = new QueryParser("content",new KeywordAnalyzer());QueryParser qparser = new QueryParser("content",new StopAnalyzer());QueryParser qparser = new QueryParser("content",new UAX29URLEmailAnalyzer());QueryParser qparser = new QueryParser("content",new UnicodeWhitespaceAnalyzer());QueryParser qparser = new QueryParser("content",new WhitespaceAnalyzer());QueryParser qparser = new QueryParser("content",new ArabicAnalyzer());QueryParser qparser = new QueryParser("content",new ArmenianAnalyzer());QueryParser qparser = new QueryParser("content",new BasqueAnalyzer());QueryParser qparser = new QueryParser("content",new BrazilianAnalyzer());QueryParser qparser = new QueryParser("content",new BulgarianAnalyzer());QueryParser qparser = new QueryParser("content",new CatalanAnalyzer());QueryParser qparser = new QueryParser("content",new CJKAnalyzer());QueryParser qparser = new QueryParser("content",new CollationKeyAnalyzer());QueryParser qparser = new QueryParser("content",new CustomAnalyzer(Version defaultMatchVersion, CharFilterFactory[] charFilters, TokenizerFactorytokenizer, TokenFilterFactory[] tokenFilters, Integer posIncGap, Integer offsetGap));QueryParser qparser = new QueryParser("content",new SmartChineseAnalyzer());//中文最長分詞
六、高亮樣本:
- 讀取indexfile建立的索引testindex,並查詢關鍵字main並高亮。出現異常:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/lucene/index/memory/MemoryIndex需要匯入:lucene-memory-6.5.1.jar,這個包用來處理儲存位置的位移量,可以讓我們在文本中定位到關鍵詞元.
public static void searchByIndex(String indexFilePath,String keyword) throws ParseException, InvalidTokenOffsetsException { try { String indexDataPath="testindex"; String keyWord = "main"; Directory dir= FSDirectory.open(new File(indexDataPath).toPath()); IndexReader reader= DirectoryReader.open(dir); IndexSearcher searcher=new IndexSearcher(reader); QueryParser queryParser = new QueryParser("contents",new StandardAnalyzer()); Query query = queryParser.parse("main"); TopDocs topdocs=searcher.search(query,10); ScoreDoc[] scoredocs=topdocs.scoreDocs; System.out.println("最大的評分:"+topdocs.getMaxScore()); for(int i=0;i<scoredocs.length;i++){ int doc=scoredocs[i].doc; Document document=searcher.doc(doc); System.out.println("====================================="); System.out.println("關鍵詞:"+keyWord); System.out.println("檔案路徑:"+document.get("path")); System.out.println("檔案ID:"+scoredocs[i].doc); //開始高亮 SimpleHTMLFormatter formatter=new SimpleHTMLFormatter("<b><font color=‘red‘>","</font></b>"); Highlighter highlighter=new Highlighter(formatter, new QueryScorer(query)); highlighter.setTextFragmenter(new SimpleFragmenter(400)); String conten = highlighter.getBestFragment(new StandardAnalyzer(),"contents","hello main man test"); //String conten = highlighter.getBestFragment(new StandardAnalyzer(),"contents",document.get("content")); System.out.println("檔案內容:"+conten); System.out.println("相關度:"+scoredocs[i].score); } reader.close(); } catch (IOException e) { e.printStackTrace(); } }輸出結果:
原始碼:https://codeload.github.com/NextNight/luncene6.5.1Test/zip/master
[Lucene]-Lucene基本概述以及簡單一實例