背景
实际业务场景中,有时会需要两阶段过滤,最终的搜索结果是在前一个搜索结果上进一步搜索而得到的(search-within-search)的特性。
假设,最终搜索结果集是由(A AND B)两个条件对应的命中结果集求交而得到的。如果A条件对应的文档集合非常小(大概不超过300个),而B条件对应的文档集合非常大。在这样的场景下在solr中使用二阶段过滤的方式来查询就再合适不过了。
详细实现
第一阶段,通过A求得命中结果集合,然后第二节点在第一阶段基础上再进行过滤。
对于第一阶段没有什么好说了了,只要在solr中设置普通参数q就能实现,关键是第二阶段过滤。
在已经得到的命中结果集合上继续进行搜索缩小结果集合的方法其实就是早期Lucene版本中的Filter,但是不知道为什么,在高版本的Lucene中已经把Filter从lucene中去掉了,完全由collector链取代了。(可能是觉得Filter和Collector的功能重合了)
首先要使用org.apache.solr.search.PostFilter, 接口说明如下:
/** The PostFilter interface provides a mechanism to further filter documents * after they have already gone through the main query and other filters. * This is appropriate for filters with a very high cost. * <p> * The filtering mechanism used is a {@link DelegatingCollector} * that allows the filter to not call the delegate for certain documents, * thus effectively filtering them out. This also avoids the normal * filter advancing mechanism which asks for the first acceptable document on * or after the target (which is undesirable for expensive filters). * This collector interface also enables better performance when an external system * must be consulted, since document ids may be buffered and batched into * a single request to the external system. * <p> * Implementations of this interface must also be a Query. * If an implementation can only support the collector method of * filtering through getFilterCollector, then ExtendedQuery.getCached() * should always return false, and ExtendedQuery.getCost() should * return no less than 100. */
很重要的一点,在子类中需要设置cache为false,cost不能小于100,对应的代码为SolrIndexSearcher中的+getProcessedFilter()方法中的一小段:
if (q instanceof ExtendedQuery) { ExtendedQuery eq = (ExtendedQuery)q; if (!eq.getCache()) { if (eq.getCost() >= 100 && eq instanceof PostFilter) { if (postFilters == null) postFilters = new ArrayList<>(sets.length-end); postFilters.add(q); } else { if (notCached == null) notCached = new ArrayList<>(sets.length-end); notCached.add(q); } continue; } }
当Query对象满足eq.getCache()为false,cost>=100,且PostFilter对象之后会把query对象放到postFilters list中以备后用。
另外,加之lucene高版本中,加入了docValue这一特性,使得在第二阶段中通过docid求对应field内容变得可行了,以前没有docvalue的时候,只能讲field的值通过fieldCache的方式缓存到内存中,现在使用docValue大大降低了内存的开销。
构建PostFilterQuery:
public class PostFilterQuery extends ExtendedQueryBase implements PostFilter { private final boolean exclude; private final Set<String> items; private final String field; public PostFilterQuery(boolean exclude, Set<String> items, String field) { super(); this.exclude = exclude; this.items = items; this.field = field; } @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; } public int getCost() { return Math.max(super.getCost(), 100); } @Override public DelegatingCollector getFilterCollector(IndexSearcher searcher) { return new DelegatingCollector() { private SortedDocValues docValue; @Override public void collect(int doc) throws IOException { int order = this.docValue.getOrd(doc); if (order == -1) { if (exclude) { super.collect(doc); } return; } BytesRef ref = this.docValue.lookupOrd(order); if (items.contains(ref.utf8ToString())) { if (!exclude) { super.collect(doc); } } else { if (exclude) { super.collect(doc); } } } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { super.doSetNextReader(context); this.docValue = DocValues.getSorted(context.reader(), field); } }; } }
该类中构造函数参数传入了三个值的意义:
- boolean exclude:使用排除过滤还是包含过滤
- Set<String> items:需要过滤的item集合
- String field:通过Document文档上的那个field来过滤。
为了让这个Query类在查询的时候生效,需要写一个queryParserPlugin:
public class PostFilterQParserPlugin extends QParserPlugin { @Override @SuppressWarnings("all") public void init(NamedList args) { } @Override public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { boolean exclude = localParams.getBool("exclude"); String field = localParams.get(CommonParams.FIELD); if (field == null) { throw new IllegalArgumentException( "field:" + field + " has not been define in localParam"); } Set<String> items = Sets.newHashSet(StringUtils.split(qstr, ',')); final PostFilterQuery q = new PostFilterQuery(exclude, items, field); return new QParser(qstr, localParams, params, req) { @Override public Query parse() throws SyntaxError { return q; } }; }}
将这个plugin配置solr-config.xml中:
<queryParser name="postfilter" class="com.dfire.tis.solrextend.queryparse.PostFilterQParserPlugin" />
接下来就是在Solr客户端查询过程中使用了,以下是一个例子:
SolrQuery query = new SolrQuery(); query.setQuery("customerregister_id:193d43b1734245f5d3bf35092dbb3a40"); query.addFilterQuery("{!postfilter f=menu_id exclude=true}000008424a4234f0014a5746c2cd1065,000008424a4234f0014a5746c2cd1065"); SimpleQueryResult<Object> result = client.query("search4totalpay", "00000241", query, Object.class); System.out.println("getNumberFound:" + result.getNumberFound());
总结
使用postfilter在特定场景下可以大大提高查询效率,不妨试试吧!
相关推荐
本文将围绕"基于Solr的多表join查询加速方法"这一主题,深入探讨如何在Solr中实现类似join的功能,并优化查询性能。 在Solr中模拟join操作通常有两种策略:嵌入式数据模型和外部数据源查询(ExternalFileField或...
这些测试结果对于理解和优化 Solr 在实际应用中的性能具有重要的指导意义。在选择 Solr 部署模式时,需要根据具体的业务需求和预期的并发量来权衡单节点和集群的优劣。在需要高性能读写和高可用性的场景下,Solr ...
solr在做检索的时候时常需要得知他的性能参数,此处使用8G内存,双核处理器测试的结果
随着传统互联网和移动互联网的持续发展,网络带给我们的...目前一些搜索公司在公共互联网领域提供了很好的解决方案,但是企业或者政府机关内部相关信息往往需要应用独立的搜索系统,Solr Cloud则是很好的一个平台选择。
随着业务增长和技术进步,Solr需要不断进行优化以满足更高的性能需求。本文将详细介绍如何针对不同场景优化Solr。 #### 二、Solr扩展策略详解 ##### 1. Scale High - 单台服务器优化 在单一Solr服务器上通过调整...
3. **查询优化**:Solr会根据查询条件和索引结构自动优化查询计划,包括使用倒排索引来快速定位匹配文档,以及对查询结果进行评分排序。 4. **高亮显示**:Solr能够对查询结果中的匹配词进行高亮,提高用户查找相关...
这些配置有助于优化搜索性能和结果的相关性。 在提供的压缩包中,尽管只有一个名为"新建文本文档 (2).txt"的文件,但通常在Solr的`manageschema`配置中,我们期望看到的是一个XML格式的Schema定义,其中包含各种...
### Solr性能优化关键知识点详解 #### 一、理解Solr环境与版本 - **环境配置**:在本文档中,我们关注的是基于Tomcat 6的Solr 3.5版本的部署与优化,这对于初学者来说是一个非常实用且稳定的组合。 - **Solr简介...
接下来,我们可能需要对Solr的查询解析器进行配置,以便支持自定义的函数查询。这通常涉及到修改`schema.xml`或`managed-schema`文件,定义新的查询字段类型和查询解析器。例如,可以创建一个新的查询解析器,专门为...
2. 引入了新的查询执行模型(Distributed Searcher):优化了分布式查询的性能和稳定性。 3. 增强的CSV处理:支持更大的CSV文件导入,改进了错误处理机制。 4. 优化的内存管理:减少了内存消耗,提高了系统稳定性。 ...
Solr是一个开源搜索平台,用于构建搜索应用程序。Solr可以和Hadoop一起使用。由于Hadoop处理大量数据,Solr帮助我们从这么大的...总之,Solr是一个可扩展的,可部署,搜索/存储引擎,优化搜索大量以文本为中心的数据。
Solr的多种性能优化技巧,如索引的性能优化、缓存的性能 优化、查询的性能优化、JVM和Web容器的优化,以及操作系统级别的优化。 拓展知识中首先讲解了Solr的一些比较生僻的知识点,如伪域、多语种索引支持、安全认证...
Solr是一种基于Apache Lucene的开源搜索引擎,提供了丰富的查询语法来满足各种搜索需求。在了解Solr查询语法前,我们首先需要了解几个核心概念。 首先,Solr的查询解析是通过queryParser来配置的,通常使用默认配置...
在查询方面,ES允许通过JSON格式或者URL进行查询,并且可以通过curl或者ElasticSearch-Head(一个类似于Solr Admin页面的工具)来进行操作。ES的查询灵活性在于它支持在查询过程中进行完整的脚本编写,从而实现对...
8. **搜索性能优化**:Solr提供了多种优化手段,包括使用倒排索引、缓存策略、查询优化器等,以提高查询速度和整体性能。 9. **安全与认证**:Solr 8.x引入了内置的安全性框架,包括Zookeeper的ACL和Solr的Role-...
- **查询性能指标**: - `QueryTime`:查询时间,单位毫秒。 - `ElapsedTime`:总的处理时间,单位毫秒。 - **查询结果**: - 总计条数:查询结果的总条数。 - 本批次条数:当前批次返回的文档数量。 - 文档...
- **性能优化**:Solr团队不断努力提升查询速度和索引效率,8.11.1版本可能包含了一些新的性能优化。 - **新功能**:可能引入了新的搜索特性,比如新的查询语法、更强大的分析器或者对最新技术标准的支持。 - **稳定...
"solr性能调优.mht"文件专门针对Solr的性能优化,包括索引优化、硬件配置、查询策略调整等方面,对于追求高效稳定运行的Solr系统来说,这部分内容是必不可少的。 这些文档和资料覆盖了Solr的多个方面,包括入门、...
1.2.5 缓存:Solr内置了多种缓存机制,如查询结果缓存、文档ID到DocValue的缓存等,显著提高了搜索性能。 1.2.6 复制:Solr支持主从复制,确保数据的安全性和高可用性,可以轻松地扩展集群规模。 1.2.7 管理接口:...