`
mozhenghua
  • 浏览: 324420 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

solr多组Merge Query原理

 
阅读更多

概要

    Solr和ES搜索引擎都有集群模式,在Solr中可以向任何一个节点发起一个查询,如果查询中没有附带路由router键的话,该节点会扮演Merge的角色向集群中每个share的一个副本发起查询,最终将所有取到的结果排序,返回给客户端。

 

详细

   为了测试需要在测试集群中构建一个Collection,有两个shard(shard中只有一个副本),使用查询Q为:id:9922600464a707520164a75ded18001f OR id:0000000064db34070164db344a460004,查询条件中的id在两个shard上各有一个存在。

   从查询结果看集群中,一共累计进行了5次查询哭,为了实现一个全shard扫描查询将本来一个查询变成了5次查询,这还只是在shard为2的时候。经过试验,在shard为n的,集群merge查询会发起 1+n+1 到 1+2n 个子查询,所以在生产环境中尽量应该避免使用merge查询。

 

查询日志详细

最终结果集落在两个分片上

 

从2组上查询候选记录

15:09:31 [x:search4xxxx_shard2_replica1] INFO o.apache.solr.core.SolrCore.Request

- [search4xxxx_shard2_replica1]  webapp=/solr path=/select

params={df=text

&distrib=false

&fl=id

&fl=score

&shards.purpose=4

&start=0

&fsv=true

&shard.url=http://127.0.0.1:8080/solr/search4xxxx_shard2_replica1/

&rows=2

&version=2

&q=id:9922600464a707520164a75ded18001f+OR+id:0000000064db34070164db344a460004

&NOW=1533020971828

&isShard=true

&wt=javabin&_=1533019917767} hits=1 status=0 QTime=0

 

 

从1组上查询候选记录

shards.purpose=4

15:09:31 [x:search4xxxx_shard1_replica1] INFO o.apache.solr.core.SolrCore.Request- [search4xxxx_shard1_replica1]  webapp=/solr path=/select params={df=text&distrib=false&fl=id&fl=score&shards.purpose=4&start=0&fsv=true

&shard.url=http://127.0.0.1:8080/solr/search4xxxx_shard1_replica1/

&rows=2

&version=2

&q=id:9922600464a707520164a75ded18001f+OR+id:0000000064db34070164db344a460004

&NOW=1533020971828

&isShard=true

&wt=javabin

&_=1533019917767} hits=1 status=0 QTime=0

 

 

从1组上召回field内容

shards.purpose=64

15:09:31 [x:search4xxxx_shard1_replica1] INFO o.apache.solr.core.SolrCore.Request- [search4xxxx_shard1_replica1]  webapp=/solr path=/select params={

df=text

&distrib=false

&fl=id,[shard]

&shards.purpose=64

&shard.url=http://127.0.0.1:8080/solr/search4xxxx_shard1_replica1/

&rows=2

&version=2

&q=id:9922600464a707520164a75ded18001f+OR+id:0000000064db34070164db344a460004

&NOW=1533020971828

&ids=0000000064db34070164db344a460004

&isShard=true

&wt=javabin&_=1533019917767} status=0 QTime=0

 

 

从2组上召回field内容

shards.purpose=64

ids=9922600464a707520164a75ded18001f

15:09:31 [x:search4xxxx_shard2_replica1] INFO o.apache.solr.core.SolrCore.Request-

[search4xxxx_shard2_replica1]  webapp=/solr path=/select params={

df=text

&distrib=false

&fl=id,[shard]

&shards.purpose=64

&shard.url=http://127.0.0.1:8080/solr/search4xxxx_shard2_replica1/

&rows=2

&version=2

&q=id:9922600464a707520164a75ded18001f+OR+id:0000000064db34070164db344a460004

&NOW=1533020971828

&ids=9922600464a707520164a75ded18001f

&isShard=true

&wt=javabin

&_=1533019917767} status=0 QTime=0

 

 

总查询

15:09:31 [x:search4xxxx_shard2_replica1] INFO o.apache.solr.core.SolrCore.Request- [search4xxxx_shard2_replica1] 

webapp=/solr

path=/select params={

q=id:9922600464a707520164a75ded18001f+OR+id:0000000064db34070164db344a460004

&indent=on

&fl=id,[shard]

&rows=2&wt=json

&_=1533019917767} hits=2 status=0 QTime=44

 

利用Solr的SearchComponent来优化MergeQuery

Solr客户端查询经常有通过Id列表的方式获取数据(这些Id是分布在多个shard上),换句话说客户端不需要对查询结果翻页,结果都在一页之中,有这样的前提就意味着可以省掉数据集排序的过程了,而排序在Mergequery中占用了非常多的时间,通过这个优化可以大大提高MergeQuery的查询性能。

 

可以扩展org.apache.solr.handler.component.SearchComponent 类来实现:

覆写distributedProcess方法:

	@Override
	public int distributedProcess(ResponseBuilder rb) throws IOException {
		if (rb.stage < ResponseBuilder.STAGE_GET_FIELDS)
			return ResponseBuilder.STAGE_GET_FIELDS;
		if (rb.stage == ResponseBuilder.STAGE_GET_FIELDS) {
			return createSubRequests(rb);
		}
		return ResponseBuilder.STAGE_DONE;
	}

 将本来需要两个阶段的MergeQuery 简化成只有一个阶段(STAGE_GET_FIELDS阶段)省去了数据排序流程,直接出数据。详细代码:

package com.dfire.tis.solrextend.handler.component.s4product;

import java.io.IOException;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.handler.component.ShardRequest;

public class RealtimeGetQueryComponent extends SearchComponent {
	public static final String NAME = "RealtimeGetQuery";
	@Override
	public void prepare(ResponseBuilder rb) throws IOException {
	}

	@Override
	public void process(ResponseBuilder rb) throws IOException {
	}

	@Override
	public int distributedProcess(ResponseBuilder rb) throws IOException {
		if (rb.stage < ResponseBuilder.STAGE_GET_FIELDS)
			return ResponseBuilder.STAGE_GET_FIELDS;
		if (rb.stage == ResponseBuilder.STAGE_GET_FIELDS) {
			return createSubRequests(rb);
		}
		return ResponseBuilder.STAGE_DONE;
	}

	public int createSubRequests(ResponseBuilder rb) throws IOException {
		SolrParams params = rb.req.getParams();
		CloudDescriptor cloudDescriptor = rb.req.getCore().getCoreDescriptor().getCloudDescriptor();
		ZkController zkController = rb.req.getCore().getCoreDescriptor().getCoreContainer().getZkController();
		String collection = cloudDescriptor.getCollectionName();

		for (Slice slice : zkController.getClusterState().getActiveSlices(cloudDescriptor.getCollectionName())) {
			String shard = slice.getName();
			ShardRequest sreq = new ShardRequest();

			sreq.purpose = 1;
			sreq.shards = sliceToShards(rb, collection, shard);
			sreq.actualShards = sreq.shards;

			SolrQuery squery = new SolrQuery();
			squery.set(ShardParams.SHARDS_QT, "/select");
			String fields = params.get(CommonParams.FL);
			if (fields != null) {
				squery.set(CommonParams.FL, fields);
			}
			squery.set("distrib", false);
			squery.setQuery(params.get(CommonParams.Q));
			sreq.params = squery;
			sreq.params.set("distrib", false);

			rb.addRequest(this, sreq);
		}
		return ResponseBuilder.STAGE_DONE;
	}

	private String[] sliceToShards(ResponseBuilder rb, String collection, String slice) {
		String lookup = collection + '_' + slice; // seems either form may be filled in rb.slices?
		for (int i = 0; i < rb.slices.length; i++) {
			if (lookup.equals(rb.slices[i]) || slice.equals(rb.slices[i])) {
				return new String[] { rb.shards[i] };
			}
		}

		throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Can't find shard '" + lookup + "'");
	}

	@Override
	public String getDescription() {
		return NAME;
	}
}

 

 例子:

    solrconfig:    

<config>

  <searchComponent name="realtimeGetQueryComponent" class="handler.component.s4product.RealtimeGetQueryComponent" />
   <requestHandler name="/rquery" class="solr.SearchHandler">
    <lst name="defaults">
      <str name="echoParams">explicit</str>
      <int name="rows">10</int>
      <str name="df">text</str>
    </lst>
    <arr name="last-components">
      <str>realtimeGetQueryComponent</str>
    </arr>
  </requestHandler>

</config>

 

 查询代码:

public class TestRQuery extends BasicTestCase {

	public void testRquery() throws Exception {
		SolrQuery solrQuery = new SolrQuery();
		StringBuilder idStr = new StringBuilder("is_valid:1 AND {!terms f=id}");
		idStr.append(
				"000000006492817901649281d0380004,9992654455288a2b0155438eb12f00da,9992654461dbc2ad0161df5d152300fe,9992654355288a2b01553eaee9e400cb,9993236363d8ecba01641bf7d08c095f");

		solrQuery.setQuery(idStr.toString());
		solrQuery.setRows(5);

		solrQuery.setRequestHandler("/rquery");

		System.out.println("start query");
		QueryResponse response = client.mergeQuery("search4product", solrQuery, false);
		for (SolrDocument doc : response.getResults()) {
			System.out.println(doc.getFieldValue("id"));
		}
	}
}

 

分享到:
评论

相关推荐

    solr压缩包

    4. **查询与筛选**:Solr提供丰富的查询语法,包括标准查询解析器(Standard Query Parser)、Lucene查询语法(Lucene Query Parser)、布尔操作符、范围查询、高亮显示、分组和 faceting 等。这些功能使用户能精确...

    wpsolr配置文件

    - **Merge Policy**: 确定何时和如何合并索引段,影响性能和存储。 - **Index Writer**: 控制索引写入行为,如缓冲大小、刷新间隔等。 ### 3. WPSOLR与WordPress的集成 WPSOLR插件通过API与WordPress交互,将...

    《lucene搜索引擎开发权威经典》一书的光盘源代码

    这本书的源代码不仅帮助读者理解Lucene的工作原理,还提供了实际操作的机会,以便于开发者能够熟练掌握搜索引擎的开发。 首先,我们要了解Lucene的核心概念。Lucene主要由以下几个部分组成: 1. 文档(Document)...

    lucene源码分析1111

    作为开源项目,其源码提供了丰富的学习资源,帮助开发者深入了解搜索引擎的工作原理和实现细节。在这个主题中,我们将对Lucene的源码进行深入的分析。 1. **Lucene的基本结构** - Lucene的核心组件包括索引(Index...

    Lucene 常用功能介绍视频详解

    **Lucene 常用功能介绍** Lucene 是一个高性能、全文检索库,由Apache软件基金会开发并维护。...结合课程文档和视频讲解,可以更深入地理解Lucene的工作原理和使用技巧,从而更好地利用它来解决实际的搜索问题。

    lucene基础资料

    对于大规模数据,可以利用Solr或Elasticsearch这样的分布式搜索平台,它们基于Lucene构建,提供了集群部署、负载均衡和自动故障恢复等功能。 ### 八、优化与合并段 为了提高搜索性能,Lucene会定期进行段合并...

    lucene-5.2.1

    Lucene是一个库,而非完整的搜索引擎产品,因此通常与其他技术结合使用,如Solr(提供REST接口和集群功能)或Elasticsearch(分布式搜索引擎)。5.2.1版本可以轻松地与这些框架集成,实现更复杂的应用场景。 9. **...

    lucene

    1. 近实时搜索(Near Real-Time Search):Lucene引入了Segment和Merge策略,能够在添加新文档后几乎立即反映到搜索结果中。 2. 分布式搜索(Distributed Search):通过Solr或Elasticsearch等工具,Lucene可以扩展...

    lucene索引

    - **合并段(Merge Segments)**:当有多个段时,Lucene会定期进行段合并,以减少段的数量,优化磁盘空间利用率。 3. 全文搜索 - **查询分析(Query Analysis)**:用户输入的查询也会经过分析,确保与索引中的...

    lucene源码---官网最新下载

    - **Query**: Lucene 支持多种查询类型,如 TermQuery(匹配单个词项)、BooleanQuery(组合多个查询)、PhraseQuery(匹配短语)等。查询对象表示了用户想要查找的信息模式。 - **Scoring**: Lucene 使用 TF-IDF...

    lucene学习-02

    7. **优化与备份**:索引优化(Merge)可以合并多个Segment,提高搜索性能。备份索引则确保数据安全。 【标签】:“lucene学习” 学习Lucene的同时,你可能会遇到以下标签相关的知识点: - **倒排索引**:Lucene...

    lucene api

    9. **多线程与分布式搜索**:Lucene API设计允许在多线程环境中高效运行,并通过Solr或Elasticsearch等扩展实现分布式搜索,以处理大规模数据。 10. **内存与磁盘索引**:Lucene既支持内存中的临时索引,也支持持久...

    lucene source code

    下面,我们将深入探讨Lucene的核心概念、架构以及关键组件,通过分析其源码,来理解这个强大工具的工作原理。 1. **核心概念** - **倒排索引(Inverted Index)**:Lucene的主要数据结构,它将文档中的词项与文档...

    lucene高级搜索进阶项目_02

    通过Solr或Elasticsearch等工具,可以将一个大索引拆分成多个小索引(分片),然后在多台机器上并行处理,提高搜索性能和可扩展性。 八、优化与性能调优 为了保持最佳性能,需要定期对Lucene索引进行优化。优化过程...

    LUCENE索引搜索数据库技术汇总

    - **合并段(Merge Segments)**: `IndexWriter`会在索引中创建多个段,定期合并小段可以提高搜索效率。 - **缓存(Cache)**: 使用`BitSet`缓存和`FilterCache`可以加快查询速度,特别是对于经常查询的过滤条件。...

    全文检索Lucene 全文检索Lucene

    - 分布式搜索:通过Solr或Elasticsearch在集群环境中扩展Lucene的能力。 - 高级查询构造:布尔查询、短语查询、范围查询、模糊查询等。 - 集成到Web应用:如Spring Boot中使用Lucene。 以上内容只是Lucene全文...

    Lucene建立索引

    **标题:“Lucene建立索引”** **描述分析:** ...学习并实践“Lucene建立索引”,不仅可以深入了解倒排索引的工作原理,还能提升处理大规模文本数据的能力,为后续的全文搜索和数据分析打下坚实基础。

    lucene项目

    4. 集群和分布式搜索:如果数据量庞大,可能需要使用Solr或Elasticsearch这样的分布式搜索引擎,它们基于Lucene但提供了更高级的功能。 5. 性能调优:优化搜索速度、索引构建速度以及内存使用。 总的来说,Lucene是...

    hibernate5.5.4

    例如,使用Session对象的save()或persist()方法可实现对象的持久化,而get()和load()用于查询,update()和merge()用于更新,delete()则用于删除。 4. **级联操作**: 在关联映射中,Hibernate允许级联操作,这意味着...

    lucene 例子

    5. **优化(Optimization)**:索引可能会随着不断添加和删除文档而变得碎片化,因此定期进行优化(Merge索引)是必要的,以提高搜索效率。 6. **更新和删除(Updating & Deleting)**:Lucene支持对已索引文档进行...

Global site tag (gtag.js) - Google Analytics