lucene初探, 是為了後面solr做準備的. 如果跳過lucene, 直接去看solr, 估計有點懵. 由於時間的關係, lucene查詢方法也有多個, 所以單獨出來. 一. 精確查詢 在查詢的時候, 新建一個Term對象, 進去精確匹配. 前一篇提到過, 經過分詞器分下來的每一個詞或者一段話, ...
lucene初探, 是為了後面solr做準備的. 如果跳過lucene, 直接去看solr, 估計有點懵.
由於時間的關係, lucene查詢方法也有多個, 所以單獨出來.
一. 精確查詢
/** * 獲取 查找對象 * @return * @throws Exception */ private IndexSearcher getSearcher() throws Exception { //1. 創建一個directory對象, 也就是索引庫存放的位置 Directory directory = FSDirectory.open(new File(indexDir)); //2. 創建一個indexReader對象, 需要指定directory IndexReader indexReader = DirectoryReader.open(directory); //3. 創建一個indexSearcher對象, 需要指定indexReader對象 IndexSearcher indexSearcher = new IndexSearcher(indexReader); return indexSearcher; } /** * 輸出信息到控制台 * @param indexSearcher * @param query * @throws Exception */ public void sout(IndexSearcher indexSearcher, Query query) throws Exception { //5. 執行查詢 TopDocs topDocs = indexSearcher.search(query, 5); //6. 返回查詢結果 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { //獲取文檔id int doc = scoreDoc.doc; //根據文檔id獲取文檔 Document document = indexSearcher.doc(doc); //文件名字 String fileName = document.get("fileName"); //文件大小 String fileSize = document.get("fileSize"); //文件路徑 String filePath = document.get("filePath"); //文件內容 String fileContent = document.get("fileContent"); System.out.println("fileName : " + fileName); System.out.println("fileSize : " + fileSize); System.out.println("filePath : " + filePath); System.out.println("fileContent : " + fileContent); System.out.println("-----------------------"); } } /** * 精確查詢 * * @throws Exception */ @Test public void searchIndex() throws Exception { //1. 獲取查詢對象 IndexSearcher indexSearcher = getSearcher(); //2. 創建一個TermQuery對象, 指定查詢的域和查詢的關鍵詞 Query query = new TermQuery(new Term("fileName", "生活")); sout(indexSearcher, query); //3. 關閉IndexReader 對象 indexSearcher.getIndexReader().close(); }
在查詢的時候, 新建一個Term對象, 進去精確匹配. 前一篇提到過, 經過分詞器分下來的每一個詞或者一段話, 就是一個Term.
這裡在新建Term的時候, 傳入的是 功能變數名稱 和 要搜索的詞.
這裡, 一個Term對象, 只有一個域, 那如果我想查詢多個域怎麼辦呢.
二. 組合查詢
/** * 組合查詢 */ @Test public void queryBoolean() throws Exception { IndexSearcher searcher = getSearcher(); BooleanQuery query = new BooleanQuery(); Query query1 = new TermQuery(new Term("fileName", "生活")); Query query2 = new TermQuery(new Term("fileContent", "生活")); query.add(query1, BooleanClause.Occur.MUST); query.add(query2, BooleanClause.Occur.SHOULD); //System.out.println(query); sout(searcher, query); searcher.getIndexReader().close(); }
這裡的Occur枚舉值, 有三個, must, should, must_not .
must : 相當於sql裡面的 and 連接
should : 相當於 or , 可有可沒有
must_not : 相當於 != , 不包含
這裡如果列印query, 會顯示: +fileName:生活 fileContent:生活
這是lucene的一種語法, lucene可以根據語法來查詢數據. 後面會提到. 如果是must_not , 則使用減號.
如: 將上面的query2使用 MUST_NOT 連接, 則顯示成: +fileName:生活 -fileContent:生活
三 . 查詢所有
一般查詢資料庫的時候, 都會提供一個 getAll 方法, 用於查詢滿足條件的所有數據, 當不傳條件時, 就查詢所有
lucene也提供了一個查詢所有的方法 : MatchAllDocsQuery
/** * 查詢所有 * * @throws Exception */ @Test public void queryAll() throws Exception { IndexSearcher searcher = getSearcher(); Query query = new MatchAllDocsQuery(); sout(searcher, query); searcher.getIndexReader().close(); }
四. 數值區間查詢
/** * 數值區間查詢 * * @throws Exception */ @Test public void queryNumericRange() throws Exception { IndexSearcher searcher = getSearcher(); Query query = NumericRangeQuery.newLongRange("fileSize", 10L, 647L, true, true); sout(searcher, query); searcher.getIndexReader().close(); }
這裡的語法輸出就是 : fileSize:[40 to 647]
這是因為我後面兩個都設置為true, 表示包含關係. 如果都設置為false, 就是 {40 to 647}
五. 分詞器解析查詢
如前面提到的, 我輸入一句話查詢, 結果展示的結果卻並不是按照我輸入的全匹配結果.
那是因為在查詢之前, 對輸入的信息, 進行了分詞器解析, 然後根據解析結果, 再去查詢數據.
/** * 條件解析對象查詢 * * @throws Exception */ @Test public void queryParser() throws Exception { IndexSearcher searcher = getSearcher(); QueryParser queryParser = new QueryParser("fileName", new IKAnalyzer()); //Query query = queryParser.parse("*:*"); Query query = queryParser.parse("fileName:這花好漂亮"); //Query query = queryParser.parse("花"); sout(searcher, query); searcher.getIndexReader().close(); }
*:* 表示查詢所有. 不管是哪個域.
fileName:這花好漂亮 : 表示在fileName域中, 將 "這花好漂亮" 分詞解析後, 進行查詢
花 : 在fileName域中, 查詢花. 因為在QueryParse創建的時候, 指定了域為 fileName
即使我在QueryParser裡面指定了要查詢的域, 但是在parse的時候, 我可以重新指定域.
這裡需要註意的是, 在上面數值區間查詢的時候, 如果我直接寫語法進去查詢, 是查不出來的. 因為數值類型變了. 通過語法輸進去, 變成字元串類型了.
從結果中可以看到, 我輸入 這花好漂亮, 查出來的卻是 軍中綠花. 這就是分詞的作用了.
六. 多域分詞查詢
/** * 條件解析對象查詢 * * @throws Exception */ @Test public void queryMultiParser() throws Exception { IndexSearcher searcher = getSearcher(); String[] fields = {"fileName", "fileContent"}; MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer()); Query query = queryParser.parse("生活大爆炸"); sout(searcher, query); searcher.getIndexReader().close(); }
多域分詞查詢, 沒啥好說的了.