通過前幾篇《全文檢索技術專欄》關於倒排索引算法的原理、Lucene分詞、索引的創建等內容的介紹,Lucene中最重要也是最能體現Lucene作用的非搜索功能莫屬。Lucene對創建的索引可實現多種搜索功能(詞項查詢、多域查詢、布爾查詢、範圍查詢、模糊查詢、通配查詢),在進行搜索時,將查詢條件封裝成query對象,最終得到多個document數據。
詞項查詢
詞項查詢是最基本的查詢方式,查詢參數就是一個域中的詞語。判斷倒排索引表中是否有相關詞項,最終將document匹配集合返回。
@Test
public void termQuery() throws IOException {
//指定一個文件輸出目錄
Path path= Paths.get("d:/test/index");
//將路徑交給FSDirectory完成路徑的管理,當路徑不存在時,由FSDirectory幫你創建
FSDirectory fsDirectory=FSDirectory.open(path);
//創建索引輸入流
IndexReader indexReader= DirectoryReader.open(fsDirectory);
IndexSearcher indexSearcher=new IndexSearcher(indexReader);
//創建詞項查詢條件
Term term=new Term("title","巴西");
Query query= new TermQuery(term);
//查詢
TopDocs docs = indexSearcher.search(query, 3);
ScoreDoc[] scoreDocs=docs.scoreDocs;
for (ScoreDoc scoreDoc:scoreDocs){
//獲取document對象屬性
//documentId
int did = scoreDoc.doc;
Document docObj = indexSearcher.doc(did);
System.out.println("============"+did+"============");
System.out.println(docObj.get("title"));
System.out.println(docObj.get("origin"));
System.out.println(docObj.get("content"));
}
}
查詢結果:
多域查詢
在上面的詞項查詢中,我們只搜索了titile,如果想同時搜索title、origin、content中有沒有要查詢的關鍵詞,可以通過多域查詢的方式。
代碼和詞項查詢的區別不是很大,唯一不同的是構造查詢條件和構造查詢對象的方式不同:
@Test
public void multiQuery() throws IOException, ParseException {
//指定一個文件輸出目錄
Path path= Paths.get("d:/test/index");
//將路徑交給FSDirectory完成路徑的管理,當路徑不存在時,由FSDirectory幫你創建
FSDirectory fsDirectory=FSDirectory.open(path);
//創建索引輸入流
IndexReader indexReader= DirectoryReader.open(fsDirectory);
IndexSearcher indexSearcher=new IndexSearcher(indexReader);
//要查詢的域
String[] files={"title","origin","content"};
//創建多域查詢條件
MultiFieldQueryParser parser=new MultiFieldQueryParser(files,new SmartChineseAnalyzer());
Query query= parser.parse("巴西");
//查詢
TopDocs docs = indexSearcher.search(query, 3);
ScoreDoc[] scoreDocs=docs.scoreDocs;
for (ScoreDoc scoreDoc:scoreDocs){
//獲取document對象屬性
//documentId
int did = scoreDoc.doc;
Document docObj = indexSearcher.doc(did);
System.out.println("============"+did+"============");
System.out.println(docObj.get("title"));
System.out.println(docObj.get("origin"));
System.out.println(docObj.get("content"));
}
}
查詢結果:
布爾查詢
布爾查詢是使用最廣泛的一種查詢方式。可以組合其它所有的查詢條件。可以將任何query對象作爲布爾查詢的子條件,從而決定最終的結果。比如在京東購買手機,可以選擇品牌、價格區間、存儲大小等組合條件進行查詢。
由於前後代碼都類似,這裏只展示查詢條件的創建過程:
//要查詢的域
String[] files={"title","origin","content"};
//創建多域查詢條件1
MultiFieldQueryParser parser=new MultiFieldQueryParser(files,new SmartChineseAnalyzer());
Query query= parser.parse("疫苗");
//創建詞項查詢條件2
Term term=new Term("title","中國");
Query query2= new TermQuery(term);
//封裝布爾查詢子條件
BooleanClause bc1=new BooleanClause(query,BooleanClause.Occur.MUST);
BooleanClause bc2=new BooleanClause(query2,BooleanClause.Occur.MUST);
//封裝最終查詢條件
Query finalQuery=new BooleanQuery.Builder().add(bc1).add(bc2).build();
代碼中,以下這兩項的意思是,查詢既滿足query又滿足query2的結果,也就是查詢query和query2的交集:
BooleanClause bc1=new BooleanClause(query,BooleanClause.Occur.MUST);
BooleanClause bc2=new BooleanClause(query2,BooleanClause.Occur.MUST);
這裏的各種組合關係,我們用圖例說明:
取得query和query2查詢子句的交集:
表示查詢結果中不能包含MUST_NOT所對應的查詢子句的檢索結果:
MUST_NOT和MUST_NOT連用,沒有任何搜索結果,查詢無意義:
除此之外,還有SHOULD,有興趣的可以繼續深入拓展。
範圍查詢
可以對域屬性中數字類型進行範圍查詢。
比如:查詢文章點擊率在10-70次的文章
//範圍查詢 文章點擊率在10-70次的文檔
Query rangeQuery=IntPoint.newRangeQuery("clickNum",10,70);
模糊查詢
在title域中查找和“苗”類似的詞語:
//模糊查詢
Query fuzzyQuery=new FuzzyQuery(new Term("title","苗"));
通配查詢
?代表任意一個字符。* 代表任意多個字符。
//通配查詢
Query wquery=new WildcardQuery(new Term("content","?國"));