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

先看下,整体的拓扑图:

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

  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,这样以来,才能真正达到高效批量的索引构建

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

  1. 如何提高Lucene构建索引的速度

    如何提高Lucene构建索引的速度 hans(汉斯) 2013-01-27 10:12 对于Lucene>=2.3:IndexWriter可以自行根据内存使用来释放缓存.调用writer.set ...

  2. 【Lucene实验1】构建索引

    一.实验名称:构建索引 二.实验日期:2013/9/21 三.实验目的: 1)        能理解Lucene中的Document-Field结构的数据建模过程: 2)        能编针对特定数 ...

  3. 构建NCBI本地BLAST数据库 (NR NT等) | blastx/diamond使用方法 | blast构建索引 | makeblastdb

    参考链接: FTP README 如何下载 NCBI NR NT数据库? 下载blast:ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+ 先了解 ...

  4. OpenACC 《大规模并行处理器编程实战》教材讲解

    ▶ <大规模并行处理器编程实战>第15章,关于OpenACC 的部分,散点 ● OpenACC 中,主机存储器和设备存储器是分开处理的,程序员只要制定要传输的存储器对象即可,编译器会自动生 ...

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

    上一篇博文中已经对全文检索有了一定的了解,这篇文章主要来总结一下全文检索的第一步:构建索引.其实上一篇博文中的示例程序已经对构建索引写了一段程序了,而且那个程序还是挺完善的.不过从知识点的完整性来考虑 ...

  6. spark ml pipeline构建机器学习任务

    一.关于spark ml pipeline与机器学习一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的流 ...

  7. Jenkins分布式构建与并行构建

    Jenkins分布式构建与并行构建 jenkins的架构 Jenkins采用的是"master+agent(slave)"架构.Jenkins master负责提供界面.处理HTT ...

  8. 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署

    达梦数据库大规模并行集群MPP 2节点安装部署   1.环境准备   os 数据库版本 ip mpp角色 centos7.x86 DM8 192.168.30.100 mpp1 centos7.x86 ...

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

    Spark中常见的三种分类模型:线性模型.决策树和朴素贝叶斯模型. 线性模型,简单而且相对容易扩展到非常大的数据集:线性模型又可以分成:1.逻辑回归:2.线性支持向量机 决策树是一个强大的非线性技术, ...

随机推荐

  1. 压缩图片大小(Java源码)

    /** * * 直接指定压缩后的宽高: * @param oldFile * 要进行压缩的文件 * @param width * 压缩后的宽度 * @param height * 压缩后的高度 * @ ...

  2. 后缀自动机求字典序第k小的串——p3975

    又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机 后缀树用来划分endpos集合,并且维护后缀之间的关系,此时每个结点代表的是一些后缀相同且长度连续的子串 自 ...

  3. 二分图hall定理应用+二分+双指针——cf981F(好题)

    /* 二分答案,判mid是否合法 如何判断:如果是在直线上,那么遍历匹配即可 现在在环上,即既可以向前匹配也可以向后匹配,那么将环拆开,扩展成三倍 显然a和b的匹配边是不可能交叉的,因为交叉必定没有不 ...

  4. 牛客多校第八场 B Beauty Values 水题

    题意: 给定一个序列,问你子区间中不同数字数量,在所有子区间中之和为多少. 题解: 统计每个数字在多少个区间中出现即可.对于每个数字,直接枚举左右端点. 注意去重,因此要记录每个数字上一次出现在哪里, ...

  5. detours3.0文档翻译

    拦截二进制函数 Detours库可以在运行过程中动态拦截函数调用.detours将目标函数前几个指令替换为一个无条件跳转,跳转到用户定义的detour函数.被拦截的函数保存在trampoline函数中 ...

  6. 关于group by的用法

    重新回顾并理解group by. 首先设计一张表,表名为test 然后执行以下SQL语句: select name from test group by name 获得执行结果: 可是为了能够更好的理 ...

  7. jQuery 表单域选中选择器

    复选框.单选按钮.下拉列表 /***********************************************/ <script type="text/javascrip ...

  8. spark入门到精通(后续开始学习)

    早几年国内外研究者和业界比较关注的是在 Hadoop 平台上的并行化算法设计.然而, HadoopMapReduce 平台由于网络和磁盘读写开销大,难以高效地实现需要大量迭代计算的机器学习并行化算法. ...

  9. Intellij IDEA 撸码最头大的问题。。

    想栈长我当初从 Eclipse 转用 IDEA 真是纠结,放弃然后尝试了N次,不过现在已经算是转型成功了,可以完全脱离 Eclipse 撸码了,虽然说我现在真的撸得非常少了.. 说到 IDEA 的痛点 ...

  10. Spring Cloud Feign设计原理

    什么是Feign? Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直 ...