摘要:系列文章系列一快速入門系列二使用及索引文檔的基本操作系列三查詢及高亮是什么在維基百科的定義是一套用于全文檢索和搜索的開放源代碼程序庫,由軟件基金會支持和提供。全面準確和快速是衡量全文檢索系統的關鍵指標。結果列表有相關度排序。
系列文章:
Lucene系列(一)快速入門
Lucene系列(二)luke使用及索引文檔的基本操作
Lucene系列(三)查詢及高亮
Lucene是什么?Lucene在維基百科的定義
Lucene是一套用于全文檢索和搜索的開放源代碼程序庫,由Apache軟件基金會支持和提供。Lucene提供了一個簡單卻強大的應用程序接口,能夠做全文索引和搜索,在Java開發環境里Lucene是一個成熟的免費開放源代碼工具;就其本身而論,Lucene是現在并且是這幾年,最受歡迎的免費Java信息檢索程序庫。
另外,Lucene不提供爬蟲功能,如果需要獲取內容需要自己建立爬蟲應用。
Lucene只做索引和搜索工作。
Lucene官網
http://lucene.apache.org/
打開Luncene官網你會發現Lucene版本更新的太快了,現在最新的版本已經是7.2.1。不過這也變相說明了Luncene這個開源庫的火爆。
Lucene和solr
我想提到Lucene,不得不提solr了。
很多剛接觸Lucene和Solr的人都會問這個明顯的問題:我應該使用Lucene還是Solr?
答案很簡單:如果你問自己這個問題,在99%的情況下,你想使用的是Solr. 形象的來說Solr和Lucene之間關系的方式是汽車及其引擎。 你不能駕駛一臺發動機,但可以開一輛汽車。 同樣,Lucene是一個程序化庫,您不能按原樣使用,而Solr是一個完整的應用程序,您可以立即使用它。(參考:Lucene vs Solr)
全文檢索是什么?全文檢索在百度百科的定義
全文數據庫是全文檢索系統的主要構成部分。所謂全文數據庫是將一個完整的信息源的全部內容轉化為計算機可以識別、處理的信息單元而形成的數據集合。全文數據庫不僅存儲了信息,而且還有對全文數據進行詞、字、段落等更深層次的編輯、加工的功能,而且所有全文數據庫無一不是海量信息數據庫。
全文檢索首先將要查詢的目標文檔中的詞提取出來,組成索引,通過查詢索引達到搜索目標文檔的目的。這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。
全文檢索(Full-Text Retrieval)是指以文本作為檢索對象,找出含有指定詞匯的文本。
全面、準確和快速是衡量全文檢索系統的關鍵指標。
關于全文檢索,我們要知道:
只處理文本。
不處理語義。
搜索時英文不區分大小寫。
結果列表有相關度排序。(查出的結果如果沒有相關度排序,那么系統不知道我想要的結果在哪一頁。我們在使用百度搜索時,一般不需要翻頁,為什么?因為百度做了相關度排序:為每一條結果打一個分數,這條結果越符合搜索條件,得分就越高,叫做相關度得分,結果列表會按照這個分數由高到低排列,所以第1頁的結果就是我們最想要的結果。)
在信息檢索工具中,全文檢索是最具通用性和實用性的。
參考:https://zhuanlan.zhihu.com/p/...
全文檢索和數據庫搜索的區別
簡單來說,這兩者解決的問題是不一樣。數據庫搜索在匹配效果、速度、效率等方面都遜色于全文檢索。下面我們的一個例子就能很清楚說明這一點。Lucene實現全文檢索流程是什么?
全文檢索的流程分為兩大部分:索引流程、搜索流程。
索引流程:即采集數據構建文檔對象分析文檔(分詞)創建索引。
搜索流程:即用戶通過搜索界面創建查詢執行搜索,搜索器從索引庫搜索渲染搜索結果
我們在下面的一個程序中,對這個全文檢索的流程會有進一步的了解。
Lucene實現向文檔寫索引并讀取文檔截止2018/3/30,用到的jar包結為最新。
程序用到的數據下載地址:
鏈接:https://pan.baidu.com/s/1ccgrCCRBBGOL-fmmOLrxlQ
密碼:vyof
創建Maven項目,并添加相關jar包依賴
org.apache.lucene lucene-core 7.2.1 org.apache.lucene lucene-queryparser 7.2.1 org.apache.lucene lucene-analyzers-common 7.2.1
向文檔里寫索引
package lucene_demo1; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.file.Paths; 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.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; /** * *TODO 索引文件 * @author Snaiclimb * @date 2018年3月30日 * @version 1.8 */ public class Indexer { // 寫索引實例 private IndexWriter writer; /** * 構造方法 實例化IndexWriter * * @param indexDir * @throws IOException */ public Indexer(String indexDir) throws IOException { //得到索引所在目錄的路徑 Directory directory = FSDirectory.open(Paths.get(indexDir)); // 標準分詞器 Analyzer analyzer = new StandardAnalyzer(); //保存用于創建IndexWriter的所有配置。 IndexWriterConfig iwConfig = new IndexWriterConfig(analyzer); //實例化IndexWriter writer = new IndexWriter(directory, iwConfig); } /** * 關閉寫索引 * * @throws Exception * @return 索引了多少個文件 */ public void close() throws IOException { writer.close(); } public int index(String dataDir) throws Exception { File[] files = new File(dataDir).listFiles(); for (File file : files) { //索引指定文件 indexFile(file); } //返回索引了多少個文件 return writer.numDocs(); } /** * 索引指定文件 * * @param f */ private void indexFile(File f) throws Exception { //輸出索引文件的路徑 System.out.println("索引文件:" + f.getCanonicalPath()); //獲取文檔,文檔里再設置每個字段 Document doc = getDocument(f); //開始寫入,就是把文檔寫進了索引文件里去了; writer.addDocument(doc); } /** * 獲取文檔,文檔里再設置每個字段 * * @param f * @return document */ private Document getDocument(File f) throws Exception { Document doc = new Document(); //把設置好的索引加到Document里,以便在確定被索引文檔 doc.add(new TextField("contents", new FileReader(f))); //Field.Store.YES:把文件名存索引文件里,為NO就說明不需要加到索引文件里去 doc.add(new TextField("fileName", f.getName(), Field.Store.YES)); //把完整路徑存在索引文件里 doc.add(new TextField("fullPath", f.getCanonicalPath(), Field.Store.YES)); return doc; } public static void main(String[] args) { //索引指定的文檔路徑 String indexDir = "D:lucenedataindex"; ////被索引數據的路徑 String dataDir = "D:lucenedata"; Indexer indexer = null; int numIndexed = 0; //索引開始時間 long start = System.currentTimeMillis(); try { indexer = new Indexer(indexDir); numIndexed = indexer.index(dataDir); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { indexer.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //索引結束時間 long end = System.currentTimeMillis(); System.out.println("索引:" + numIndexed + " 個文件 花費了" + (end - start) + " 毫秒"); } }
運行效果:
我們查看D:lucenedataindex文件夾。我們發現多了一些東西,這些東西就是我們馬上用來全文搜索的索引。
//索引指定的文檔路徑 String indexDir = "D:lucenedataindex";
Mark博文:Lucene的索引文件格式(1)
全文檢索測試
package lucene_demo1; import java.nio.file.Paths; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; 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.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; /** * 根據索引搜索 *TODO * @author Snaiclimb * @date 2018年3月25日 * @version 1.8 */ public class Searcher { public static void search(String indexDir, String q) throws Exception { // 得到讀取索引文件的路徑 Directory dir = FSDirectory.open(Paths.get(indexDir)); // 通過dir得到的路徑下的所有的文件 IndexReader reader = DirectoryReader.open(dir); // 建立索引查詢器 IndexSearcher is = new IndexSearcher(reader); // 實例化分析器 Analyzer analyzer = new StandardAnalyzer(); // 建立查詢解析器 /** * 第一個參數是要查詢的字段; 第二個參數是分析器Analyzer */ QueryParser parser = new QueryParser("contents", analyzer); // 根據傳進來的p查找 Query query = parser.parse(q); // 計算索引開始時間 long start = System.currentTimeMillis(); // 開始查詢 /** * 第一個參數是通過傳過來的參數來查找得到的query; 第二個參數是要出查詢的行數 */ TopDocs hits = is.search(query, 10); // 計算索引結束時間 long end = System.currentTimeMillis(); System.out.println("匹配 " + q + " ,總共花費" + (end - start) + "毫秒" + "查詢到" + hits.totalHits + "個記錄"); // 遍歷hits.scoreDocs,得到scoreDoc /** * ScoreDoc:得分文檔,即得到文檔 scoreDocs:代表的是topDocs這個文檔數組 * * @throws Exception */ for (ScoreDoc scoreDoc : hits.scoreDocs) { Document doc = is.doc(scoreDoc.doc); System.out.println(doc.get("fullPath")); } // 關閉reader reader.close(); } public static void main(String[] args) { String indexDir = "D:lucenedataindex"; //我們要搜索的內容 String q = "Jean-Philippe sdsds Barrette-LaPierre"; try { search(indexDir, q); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
上面我們搜索的是:"Jean-Philippe Barrette-LaPierre";即使你:"Jean-Philippe ssss Barrette-LaPierre"這樣搜索也還是搜索到,以為Lucene對其進行了分詞,對中文無效。
我們剛剛實現的程序已經清楚地向我們展示了Lucene實現全文檢索流程,我們再來回顧一下。
在Lucene中,采集數據(從網站爬取或連接數據庫)就是為了創建索引,創建索引需要先將采集的原始數據加工為文檔,再由文檔分詞產生索引。文檔(Document) 中包含若干個Field域。
IndexWriter是索引過程的核心組件,通過IndexWriter可以創建新索引、更新索引、刪除索引操作。IndexWriter需要通過Directory對索引進行存儲操作。
Directory描述了索引的存儲位置,底層封裝了I/O操作,負責對索引進行存儲。它是一個抽象類,它的子類常用的包括FSDirectory(在文件系統存儲索引)、RAMDirectory(在內存存儲索引)。
在對Docuemnt中的內容索引之前需要使用分詞器進行分詞 ,分詞的主要過程就是分詞、過濾兩步。 分詞就是將采集到的文檔內容切分成一個一個的詞,具體應該說是將Document中Field的value值切分成一個一個的詞。
過濾包括去除標點符號、去除停用詞(的、是、a、an、the等)、大寫轉小寫、詞的形還原(復數形式轉成單數形參、過去式轉成現在式等)。
停用詞是為節省存儲空間和提高搜索效率,搜索引擎在索引頁面或處理搜索請求時會自動忽略某些字或詞,這些字或詞即被稱為Stop Words(停用詞)。比如語氣助詞、副詞、介詞、連接詞等,通常自身并無明確的意義,只有將其放入一個完整的句子中才有一定作用,如常見的“的”、“在”、“是”、“啊”等。
Lucene中自帶了StandardAnalyzer,它可以對英文進行分詞。
參照:https://zhuanlan.zhihu.com/p/...
Lucene工作原理總結1、索引流程
從原始文件中提取一些可以用來搜索的數據(封裝成各種Field),把各field再封裝成document,然后對document進行分析(對各字段分詞),得到一些索引目錄寫入索引庫,document本身也會被寫入一個文檔信息庫;
2、搜索流程
根據關鍵詞解析(queryParser)出查詢條件query(Termquery),利用搜索工具(indexSearcher)去索引庫獲取文檔id,然后再根據文檔id去文檔信息庫獲取文檔信息
分詞器不同,建立的索引數據就不同;比較通用的一個中文分詞器IKAnalyzer的用法
3、相關度得分
a) 在建立索引的時候,可以給指定文檔的指定域設置一個權重
Field.setBoosts()(現在5.5版本之前的是這樣設置權重,后面的不是了)
b) 在搜索的時候,可以給不同的搜索域設置不同的權重
Boosts = new HashMap
MultiFieldsQueryParser(fields,analyzer,boosts)
歡迎關注我的微信公眾號:“Java面試通關手冊”(堅持原創,分享美文,分享各種Java學習資源,面試題,以及企業級Java實戰項目回復關鍵字免費領取):
Lucene我想暫時先更新到這里,僅僅這三篇文章想掌握Lucene是遠遠不夠的。另外我這里三篇文章都用的最新的jar包,Lucene更新太快,5系列后的版本和之前的有些地方還是有挺大差距的,就比如為文檔域設置權值的setBoost方法6.6以后已經被廢除了等等。因為時間有限,所以我就草草的看了一下Lucene的官方文檔,大多數內容還是看java1234網站的這個視頻來學習的,然后在版本和部分代碼上做了改進。截止2018/4/1,上述代碼所用的jar包皆為最新。
最后推薦一下自己覺得還不錯的Lucene學習網站/博客:
官方網站:Welcome to Apache Lucene
Github:Apache Lucene and Solr
Lucene專欄
搜索系統18:lucene索引文件結構
Lucene6.6的介紹和使用
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68951.html
摘要:系列文章系列一快速入門系列二使用及索引文檔的基本操作系列三查詢及高亮入門簡介地址下載地址是一個用于搜索引擎的,方便開發和診斷的可視化工具。使用作為其最低級別的搜索引擎基礎。截止,上述代碼所用的包皆為最新。 系列文章: Lucene系列(一)快速入門 Lucene系列(二)luke使用及索引文檔的基本操作 Lucene系列(三)查詢及高亮 luke入門 簡介: github地址:http...
摘要:極速的查詢速度通過有限狀態轉換器實現了用于全文檢索的倒排索引,實現了用于存儲數值數據和地理位置數據的樹,以及用于分析的列存儲。每個數據都被編入了索引。強大的彈性保障硬件故障。檢測這些故障并確保集群和數據的安全性和可用性。 What —— Elasticsearch是什么? Elasticsearch是一個基于Lucene的搜索服務器,Elasticsearch也是使用Java編寫的,它...
摘要:那我們現在是不知道記錄是否真真正正存儲到索引庫中的,因為我們看不見。索引庫存放的數據放在文件下,我們也是不能打開文件的。 什么是Lucene?? Lucene是apache軟件基金會發布的一個開放源代碼的全文檢索引擎工具包,由資深全文檢索專家Doug Cutting所撰寫,它是一個全文檢索引擎的架構,提供了完整的創建索引和查詢索引,以及部分文本分析的引擎,Lucene的目的是為軟件開發...
閱讀 2466·2021-11-22 09:34
閱讀 3074·2021-10-25 09:43
閱讀 1988·2021-10-11 10:59
閱讀 3400·2021-09-22 15:13
閱讀 2336·2021-09-04 16:40
閱讀 427·2019-08-30 15:53
閱讀 3196·2019-08-30 11:13
閱讀 2612·2019-08-29 17:30