文章出處

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();
}

多域分詞查詢, 沒啥好說的了. 

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

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