Lucene自定義擴展QueryParser


Lucene版本:4.10.2

 

在使用lucene的時候,不可避免的需要擴展lucene的相關功能來實現業務的需要,比如搜索時,需要在滿足一個特定范圍內的document進行搜索,如年齡在20和30歲之間的document中搜索並排序。其實lucene自帶的NumericRangeQuery類已經能實現這個功能了,如下:

public void testInclusive() throws Exception {

    Directory dir = FSDirectory(---);

    IndexSearcher searcher = new IndexSearcher(dir);

 

    NumericRangeQuery query = NumericRangeQuery.newIntRange("age",20,30,true,true);

    TopDocs matches = searcher.search(query,10);

}

 

這個是通過lucene內置的query類型來進行搜索,但是這樣使用起來的缺點就是無法再搜索期間生成對應的NumericRangeQuery實例,如比如直接在搜索的時候傳入搜索text: age:[20 TO 30],這樣就可以動態的使用范圍搜索,更為靈活,那么要是實現這個功能,我們就需要自定義QueryParser了。

QueryParser,故名思議,就是講前台傳入的查詢條件,解析為Query實例,從而進行查詢,所以簡單的說,我們需要自定義一個NumericRangeQueryParser,用來實現,從 age:[20 TO 30] 轉化為

NumericRangeQuery query = NumericRangeQuery.newIntRange("age",20,30,true,true); 

的一個Query實例。

 

在lucene中擴展QueryParser是比較簡單的,我們可以直接繼承QueryParser類,然后實現特定的方法就可以了(查詢age在20至30歲的記錄):

 

        //自定義queryParser
    class NumericRangeQueryParser extends QueryParser {

        /**
         * @param arg0
         */
        protected NumericRangeQueryParser(String field,Analyzer analyzer) {
            //調用父類的構造方法
            super(field,analyzer);
            // TODO Auto-generated constructor stub
        }
        
        //獲取query實例的方法
        public Query getRangeQuery(String field,String part1,String part2,boolean startInclusive,boolean endInclusive) throws ParseException {
            //調用父類的getRangeQuery方法獲取query實例
            TermRangeQuery query = (TermRangeQuery) super.getRangeQuery方法獲取query實例(field, part1, part2, startInclusive,endInclusive);
            //如果是搜索age Field
            if("age".equals(field)) {
                System.out.println(query.getLowerTerm().utf8ToString());
                System.out.println(query.getUpperTerm().utf8ToString());

                //按照業務需求處理query生成新的query實例並返回
                return NumericRangeQuery.newDoubleRange("price", Double.parseDouble(query.getLowerTerm().utf8ToString()),
                        Double.parseDouble(query.getUpperTerm().utf8ToString()), query.includesLower(), query.includesUpper());
            } else {
                return query;
            }
        }
        
    }

 

其實代碼很簡單,因為我只是將范圍查詢的上下限從Int類型格式化成Double類型。其中最重要的一條代碼是:

NumericRangeQuery.newDoubleRange("price", Double.parseDouble(query.getLowerTerm().utf8ToString()),

                        Double.parseDouble(query.getUpperTerm().utf8ToString()), query.includesLower(), query.includesUpper());

 

NumericRangeQuery.newDoubleRange是調用了lucene自帶的方法來生成相應的query實例,在這里是浮點數范圍查詢Query實例。其中參數的解釋:

query.getLowerTerm().utf8ToString():getLowerTerm是指獲取范圍查詢中的下限,在這里是20。getLowerTerm()返回一個BytesRef對象,lucene自定義的一種對象,我們需要轉換成String類型再轉成Double類型的對象,傳給NumericRangeQuery.newDoubleRange方法,在這里我一開始想到的是toString方法,結果老是報錯,最后查看源碼才知道應該使用utf8ToString()方法,它會將BytesRef轉成utf8編碼的String對象。

public String utf8ToString()

Interprets stored bytes as UTF8 bytes, returning the resulting string

 

query.getUpperTerm().utf8ToString():與query.getLowerTerm().utf8ToString()同理,獲取范圍查詢中的上限,在這里是30

 

query.includesLower()和query.includesUpper():是否包含臨界值,在這里值是否包含年齡為20和30歲的記錄,即[20,30]或[20,30)…

 

下面我沒來測試NumericRangeQueryParser:

    public static void main(String[] args) throws IOException, ParseException {
        String expression = "age:[10 TO 20]";
        Analyzer analyzer  = new StandardAnalyzer();
        QueryParser parser = new QueryParser("age",analyzer);
        Query query = parser.parse(expression);
        
        QueryParser testParser = kscSearch.new NumericRangeQueryParser("age",analyzer);
        Query testQuery = testParser.parse(expression);
        
        System.out.println(expression + "  parser to  " + query);
        System.out.println(expression + "  parser to  " + testQuery);
    }

 

測試結果如下:

age:[10 TO 20] parser to age:[10 TO 20]

age:[10 TO 20] parser to price:[10.0 TO 20.0]

 

可以看到使用NumericRangeQueryParser后,10和20都變成了浮點數。

 

相應的我們可以自定義日期QueryParser或者是更為復雜的QueryParser。不過從這個簡單的NumericRangeQueryParser中我們可以看到QueryParser的原理,就是講給定的查詢字符串解析生成Lucene能識別的Query實例,從而進行查詢,我們這里是使用了Lucene內置的NumericRangeQuery擴展QueryParser,如果有需要,甚至可以自定義NumericRangeQuery。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM