如何使用Spark大规模并行构建索引

使用Spark构建索引非常简单,因为spark提供了更高级的抽象rdd分布式弹性数据集,相比以前的使用Hadoop的MapReduce来构建大规模索引,Spark具有更灵活的api操作,性能更高,语法更简洁等一系列优点。

先看下,整体的拓扑图:

然后,再来看下,使用scala写的spark程序:

Java代码  

  1. package com.easy.build.index
  2. import java.util
  3. import org.apache.solr.client.solrj.beans.Field
  4. import org.apache.solr.client.solrj.impl.HttpSolrClient
  5. import org.apache.spark.rdd.RDD
  6. import org.apache.spark.{SparkConf, SparkContext}
  7. import scala.annotation.meta.field
  8. /**
  9. * Created by qindongliang on 2016/1/21.
  10. */
  11. //注册model,时间类型可以为字符串,只要后台索引配置为Long即可,注解映射形式如下
  12. case class Record(
  13. @(Field@field)("rowkey")     rowkey:String,
  14. @(Field@field)("title")  title:String,
  15. @(Field@field)("content") content:String,
  16. @(Field@field)("isdel") isdel:String,
  17. @(Field@field)("t1") t1:String,
  18. @(Field@field)("t2")t2:String,
  19. @(Field@field)("t3")t3:String,
  20. @(Field@field)("dtime") dtime:String
  21. )
  22. /***
  23. * Spark构建索引==>Solr
  24. */
  25. object SparkIndex {
  26. //solr客户端
  27. val client=new  HttpSolrClient("http://192.168.1.188:8984/solr/monitor");
  28. //批提交的条数
  29. val batchCount=10000;
  30. def main2(args: Array[String]) {
  31. val d1=new Record("row1","title","content","1","01","57","58","3");
  32. val d2=new Record("row2","title","content","1","01","57","58","45");
  33. val d3=new Record("row3","title","content","1","01","57","58",null);
  34. client.addBean(d1);
  35. client.addBean(d2)
  36. client.addBean(d3)
  37. client.commit();
  38. println("提交成功!")
  39. }
  40. /***
  41. * 迭代分区数据(一个迭代器集合),然后进行处理
  42. * @param lines 处理每个分区的数据
  43. */
  44. def  indexPartition(lines:scala.Iterator[String] ): Unit ={
  45. //初始化集合,分区迭代开始前,可以初始化一些内容,如数据库连接等
  46. val datas = new util.ArrayList[Record]()
  47. //迭代处理每条数据,符合条件会提交数据
  48. lines.foreach(line=>indexLineToModel(line,datas))
  49. //操作分区结束后,可以关闭一些资源,或者做一些操作,最后一次提交数据
  50. commitSolr(datas,true);
  51. }
  52. /***
  53. *  提交索引数据到solr中
  54. *
  55. * @param datas 索引数据
  56. * @param isEnd 是否为最后一次提交
  57. */
  58. def commitSolr(datas:util.ArrayList[Record],isEnd:Boolean): Unit ={
  59. //仅仅最后一次提交和集合长度等于批处理的数量时才提交
  60. if ((datas.size()>0&&isEnd)||datas.size()==batchCount) {
  61. client.addBeans(datas);
  62. client.commit(); //提交数据
  63. datas.clear();//清空集合,便于重用
  64. }
  65. }
  66. /***
  67. * 得到分区的数据具体每一行,并映射
  68. * 到Model,进行后续索引处理
  69. *
  70. * @param line 每行具体数据
  71. * @param datas 添加数据的集合,用于批量提交索引
  72. */
  73. def indexLineToModel(line:String,datas:util.ArrayList[Record]): Unit ={
  74. //数组数据清洗转换
  75. val fields=line.split("\1",-1).map(field =>etl_field(field))
  76. //将清洗完后的数组映射成Tuple类型
  77. val tuple=buildTuble(fields)
  78. //将Tuple转换成Bean类型
  79. val recoder=Record.tupled(tuple)
  80. //将实体类添加至集合,方便批处理提交
  81. datas.add(recoder);
  82. //提交索引到solr
  83. commitSolr(datas,false);
  84. }
  85. /***
  86. * 将数组映射成Tuple集合,方便与Bean绑定
  87. * @param array field集合数组
  88. * @return tuple集合
  89. */
  90. def buildTuble(array: Array[String]):(String, String, String, String, String, String, String, String)={
  91. array match {
  92. case Array(s1, s2, s3, s4, s5, s6, s7, s8) => (s1, s2, s3, s4, s5, s6, s7,s8)
  93. }
  94. }
  95. /***
  96. *  对field进行加工处理
  97. * 空值替换为null,这样索引里面就不会索引这个字段
  98. * ,正常值就还是原样返回
  99. *
  100. * @param field 用来走特定规则的数据
  101. * @return 映射完的数据
  102. */
  103. def etl_field(field:String):String={
  104. field match {
  105. case "" => null
  106. case _ => field
  107. }
  108. }
  109. /***
  110. * 根据条件清空某一类索引数据
  111. * @param query 删除的查询条件
  112. */
  113. def deleteSolrByQuery(query:String): Unit ={
  114. client.deleteByQuery(query);
  115. client.commit()
  116. println("删除成功!")
  117. }
  118. def main(args: Array[String]) {
  119. //根据条件删除一些数据
  120. deleteSolrByQuery("t1:03")
  121. //远程提交时,需要提交打包后的jar
  122. val jarPath = "target\\spark-build-index-1.0-SNAPSHOT.jar";
  123. //远程提交时,伪装成相关的hadoop用户,否则,可能没有权限访问hdfs系统
  124. System.setProperty("user.name", "webmaster");
  125. //初始化SparkConf
  126. val conf = new SparkConf().setMaster("spark://192.168.1.187:7077").setAppName("build index ");
  127. //上传运行时依赖的jar包
  128. val seq = Seq(jarPath) :+ "D:\\tmp\\lib\\noggit-0.6.jar" :+ "D:\\tmp\\lib\\httpclient-4.3.1.jar" :+ "D:\\tmp\\lib\\httpcore-4.3.jar" :+ "D:\\tmp\\lib\\solr-solrj-5.1.0.jar" :+ "D:\\tmp\\lib\\httpmime-4.3.1.jar"
  129. conf.setJars(seq)
  130. //初始化SparkContext上下文
  131. val sc = new SparkContext(conf);
  132. //此目录下所有的数据,将会被构建索引,格式一定是约定好的
  133. val rdd = sc.textFile("hdfs://192.168.1.187:9000/user/monitor/gs/");
  134. //通过rdd构建索引
  135. indexRDD(rdd);
  136. //关闭索引资源
  137. client.close();
  138. //关闭SparkContext上下文
  139. sc.stop();
  140. }
  141. /***
  142. * 处理rdd数据,构建索引
  143. * @param rdd
  144. */
  145. def indexRDD(rdd:RDD[String]): Unit ={
  146. //遍历分区,构建索引
  147. rdd.foreachPartition(line=>indexPartition(line));
  148. }
  149. }

