Lucene是apache軟件基金會發布的一個開放源代碼的全文檢索引擎工具包,由資深全文檢索專家Doug Cutting所撰寫,它是一個全文檢索引擎的架構,提供了完整的建立索引和查詢索引,以及部分文本分析的引擎,Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便在目標系統中實現全文檢索的功能,或者是以此爲基礎創建起完整的全文檢索引擎,Lucene在全文檢索領域是一個經典的祖先,如今不少檢索引擎都是在其基礎上建立的,思想是相通的。java
Lucene是根據關健字來搜索的文本搜索工具,只能在某個網站內部搜索文本內容,不能跨網站搜索程序員
既然談到了網站內部的搜索,那麼咱們就談談咱們熟悉的百度、google那些搜索引擎又是基於什麼搜索的呢….算法
從圖上已經看得很清楚,baidu、google等搜索引擎實際上是經過網絡爬蟲的程序來進行搜索的…數據庫
在介紹Lucene的時候,咱們已經說了:Lucene又不是搜索引擎,僅僅是在網站內部進行文本的搜索。那咱們爲何要學他呢???apache
咱們以前編寫納稅服務系統的時候,其實就已經使用過SQL來進行站內的搜索..markdown
既然SQL能作的功能,咱們還要學Lucene,爲何呢???網絡
咱們來看看咱們用SQL來搜索的話,有什麼缺點:架構
咱們來看看在baidu中搜索Lucene爲關鍵字搜索出的內容是怎麼樣的:工具
以上所說的,咱們若是使用SQL的話,是作不到的。所以咱們就學習Lucene來幫咱們在站內根據文本關鍵字來進行搜索數據!學習
咱們若是網站須要根據關鍵字來進行搜索,可使用SQL,也可使用Lucene…那麼咱們Lucene和SQL是同樣的,都是在持久層中編寫代碼的。。
接下來,咱們就講解怎麼使用Lucene了…..在講解Lucene的API以前,咱們首先來說講Lucene存放的到底是什麼內容…咱們的SQL使用的是數據庫中的內存,在硬盤中爲DBF文件…那麼咱們Lucene內部又是什麼東西呢??
Lucene中存的就是一系列的二進制壓縮文件和一些控制文件,它們位於計算機的硬盤上,
這些內容統稱爲索引庫,索引庫有二部份組成:
也就是說:Lucene存放數據的地方咱們一般稱之爲索引庫,索引庫又分爲兩部分組成:原始記錄和詞彙表….
當咱們想要把數據存到索引庫的時候,咱們首先存入的是將數據存到原始記錄上面去….
又因爲咱們給用戶使用的時候,用戶使用的是關鍵字來進行查詢咱們的具體記錄。所以,咱們須要把咱們原始存進的數據進行拆分!將拆分出來的數據存進詞彙表中。
詞彙表就是相似於咱們在學Oracle中的索引表,拆分的時候會給出對應的索引值。
一旦用戶根據關鍵字來進行搜索,那麼程序就先去查詢詞彙表中有沒有該關鍵字,若是有該關鍵字就定位到原始記錄表中,將符合條件的原始記錄返回給用戶查看。
咱們查看如下的圖方便理解:
到了這裏,有人可能就會疑問:難道原始記錄拆分的數據都是一個一個漢字進行拆分的嗎??而後在詞彙表中不就有不少的關鍵字了???
其實,咱們在存到原始記錄表中的時候,能夠指定咱們使用哪一種算法來將數據拆分,存到詞彙表中…..咱們的圖是Lucene的標準分詞算法,一個一個漢字進行拆分。咱們可使用別的分詞算法,兩個兩個拆分或者其餘的算法。
首先,咱們來導入Lucene的必要開發包:
建立User對象,User對象封裝了數據….
/** * Created by ozc on 2017/7/12. */ public class User { private String id ; private String userName; private String sal; public User() { } public User(String id, String userName, String sal) { this.id = id; this.userName = userName; this.sal = sal; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSal() { return sal; } public void setSal(String sal) { this.sal = sal; } }
咱們想要使用Lucene來查詢出站內的數據,首先咱們得要有個索引庫吧!因而咱們先建立索引庫,將咱們的數據存到索引庫中。
建立索引庫的步驟:
@Test public void createIndexDB() throws Exception { //把數據填充到JavaBean對象中 User user = new User("1", "鍾福成", "將來的程序員"); //建立Document對象【導入的是Lucene包下的Document對象】 Document document = new Document(); //將JavaBean對象全部的屬性值,均放到Document對象中去,屬性名能夠和JavaBean相同或不一樣 /** * 向Document對象加入一個字段 * 參數一:字段的關鍵字 * 參數二:字符的值 * 參數三:是否要存儲到原始記錄表中 * YES表示是 * NO表示否 * 參數四:是否須要將存儲的數據拆分到詞彙表中 * ANALYZED表示拆分 * NOT_ANALYZED表示不拆分 * * */ document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED)); document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED)); //建立IndexWriter對象 //目錄指定爲E:/createIndexDB Directory directory = FSDirectory.open(new File("E:/createIndexDB")); //使用標準的分詞算法對原始記錄表進行拆分 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); //LIMITED默認是1W個 IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED; /** * IndexWriter將咱們的document對象寫到硬盤中 * * 參數一:Directory d,寫到硬盤中的目錄路徑是什麼 * 參數二:Analyzer a, 以何種算法來對document中的原始記錄表數據進行拆分紅詞彙表 * 參數三:MaxFieldLength mfl 最多將文本拆分出多少個詞彙 * * */ IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength); //將Document對象經過IndexWriter對象寫入索引庫中 indexWriter.addDocument(document); //關閉IndexWriter對象 indexWriter.close(); }
程序執行完,咱們就會在硬盤中見到咱們的索引庫。
那咱們如今是不知道記錄是否真真正正存儲到索引庫中的,由於咱們看不見。索引庫存放的數據放在cfs文件下,咱們也是不能打開cfs文件的。
因而,咱們如今用一個關鍵字,把索引庫的數據讀取。看看讀取數據是否成功。
根據關鍵字查詢索引庫中的內容:
@Test public void findIndexDB() throws Exception { /** * 參數一: IndexSearcher(Directory path)查詢以xxx目錄的索引庫 * * */ Directory directory = FSDirectory.open(new File("E:/createIndexDB")); //建立IndexSearcher對象 IndexSearcher indexSearcher = new IndexSearcher(directory); //建立QueryParser對象 /** * 參數一: Version matchVersion 版本號【和上面是同樣的】 * 參數二:String f,【要查詢的字段】 * 參數三:Analyzer a【使用的拆詞算法】 * */ Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", analyzer); //給出要查詢的關鍵字 String keyWords = "鍾"; //建立Query對象來封裝關鍵字 Query query = queryParser.parse(keyWords); //用IndexSearcher對象去索引庫中查詢符合條件的前100條記錄,不足100條記錄的以實際爲準 TopDocs topDocs = indexSearcher.search(query, 100); //獲取符合條件的編號 for (int i = 0; i < topDocs.scoreDocs.length; i++) { ScoreDoc scoreDoc = topDocs.scoreDocs[i]; int no = scoreDoc.doc; //用indexSearcher對象去索引庫中查詢編號對應的Document對象 Document document = indexSearcher.doc(no); //將Document對象中的全部屬性取出,再封裝回JavaBean對象中去 String id = document.get("id"); String userName = document.get("userName"); String sal = document.get("sal"); User user = new User(id, userName, sal); System.out.println(user); }
效果:
咱們的Lucene程序就是大概這麼一個思路:將JavaBean對象封裝到Document對象中,而後經過IndexWriter把document寫入到索引庫中。當用戶須要查詢的時候,就使用IndexSearcher從索引庫中讀取數據,找到對應的Document對象,從而解析裏邊的內容,再封裝到JavaBean對象中讓咱們使用。