lucene中的Filter
来源:互联网 发布:国际网络购物平台 编辑:程序博客网 时间:2024/05/21 01:57
前言
用Lucene一定不能不知道Filter,Filter在合适的场景下能大大提升搜索性能
背景
最近在折腾solr,这个3年前“玩过”的东西,现在又来玩了,3年前是瞎比玩,只知道最上层的一些接口,却不知其所以然,而现在的目标就是要把solr以及lucene底层的核心代码都分析一遍,并成功的部署一套电商搜索解决方案。
Filter逻辑
Filter的构造逻辑其实本身和Query的构造逻辑差距不大,唯一一点不一样的就是Query之后会在collector中进行打分,并使用堆来进行一个结果的取舍。
那么在lucene中Filter是怎么用的呢?首先需要知道Filter的功能,那就是通过某个条件把所有符合这个条件的docid拿到, 然后在构造scorer的时候把这些符合条件docid传过来,然后遍历这些符合条件的docid,通过query对应的相关信息,例如similarity等对这个doc打分。 所以说,如果你的filter能够把结果限制在很少的范围内的话,那么即使你的similarity或者是customScoreProvider稍微复杂点,那也是可以接受的。
调用层次:
1. Filter和Query都传给searcher
2. 把Filter和Query通过wrapFilter构造出FilteredQuery,通过filter条件过滤docid的逻辑就在FilteredQuery中:
public Scorer scorer(AtomicReaderContext context, boolean scoreDocsInOrder, boolean topScorer, final Bits acceptDocs) throws IOException { assert filter != null; final DocIdSet filterDocIdSet = filter.getDocIdSet(context, acceptDocs); if (filterDocIdSet == null) { // this means the filter does not accept any documents. return null; } return strategy.filteredScorer(context, scoreDocsInOrder, topScorer, weight, filterDocIdSet); }
- Scorer在collector文档的时候,只要扫一遍通过filter query筛选出来的候选集即可
public void score(Collector collector) throws IOException { collector.setScorer(this); int doc; while ((doc = nextDoc()) != NO_MORE_DOCS) { collector.collect(doc); } }
SOLR
那么在solr里的filter query是怎么玩的呢?
- solr里的fq参数会被searchHandler中的QueryComponent.prepare方法解析,并且构造这些field:value对应的query存到QueryComponent的rb(ResponseBuilder)中,并把rb存放到见下代码:
String[] fqs = req.getParams().getParams(CommonParams.FQ);if (fqs!=null && fqs.length!=0) { List<Query> filters = rb.getFilters(); if (filters==null) { filters = new ArrayList<Query>(fqs.length); } for (String fq : fqs) { if (fq != null && fq.trim().length()!=0) { QParser fqp = QParser.getParser(fq, null, req); filters.add(fqp.getQuery()); } } // only set the filters if they are not empty otherwise // fq=&someotherParam= will trigger all docs filter for every request // if filter cache is disabled if (!filters.isEmpty()) { rb.setFilters( filters ); }}
- QueryComponent的prepare进行完后,执行process,进行搜索,这里把rb中的filter,query等一系列参数传给SolrIndexSearcher.QueryCommand,然后执行SolrIndexSearcher的search方法
SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand();。。。。searcher.search(result,cmd);
- 然后在SolrIndexSearcher中解析cmd中的filter,其中所有filter都存放在一个以Query类为模板的List中。然后在getDocListNC中调用getProcessedFilter,这个函数是干什么的呢,就是把每个filter对应的Query解析成一个个DocSet,然后根据这些filter的AND或者OR的关系去对这些DocSet取交集或者并集,这样就生成了一个候选的DocSet,大大减小了待查询打分的候选集。见getProcessedFilter的部分代码:
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; } } Query posQuery = QueryUtils.getAbs(q); sets[end] = getPositiveDocSet(posQuery); // Negative query if absolute value different from original if (q == posQuery) { neg[end] = false; // keep track of the smallest positive set. // This optimization is only worth it if size() is cached, which // it would // be if we don't do any set operations. int sz = sets[end].size(); if (sz < smallestCount) { smallestCount = sz; smallestIndex = end; answer = sets[end]; } } else { neg[end] = true; } end++;}
这里还有个比较有意思的地方,对于每个Filter,要先看看它是不是负的,即”-brand_name:宝马”就是所有品牌不是宝马的内容,这里的方法是先取这个Filter的“绝对值”,即“brand_name:宝马”得到DocSet A,然后通过matchAllDocsQuery得到包含所有文档的DocSet B,然后B.andNot(A)就可以把B中的A的内容排除掉,实现了取反的逻辑。
至此,Filter Query的任务也就告一段落了,不过还有一些Cache相关的东西
Filter Cache
- lucene中的Filter
- apache lucene cutom filter
- Lucene Filter的例子
- lucene自定义过滤器Filter
- Lucene - 自定义过滤器Filter
- 【Lucene】Lucene中的CRUD
- Lucene使用Filter搜索过滤
- lucene搜索中filter的使用
- Lucene中Filter的性能问题
- Lucene Search(2)-filter,collector,querybuild
- Lucene中的Field
- Lucene中的基本概念
- lucene中的删除索引
- Lucene中的范围搜索
- Lucene中的基本概念
- Lucene中的Analyzer
- lucene中的ranking算法
- Lucene中的特殊字符
- 白天夜间模式切换
- Multi-University 2015 #6 E(hdu 5357 Easy Sequence)
- 分布式系统(一)分布式系统介绍
- C语言基础 优秀习惯起名字与赋初值
- Context应用场景
- lucene中的Filter
- 碎片的生命周期
- 关键子工程
- caffe|Fine-tuning for driver
- 浅谈Android实现3D旋转
- docker 入门
- JavaScript中的call()和apply()方法
- 238. Product of Array Except Self
- 网络编程socket(服务端简单模拟)(OC)