ok,至此,我们的建索引程序就写完了,本例子中用的是远程提交模式,实际上它也可以支持spark on yarn (cluster 或者 client )  模式,不过此时需要注意的是,不需要显式指定setMaster的值,而由提交任务时,通过--master来指定运行模式,另外,依赖的相关jar包,也需要通过--jars参数来提交到集群里面,否则的话,运行时会报异常,最后看下本例子里面的solr是单机模式的,所以使用spark建索引提速并没有达到最大值,真正能发挥最大威力的是,多台search集群正如我画的架构图里面,每台机器是一个shard,这就是solrcloud的模式,或者在elasticsearch里面的集群shard,这样以来,才能真正达到高效批量的索引构建

时间: 2024-10-13 07:31:31

如何使用Spark大规模并行构建索引的相关文章

三十三天 大规模站点构建、lvs原理、lvs调度及nat模型实现、lvs dr模型及lxc虚拟化

1.大规模站点构建框架.        http:状态               keep-alive:长连接               cookie:session          cluster:集群                 构建高可扩展性系统的重要原则:在系统内部尽量避免串行化和交互                 HA:High Availability                 LB:Load Balancing                 session复制 

MongoDB数据量较大时如何构建索引--减少业务最少影响

在数据量较大或请求量较大,直接建立索引对性能有显著影响时,可以利用复制集(数据量较大时一般为线上环境,使用复制集为必然选择或者使用分片.)中部分机器宕机不影响复制集工作的特性,继而建立索引. 备注:添加索引的表使用WT引擎,数据量有1.5亿左右. 1. 副本集配置参数 节点1: $ more shard1.conf dbpath=/data/users/mgousr01/mongodb/dbdata/shard1_1 logpath=/data/users/mgousr01/mongodb/lo

