zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    Laravel schema构建器列类型
    wkhtmltopdf docker + java(环境搭建及一些坑)
    dockerfile,仓库,私有仓库流程(转载)
    wkhtmltopdf参数详解及精讲使用方法(转载)
    传统前端项目中进行模块化编程并引入使用vue、elementui 前端
    vue3 + vuex4 实践 前端
    elementplus 原生开发 日期国际化语言 前端
    Vite2.0打包elementplus UI报错 前端
    vue3 Vetur报错:has no default export 组件没导出 前端
    windows版的HbuilderX连接iPad真机测试(uniapp)
  • 原文地址:https://www.cnblogs.com/edwinchen/p/4268005.html
Copyright © 2011-2022 走看看