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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值