文章出處

 上一節主要總結了一下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中加就行了。這很方便,一般查詢條件多的時候,就可以采用這種組合的查詢方式來查詢。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()