solr4.7.2自定义后置过滤器PostFilter

fq(Filter Query)参数

fq 参数定义了一个查询,可以用来限制可以返回的文档的超集,而不影响 score。这对于加快复杂查询非常有用,因为指定的查询 fq 是独立于主查询而被缓存的。当以后的查询使用相同的过滤器时,会有一个缓存命中,过滤器结果从缓存中快速返回。

使用该 fq 参数时,请记住以下几点:

  1. 该 fq 参数可以在查询中多次指定
  2. filter 查询可能涉及复杂的 Boolean 查询
  3. 每个过滤器查询的文档集都是独立缓存的
  4. 还可以在 fq 内部使用 filter(condition) 语法来单独缓存子句, 以及在其他情况下,实现缓存的筛选器查询的联合
  5. 与所有参数一样:URL 中的特殊字符需要正确转义并编码为十六进制值

cache 参数

Solr 默认缓存所有查询的结果并过滤查询。
要禁用结果缓存,请设置 cache=false 参数。
可以使用 成本(cost)选项来控制计算非缓存筛选器查询的顺序。这使您可以在昂贵成本的非缓存过滤器之前订购更便宜成本的非缓存过滤器。
对于成本非常高的过滤器,如果 cache=false 并且 cost>=100 和查询实现了 PostFilter 接口,则将从该查询请求收集器,并在匹配主查询和所有其他过滤器查询后用于过滤文档。
可以有多个后置过滤器;他们也按成本cost排序。

SolrIndexSearcher

SolrIndexSearcher类中getProcessedFilter方法定义了PostFilter的使用逻辑

public ProcessedFilter getProcessedFilter(DocSet setFilter, List<Query> queries) throws IOException {
    ProcessedFilter pf = new ProcessedFilter();
    if (queries==null || queries.size()==0) {
      if (setFilter != null)
        pf.filter = setFilter.getTopFilter();
      return pf;
    }

    ........省略部分代码..........
    
    for (Query q : queries) {
      if (q instanceof ExtendedQuery) {
        ExtendedQuery eq = (ExtendedQuery)q;
        if (!eq.getCache()) {
          if (eq.getCost() >= 100 && eq instanceof PostFilter) {
            if (postFilters == null) postFilters = new ArrayList<Query>(sets.length-end);
            postFilters.add(q);
          } else {
            if (notCached == null) notCached = new ArrayList<Query>(sets.length-end);
            notCached.add(q);
          }
          continue;
        }
      }
      ........省略部分代码..........    
    } 
    ........省略部分代码.......... 

    if (postFilters != null) {
      Collections.sort(postFilters, sortByCost);
      for (int i=postFilters.size()-1; i>=0; i--) {
        DelegatingCollector prev = pf.postFilter;
        pf.postFilter = ((PostFilter)postFilters.get(i)).getFilterCollector(this);
        if (prev != null) pf.postFilter.setDelegate(prev);
      }
    }

    return pf;
}

分析代码可知要使用自定义PostFilter,必须cache=false 并且 cost>=100

编写自定义PostFilter

1) schema.xml定义

id 和 spopulation 启用docValues,在过滤器中可通过docid取 id 和 spopulation 值

  <field name="id"          type="string"   indexed="true"  stored="true"  multiValued="false" docValues="true" /> 
  <field name="sname"       type="string"   indexed="true"  stored="true"  multiValued="false" /> 
  <field name="slocation"   type="string"   indexed="true"  stored="true"  multiValued="false" /> 
  <field name="sdes"        type="text_ik"  indexed="true"  stored="true"  multiValued="false" /> 
  <field name="sarea"       type="string"   indexed="true"  stored="true"  multiValued="false" />  
  <field name="spopulation" type="long"     indexed="true"  stored="true"  multiValued="false" docValues="true" /> 
 

2)过滤逻辑

     假设过滤查询结果中 spopulation>某个值 and id 不能空的

3)   编写过滤器

public class MyFilterQParserPlugin extends QParserPlugin {

    private final Logger log = LoggerFactory.getLogger(MyFilterQParserPlugin.class);

    public MyFilterQParserPlugin() {

    }

    @Override
    public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
        log.info("MyFilterQParserPlugin createParser start !!!");
        // 是否启用过滤逻辑
        boolean enable = localParams.getBool("enable");
        // 过滤条件最小值
        String min = localParams.get("min");
        if (StringUtils.isBlank(min)) {
            throw new IllegalArgumentException(
                    "field:" + enable + " has not been define in localParam");
        }
        log.info("MyFilterQParserPlugin qstr=" + qstr);
        log.info("MyFilterQParserPlugin enable=" + String.valueOf(enable));
        log.info("MyFilterQParserPlugin min=" + min);
        final MyFilterQuery q = new MyFilterQuery(enable, min);
        return new QParser(qstr, localParams, params, req) {
            @Override
            public Query parse() throws SyntaxError {
                return q;
            }
        };
    }

    @Override
    public void init(NamedList args) {

    }
}
public class MyFilterQuery extends ExtendedQueryBase implements PostFilter {
    private final Logger log = LoggerFactory.getLogger(MyFilterQuery.class);
    private final String min;
    private final Boolean enable;

