上一節主要總結了一下Lucene是如何構建索引的,這一節簡單總結一下Lucene中的搜索功能。主要分為幾個部分,對特定項的搜索;查詢表達式QueryParser的使用;指定數字范圍內搜索;指定字符串開頭搜索以及多條件查詢。
1. 對特定項的搜索
要使用Lucene的搜索功能,首先得有索引,也就是說Lucene首先得針對特定的文件生成特定的索引,然后我們才能搜索,這在第一節里描述的很清楚,那么構建索引的例子也是使用第一節中的例子,在這就不再贅述了,然后生成了索引后,如何來搜索呢?先看第一種搜索方式:對特定項的搜索。使用的文件和建立的索引還是使用第一節的那些,生成好了索引后,就可以對特定項進行搜索了。
public class SearchTest { private Directory dir; private IndexReader reader; private IndexSearcher search; @Before public void setUp() throws Exception { dir = FSDirectory.open(Paths.get("D:\\lucene")); //索引的目錄在D:\\lucene reader = DirectoryReader.open(dir); //根據目錄獲取IndexReader search = new IndexSearcher(reader); //根據IndexReader獲取IndexSearcher } @After public void tearDown() throws Exception { reader.close(); //關閉InderxReader } //對特定項進行搜索 @Test public void testTermQuery() throws Exception { String searchField = "contents"; String q = "particular"; Term term = new Term(searchField, q); Query query = new TermQuery(term); TopDocs hits = search.search(query, 10); System.out.println("匹配" + q + "總共查詢到" + hits.totalHits + "個文檔"); for(ScoreDoc score : hits.scoreDocs) { Document doc = search.doc(score.doc); System.out.println(doc.get("fullPath")); } } }
首先初始化IndexSearcher,在搜索的時候,要在特定的Field中對特定的字符串q進行搜索,由上面的程序可知,我要在contents字段中搜索particular這個字符串。contents是在建立索引的時候建立的,包括程序最后一行中的fullPath字段,都是在建立索引的時候創建的。有了Field和搜索字符串后,就可以生成一個搜索項Term了,然后根據這個搜索項創建一個搜索。最后就可以搜索出包含這個字符串的文件的路徑。
這是針對特定項進行搜索,為什么叫針對特定項呢?因為如果我搜索particul,那么結果就為0,也就是說我必須是針對具體的一個單詞,也就是說Lucene在建立索引的時候也是根據一個個單詞來的,如果我只搜索單詞的一部分,那么是搜不到的,所以這種針對特定項搜索其實用的不多,因為在實際中,我如果搜索particul的話,理論上應該能將particular搜出來才對。所以要用到查詢表達式QueryParser。
2. 使用查詢表達式QueryParser搜索
首先來看一下如何使用這個QueryParser。
@Test public void testQueryParser() throws Exception { Analyzer analyzer = new StandardAnalyzer(); //標準分詞器,會自動去掉空格啊,is a the等單詞 String searchField = "contents"; String q = "particular"; //OR AND particular~ QueryParser parser = new QueryParser(searchField, analyzer); //查詢解析器 Query query = parser.parse(q); //通過解析要查詢的String,獲取查詢對象 TopDocs docs = search.search(query, 10);//開始查詢,查詢前10條數據,將記錄保存在docs中 System.out.println("匹配" + q + "總共查詢到" + docs.totalHits + "個文檔"); for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每條查詢結果 Document doc = search.doc(scoreDoc.doc); //scoreDoc.doc相當于docID,根據這個docID來獲取文檔 System.out.println(doc.get("fullPath")); //fullPath是剛剛建立索引的時候我們定義的一個字段 } }
從程序中可以看出,初始化QueryParser需要傳入一個分詞器,這里使用的是標準分詞器,然后跟上面一樣,得指定具體的Field和要查詢的字符串。這看起來好像和上面根據特定項來搜索沒什么兩樣,其實不然,使用QueryParser的好處就在于初始化查詢字符串q的時候,是有語法的,程序中只是簡單的查詢一個particular單詞而已。
如果我將q改成”particular OR Unicode”,那么Lucene就會查詢出所有包含particular或Unicode(不區分大小寫)的文檔,這里的OR也可以省略不寫。同樣的,如果我把OR改成AND,那么就是查詢出所有包含particular且包含Unicode的文檔。那么如果我要類似于上面提到的模糊查詢呢?比如我輸入particul想查出particular咋整呢?可以將q定義為“particul~”,這樣就OK了。實際中用的比較多的是這個QueryParser,這一塊更多的內容可以看一下官方文檔。
3. 指定數字范圍搜索
這個主要用于某個字段是int型的,然后可以根據這個字段來搜索,可以搜索某兩個int值范圍內的所有項。為了模擬這個場景,我使用上一節的例子來建立索引,因為里面有id,將其修改為Integer類型即可。然后看下如何指定數字范圍內搜索。
@Test public void testNumericRangeQuery() throws Exception { NumericRangeQuery<Integer> query = NumericRangeQuery.newIntRange("id", 1, 2, true, true); TopDocs hits = search.search(query, 10); System.out.println("總共查詢到" + hits.totalHits + "個文檔"); for (ScoreDoc score : hits.scoreDocs) { Document doc = search.doc(score.doc); System.out.println(doc.get("id")); System.out.println(doc.get("city")); System.out.println(doc.get("desc")); } }
首先得要創建一個NumericRangeQuery對象,初始化的時候第一個參數是字段名,第二個和第三個參數是始末數,后面兩個是包含大小寫,一般都設置為true,后面就跟之前的查詢一樣了。上面的程序可以查詢到兩個記錄。
4. 指定字符串開頭搜索
這個和上面的數字范圍內搜索有點類似,只不過搜索的條件不同,初始化也不同,指定字符串開頭搜索的話需要先創建一個PrefixQuery對象,將要搜索的字段和開頭的字符串傳進去,然后再搜索。如下搜索city中以s開頭的所有項。
@Test public void testPrefixQuery() throws Exception { PrefixQuery query = new PrefixQuery(new Term("city", "s")); TopDocs hits = search.search(query, 10); System.out.println("總共查詢到" + hits.totalHits + "個文檔"); for (ScoreDoc score : hits.scoreDocs) { Document doc = search.doc(score.doc); System.out.println(doc.get("id")); System.out.println(doc.get("city")); System.out.println(doc.get("desc")); } }
5. 多條件查詢(組合查詢)
多條件查詢又稱為組合查詢,顧名思義,就是將多個查詢條件組合到一起進行查詢,這個就比較厲害了。比如我現在想組合上面兩個查詢,首先id為1到2之間,然后city又是s開頭的,可以這么做:
@Test public void testBooleanQuery() throws Exception { NumericRangeQuery<Integer> query1 = NumericRangeQuery.newIntRange("id", 1, 2, true, true); PrefixQuery query2 = new PrefixQuery(new Term("city", "s")); BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder(); booleanQuery.add(query1, BooleanClause.Occur.MUST); booleanQuery.add(query2, BooleanClause.Occur.MUST); TopDocs hits = search.search(booleanQuery.build(), 10); System.out.println("總共查詢到" + hits.totalHits + "個文檔"); for (ScoreDoc score : hits.scoreDocs) { Document doc = search.doc(score.doc); System.out.println(doc.get("id")); System.out.println(doc.get("city")); System.out.println(doc.get("desc")); } }
組合查詢使用的是BooleanQuery,然后組合的條件還是上面的那些條件,這些條件中原來該使用什么類初始化還是使用那些類初始化,只是往BooleanQuery中加就行了。這很方便,一般查詢條件多的時候,就可以采用這種組合的查詢方式來查詢。
文章列表