[Lucene]-Lucene基本概述以及簡單實例

1、Lucene基本介紹:

  • 基本信息:Lucene 是 Apache 軟件基金會的一個開放源代碼的全文檢索引擎工具包,是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎。Lucene 的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎創建起完整的全文檢索引擎。
  • 文件結構:自上而下樹形展開,一對多。
    • 索引Index:至關於庫或者表。
    • 段Segment:至關於分庫或者分表。
    • 文檔Document:至關一條數據 ,如小說吞噬星空
    • 域Field:一片文檔能夠分爲多個域,至關於字段,如:小說做者,標題,內容。。。
    • 詞元Term:一個域又能夠分爲多個詞元,詞元是作引搜索的最小單位,標準分詞下得詞元是一個個單詞和漢字。
  • 正向信息:
    • 索引->段->文檔->域->詞
  • 反向信息:
    • 詞->文檔。 

2、Lucene全文檢索:

一、數據分類:html

  • 結構化數據:數據庫,固定長度和格式的數據。
  • 半結構化數據:如xml,html,等..。
  • 非結構化數據:長度和格式都不固定的數據,如文本...

二、檢索過程:Luncene檢索過程能夠分爲兩個部分,一個部分是上圖左側結構化,半結構化,非結構化數據的索引創建過程,另外一部分是右側索引查詢過程。java

  •  索引過程:
    • 有一系列被索引文件
    • 被索引文件通過語法分析和語言處理造成一系列詞(Term)。
    • 通過索引建立造成詞典和反向索引表。
    • 經過索引存儲將索引寫入硬盤/內存。
  •  搜索過程:
    • 用戶輸入查詢關鍵字。
    • 對查詢語句通過語法分析和語言分析獲得一系列詞(Term)。
    • 經過語法分析獲得一個查詢樹。
    • 經過索引存儲將索引讀入到內存。
    • 利用查詢樹搜索索引,從而獲得每一個詞(Term)的文檔鏈表,對文檔鏈表進行交,差,並獲得結果文檔。
    • 將搜索到的結果文檔對查詢的相關性進行排序。
    • 返回查詢結果給用戶。

三、反向索引:  git

  luncene檢索關鍵詞,經過索引能夠將關鍵詞定位到一篇文檔,這種與哦關鍵詞到文檔的映射是文檔到字符串映射的方向過程,因此稱之爲方向索引。github

四、建立索引:數據庫

  • document:索引文檔,
  • 分詞技術:各類分詞技術,標準分詞:中文分紅單個漢字,英文單個單詞。
  • 索引建立:獲得一張索引表。

五、索引檢索:apache

  • 四個步驟:關鍵詞(keyword)->分詞方法(analyzer)->檢索索引(searchIndex)->返回結果(result)
  • 詳細步驟:輸入一個關鍵詞,使用分詞方法進行分詞獲得詞元,到索引表中去檢索這些詞元,找到包含全部詞源的文檔,並將其返回。

3、Lucene的數學模型:

一、關鍵名詞:架構

  • 文檔:一篇文章是一篇文檔。
  • 域:文檔有能夠分錯多個域:如文檔名,文檔做者,文檔時間,文檔內容。
  • 詞元:一個域能夠分爲多個詞元,好比說文檔名爲中華古詩詞簡介,經過分詞能夠獲得詞元:中,華,古,詩,詞,簡,介。這個是用標準分詞獲得,詞元是搜索的最小單位。

二、權重計算:工具

  • TF:Term Frequency,詞元在這個文檔中出現的次數,tf值越大,詞越重要。
  • DF:Document Frequency,有多少文檔包含這個詞元,df越大,那麼詞就越不重要。
  • 權重計算公式:Wt,d=TFt,d * log(n/DFt),TFt,d表示詞元t在文檔d出現的次數,n表示文檔數,DFt表示包含詞元t的文檔數。

三、空間向量模型:ui

  • 用一篇文檔的每次詞元的權重構成一個向量(每一個詞元的權重值做爲向量的維度)來表示這篇文檔,這樣全部的文檔均可以表示成一個N維的空間向量。N表示全部文檔分詞後的詞元集合的詞元總數。實例以下:
  • 檢索過程:m篇文檔咱們獲得了m個N維的空間向量,搜索詞咱們分詞獲得x個詞元,計算這x個詞元的權重,獲得一個N維的向量XV,經過計算XV和m個N維向量的類似度(餘玄夾角)來表示相關性。Lucene經過這個相關性打分機制來獲得返回的文檔。

4、官方示例Demo:

  • 下載源代碼和jar:http://lucene.apache.org/core/
  • 核心jar包以下:
  • 運行源代碼中的demo實例文件和LucenecoreAPI中示例,來看看luncene是如何建立Index和檢索的。spa

  • 用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

5、核心類:

  • 創建索引: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, TokenizerFactory
    tokenizer, TokenFilterFactory[] tokenFilters, Integer posIncGap, Integer offsetGap));
    QueryParser qparser = new QueryParser("content",new SmartChineseAnalyzer());//中文最長分詞

6、高亮示例:

  • 讀取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

相關文章
相關標籤/搜索