    public MyFilterQuery(Boolean enable,String min) {
        this.enable = enable;
        this.min = min;
    }

    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }

    @Override
    public boolean equals(Object obj) {
        return this == obj;
    }

    @Override
    public void setCache(boolean cache) {

    }

    @Override
    public boolean getCache() {
        return false;
    }

    @Override
    public int getCost() {
        return Math.max(super.getCost(), 100);
    }

    @Override
    public DelegatingCollector getFilterCollector(IndexSearcher searcher) {
        try {
            return new DelegatingCollector() {
                AtomicReader reader;
                @Override
                public void collect(int doc) throws IOException {
                    //获取id的docValues
                    SortedDocValues idDocValue = this.reader.getSortedDocValues("id");
                    BytesRef byteRef = new BytesRef();
                    //根据docid取值
                    idDocValue.get(doc, byteRef);
                    String id = byteRef.utf8ToString();

                    Long spopulation=0L;
                    //获取spopulation的docValues
                    NumericDocValues spopulationDocValue = this.reader.getNumericDocValues("spopulation");
                    //根据docid取值
                    spopulation=spopulationDocValue.get(doc);

                    /**
                     * 业务处理,id不为空,并且 spopulation 大于最小值
                     */
                    if(enable) {
                        if (StringUtils.isNotEmpty(id) && spopulation >= Long.valueOf(min)) {
                            // 保留记录
                            super.collect(doc);
                        }
                    }
                    else{
                        super.collect(doc);
                    }
                }

                @Override
                public void setNextReader(AtomicReaderContext context) throws IOException {
                    super.setNextReader(context);
                    this.reader = context.reader();
                }
            };
        } catch (Exception var3) {
            this.log.error("Exception{}", var3);
            return null;
        }
    }
}

自定义过滤器有2个自定义参数:

  1. enable  是否启用过滤逻辑
  2. min 过滤的最小值

过滤器使用方式:

fq={!myFilter min=1000000000 enable=true}查询字符串

4) solrconfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<config>
<queryParser name="myFilter" class="cn.chy.plugin.postfilter.MyFilterQParserPlugin" />
....省略部分配置.....
</config>

5)jar包

solr默认加载core目录中lib目录中的jar包,将jar包放到lib目录即可

6)启动加载solrcore配置

7)  查询

http://localhost:8892/solr/testindex_shard3_replica1/select?q=sdes%3A%E7%BE%8E%E4%B8%BD&fq=%7B!myFilter+min%3D1000000000+enable%3Dtrue%7Dtest&wt=json&indent=true

8) enable:false

不启用过滤

9) enable:true

启用过滤

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Solr是一个基于Java的搜索引擎,可以用Java实现自定义排序。以下是实现自定义排序的步骤: 1. 创建一个自定义排序器类,实现org.apache.solr.search.SortComparator。 2. 在自定义排序器类中实现compare方法,该方法接收两个参数,即要比较的文档对象。 3. 在compare方法中实现自定义排序逻辑,根据需要将文档对象进行排序。 4. 在solrconfig.xml文件中配置自定义排序器,将其添加到fieldType中。 5. 在查询请求中指定使用自定义排序器。 下面是一个示例代码,演示了如何使用Java实现自定义排序器: ```java public class CustomSortComparator extends SortComparator { @Override public int compare(SortField sortField, SchemaField schemaField, FieldComparator<?> fieldComparator1, FieldComparator<?> fieldComparator2) throws IOException { // 获取要比较的文档对象 Object value1 = fieldComparator1.value(sortField.getReverse()); Object value2 = fieldComparator2.value(sortField.getReverse()); // 根据自定义逻辑进行排序 if (value1 instanceof Long && value2 instanceof Long) { Long long1 = (Long) value1; Long long2 = (Long) value2; if (long1 > long2) { return sortField.getReverse() ? -1 : 1; } else if (long1 < long2) { return sortField.getReverse() ? 1 : -1; } else { return 0; } } // 默认情况下,按照Solr默认的排序逻辑进行排序 return super.compare(sortField, schemaField, fieldComparator1, fieldComparator2); } } ``` 在solrconfig.xml文件中配置自定义排序器: ```xml <fieldType name="text_custom" class="solr.TextField"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> </analyzer> <sortComparator class="com.example.CustomSortComparator"/> </fieldType> ``` 在查询请求中指定使用自定义排序器: ```sh http://localhost:8983/solr/mycore/select?q=*:*&sort=custom_field+desc&fl=field1,field2&defType=edismax&wt=json ``` 以上代码演示了如何使用Java实现自定义排序器,通过实现compare方法自定义排序逻辑,将自定义排序器添加到fieldType中,在查询请求中指定使用自定义排序器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值