【Lucene实验1】构建索引

一.实验名称:构建索引 二.实验日期:2013/9/21 三.实验目的: 1)        能理解Lucene中的Document-Field结构的数据建模过程: 2)        能编针对特定数据生成索引文件. 四.实验用的仪器和材料: MyEclipse 10,JDK 五.实验的步骤和方法: 题目一:在指定目录生成表示3本书的索引,要求建立3个document分别存放书名数据.把生成的索引文件截好图(复合索引与一般索引各生成一次) 图1:一般索引的截图 图2:复合索引的截图 题目二:修改

Oracle使用并行建索引需要注意的问题

建索引时,我们为了建索引快,会加上并行,加上并行之后,此列索引就会是并行了.访问有并行度的索引时,CBO可能可能会考虑并行执行,这可能会引发一些问题,如在服务器资源紧张的时候用并行会引起更加严重的争用.当使用并行后,需要把并行度改回来. SQL> drop table test purge; SQL> create table test as select * from dba_objects; SQL> create index ind_t_object_id on test(obje

【Lucene】Apache Lucene全文检索引擎架构之构建索引

上一篇博文中已经对全文检索有了一定的了解,这篇文章主要来总结一下全文检索的第一步:构建索引.其实上一篇博文中的示例程序已经对构建索引写了一段程序了,而且那个程序还是挺完善的.不过从知识点的完整性来考虑,我想从Lucene的添加文档.删除文档.修改文档以及文档域加权四个部分来展开对构建索引的总结,也便于我后期的查看.会重点分析一下删除文档(因为有两中方式)和文档域加权这(实际中会用到比较多)两个部分. 1. 准备阶段 新建一个maven工程,pom.xml如下: <project xmlns=&quo

大规模代码构建技术实践

原文地址 什么是持续集成? 大师Martin Fowler认为持续集成是一种软件开发实践,在实践中团队开发成员会频繁的进行任务的集成,通常每个成员每天都会集成一次,也就意味着每天可能会发生多次集成.每次集成都通过自动化的构建来验证,从而尽快地发现集成错误,快速进行修复. 如上图所示,一个完整的持续集成环节包括:首先项目经理创建一个项目,将项目成员添加到项目中:开发人员在项目中拉取开发分支进行代码开发,在开发过程中,开发人员将代码提交到代码仓库(如SN.GIT):后端的持续集成任务会定时扫描代码仓

Spark学习笔记——构建分类模型

Spark中常见的三种分类模型:线性模型.决策树和朴素贝叶斯模型. 线性模型,简单而且相对容易扩展到非常大的数据集:线性模型又可以分成:1.逻辑回归:2.线性支持向量机 决策树是一个强大的非线性技术,训练过程计算量大并且较难扩展(幸运的是,MLlib会替我们考虑扩展性的问题),但是在很多情况下性能很好: 朴素贝叶斯模型简单.易训练,并且具有高效和并行的优点(实际中,模型训练只需要遍历所有数据集一次).当采用合适的特征工程,这些模型在很多应用中都能达到不错的性能.而且,朴素贝叶斯模型可以作为一个很

Oracle使用并行建索引须要注意的问题

建索引时.我们为了建索引快.会加上并行,加上并行之后.此列索引就会是并行了. 訪问有并行度的索引时,CBO可能可能会考虑并行运行.这可能会引发一些问题,如在server资源紧张的时候用并行会引起更加严重的争用.当使用并行后,须要把并行度改回来. SQL> drop table test purge; SQL> create table test as select * from dba_objects; SQL> create index ind_t_object_id on test(

spark集群构建

一.spark启动有standalong.yarn.cluster,具体的他们之间的区别这里不在赘述,请参考官网.本文采用的是standalong模式进行搭建及将接使用. 1.首先去官网下载需要的spark版本: http://spark.apache.org/downloads.html 本例使用的是spark-2.2.0-bin-hadoop2.7,hadoop使用的是2.7版本,spark是需要scala环境的,可以下载编译好的spark,这样就不需要自己在安装了. 同时使用了hive仓库