mapreduce创建solrcloud索引

原理图(摘自网络):


1、datasource
hdfs或者 TableMapReduceUtil来scan数据(不建议HFileInputFomat方式,易丢失数据)
2、map
setup()方法中通过zkHost创建CloudSolrServer,目的是通过docId,来计算这个docId应该router到哪个shardId,关键代码为:
// copy from org.apache.solr.common.cloud.HashBasedRouter
 private int sliceHash(String id) {
  return Hash.murmurhash3_x86_32(id, 0, id.length(), 0);
 }

 // copy from org.apache.solr.common.cloud.HashBasedRouter
 private Slice hashToSlice(int hash, DocCollection collection) {
  for (Slice slice : collection.getSlices()) {
   Range range = slice.getRange();
   if (range != null && range.includes(hash))
    return slice;
  }
  throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No slice servicing hash code " + Integer.toHexString(hash) + " in " + collection);
 }
map()方法,输入(ImmutableBytesWritable , Result )输出(Text, Result)即将 ImmutableBytesWritable计算shardId(比如:shard1,shard2...)
关键代码:
@Override
 protected void map(ImmutableBytesWritable key, Result columns, Context context) throws IOException, InterruptedException {
  String id = Bytes.toString(columns.getRow());
  int sliceHash = sliceHash(id);
  Slice slice = hashToSlice(sliceHash, cstate.getCollection(defau_collection));
  String shardid = slice.getName();// shard1,shard2 ...
  context.write(new Text(shardid), columns);
 }
3、 Partitioner
通过shardId,随机发散到多个reduce,即一个shard数据,多个reduce来建索引,更高效
关键代码:
/**
* numPartitions为配置一个shard对应多少个reduce
*/
@Override
 public int getPartition(Text key, Result result, int numPartitions) {
  initReducerTimes();
  int shardId = Integer.valueOf(key.toString().substring(5))-1;// 十位
  int part2 = (int) Math.round(Math.random() * (reducerTimes-1));// 个位
  return reducerTimes * shardId + part2;
 }
4、reduce
setup()方法中获取partition,计算shardid, 通过zkHost获取cloudServer,最后ConcurrentUpdateSolrServer,这个solrServer就是针对某个shard建索引的server。
关键代码:
@Override
 protected void setup(Context context) throws IOException, InterruptedException {
 
  Configuration conf = context.getConfiguration();
  zk_host = conf.get(IndexingConfig.ZK_HOST, zk_host);
  defau_collection = conf.get(IndexingConfig.DEFAULT_COLLECTION, defau_collection);
// max_segments = conf.getInt(IndexingConfig.MAX_SEGMENTS, max_segments);
  document_buffer_size = conf.getInt(IndexingConfig.DOCUMENT_BUFFER_SIZE, document_buffer_size);
  solr_thread_count = conf.getInt(IndexingConfig.SOLR_THREAD_COUNT, solr_thread_count);
  id_field = conf.get(IndexingConfig.ID_FIELD, id_field);
  logger.info("初始化server...");
  try {
   cloudServer = new CloudSolrServer(zk_host);
   cloudServer.setDefaultCollection(defau_collection);
   SolrPingResponse response = cloudServer.ping();
   logger.info("status:" + response.getStatus());
   if (response.getStatus() != 0) {
    logger.error("服务有问题");
    throw new RuntimeException("服务响应不正常");
   }
   logger.info(cloudServer.ping().toString());
  } catch (Exception e) {
   logger.error("", e);
   throw new RuntimeException("配置好solr服务");
  }
  logger.info("初始化结束");
  // 取得partition
  partition = conf.get("mapred.task.partition");// 0~79
  // 根据partition来启动不同的solrServer
  shardid = getShardId(partition);
  ZkStateReader reader = cloudServer.getZkStateReader();
  try {
   String url = reader.getLeaderUrl(defau_collection, "shard" + shardid, 3000);
   //solrServer = new ConcurrentUpdateSolrServer(url, document_buffer_size, solr_thread_count);
    solrServer = new HttpSolrServer(url);
   System.out.println("###url: " + url);
  } catch (InterruptedException e) {
   e.printStackTrace();
  } catch (KeeperException e) {
   e.printStackTrace();
  }
 
  initTransformers();
  initFieldBoost();
  // transformers init();
  for (TransformerMR t :transformers) {
   t.init(conf);
  }
 }

总结:重点在于直接将doc router到正确的shard,而不经过solrCloud的内部router(实际上是copy其router源码);并且每个shard对应多个reduce,随机发散,增加一层并发。

注意:

ConcurrentUpdateSolrServer使用了  final BlockingQueue<UpdateRequest> queue;
在高并发过程中(mapreduce建索引),会造成阻塞问题,丢失数据。
原因可能有2个
1、 queue满了,写不进去,请求连接中断
2、 queue还有数据未写入硬盘,直接执行optimize()操作
换成HttpSolrServer就没有问题了,solrServer = new HttpSolrServer(url); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值