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

然后,再来看下,使用scala写的spark程序:
- package com.easy.build.index
- import java.util
- import org.apache.solr.client.solrj.beans.Field
- import org.apache.solr.client.solrj.impl.HttpSolrClient
- import org.apache.spark.rdd.RDD
- import org.apache.spark.{SparkConf, SparkContext}
- import scala.annotation.meta.field
- /**
- * Created by qindongliang on 2016/1/21.
- */
- //注册model,时间类型可以为字符串,只要后台索引配置为Long即可,注解映射形式如下
- case class Record(
- @(Field@field)("rowkey") rowkey:String,
- @(Field@field)("title") title:String,
- @(Field@field)("content") content:String,
- @(Field@field)("isdel") isdel:String,
- @(Field@field)("t1") t1:String,
- @(Field@field)("t2")t2:String,
- @(Field@field)("t3")t3:String,
- @(Field@field)("dtime") dtime:String
- )
- /***
- * Spark构建索引==>Solr
- */
- object SparkIndex {
- //solr客户端
- val client=new HttpSolrClient("http://192.168.1.188:8984/solr/monitor");
- //批提交的条数
- val batchCount=10000;
- def main2(args: Array[String]) {
- val d1=new Record("row1","title","content","1","01","57","58","3");
- val d2=new Record("row2","title","content","1","01","57","58","45");
- val d3=new Record("row3","title","content","1","01","57","58",null);
- client.addBean(d1);
- client.addBean(d2)
- client.addBean(d3)
- client.commit();
- println("提交成功!")
- }
- /***
- * 迭代分区数据(一个迭代器集合),然后进行处理
- * @param lines 处理每个分区的数据
- */
- def indexPartition(lines:scala.Iterator[String] ): Unit ={
- //初始化集合,分区迭代开始前,可以初始化一些内容,如数据库连接等
- val datas = new util.ArrayList[Record]()
- //迭代处理每条数据,符合条件会提交数据
- lines.foreach(line=>indexLineToModel(line,datas))
- //操作分区结束后,可以关闭一些资源,或者做一些操作,最后一次提交数据
- commitSolr(datas,true);
- }
- /***
- * 提交索引数据到solr中
- *
- * @param datas 索引数据
- * @param isEnd 是否为最后一次提交
- */
- def commitSolr(datas:util.ArrayList[Record],isEnd:Boolean): Unit ={
- //仅仅最后一次提交和集合长度等于批处理的数量时才提交
- if ((datas.size()>0&&isEnd)||datas.size()==batchCount) {
- client.addBeans(datas);
- client.commit(); //提交数据
- datas.clear();//清空集合,便于重用
- }
- }
- /***
- * 得到分区的数据具体每一行,并映射
- * 到Model,进行后续索引处理
- *
- * @param line 每行具体数据
- * @param datas 添加数据的集合,用于批量提交索引
- */
- def indexLineToModel(line:String,datas:util.ArrayList[Record]): Unit ={
- //数组数据清洗转换
- val fields=line.split("\1",-1).map(field =>etl_field(field))
- //将清洗完后的数组映射成Tuple类型
- val tuple=buildTuble(fields)
- //将Tuple转换成Bean类型
- val recoder=Record.tupled(tuple)
- //将实体类添加至集合,方便批处理提交
- datas.add(recoder);
- //提交索引到solr
- commitSolr(datas,false);
- }
- /***
- * 将数组映射成Tuple集合,方便与Bean绑定
- * @param array field集合数组
- * @return tuple集合
- */
- def buildTuble(array: Array[String]):(String, String, String, String, String, String, String, String)={
- array match {
- case Array(s1, s2, s3, s4, s5, s6, s7, s8) => (s1, s2, s3, s4, s5, s6, s7,s8)
- }
- }
- /***
- * 对field进行加工处理
- * 空值替换为null,这样索引里面就不会索引这个字段
- * ,正常值就还是原样返回
- *
- * @param field 用来走特定规则的数据
- * @return 映射完的数据
- */
- def etl_field(field:String):String={
- field match {
- case "" => null
- case _ => field
- }
- }
- /***
- * 根据条件清空某一类索引数据
- * @param query 删除的查询条件
- */
- def deleteSolrByQuery(query:String): Unit ={
- client.deleteByQuery(query);
- client.commit()
- println("删除成功!")
- }
- def main(args: Array[String]) {
- //根据条件删除一些数据
- deleteSolrByQuery("t1:03")
- //远程提交时,需要提交打包后的jar
- val jarPath = "target\\spark-build-index-1.0-SNAPSHOT.jar";
- //远程提交时,伪装成相关的hadoop用户,否则,可能没有权限访问hdfs系统
- System.setProperty("user.name", "webmaster");
- //初始化SparkConf
- val conf = new SparkConf().setMaster("spark://192.168.1.187:7077").setAppName("build index ");
- //上传运行时依赖的jar包
- 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"
- conf.setJars(seq)
- //初始化SparkContext上下文
- val sc = new SparkContext(conf);
- //此目录下所有的数据,将会被构建索引,格式一定是约定好的
- val rdd = sc.textFile("hdfs://192.168.1.187:9000/user/monitor/gs/");
- //通过rdd构建索引
- indexRDD(rdd);
- //关闭索引资源
- client.close();
- //关闭SparkContext上下文
- sc.stop();
- }
- /***
- * 处理rdd数据,构建索引
- * @param rdd
- */
- def indexRDD(rdd:RDD[String]): Unit ={
- //遍历分区,构建索引
- rdd.foreachPartition(line=>indexPartition(line));
- }
- }
ok,至此,我们的建索引程序就写完了,本例子中用的是远程提交模式,实际上它也可以支持spark on yarn (cluster 或者 client ) 模式,不过此时需要注意的是,不需要显式指定setMaster的值,而由提交任务时,通过--master来指定运行模式,另外,依赖的相关jar包,也需要通过--jars参数来提交到集群里面,否则的话,运行时会报异常,最后看下本例子里面的solr是单机模式的,所以使用spark建索引提速并没有达到最大值,真正能发挥最大威力的是,多台search集群正如我画的架构图里面,每台机器是一个shard,这就是solrcloud的模式,或者在elasticsearch里面的集群shard,这样以来,才能真正达到高效批量的索引构建
如何使用Spark大规模并行构建索引的更多相关文章
- 如何提高Lucene构建索引的速度
如何提高Lucene构建索引的速度 hans(汉斯) 2013-01-27 10:12 对于Lucene>=2.3:IndexWriter可以自行根据内存使用来释放缓存.调用writer.set ...
- 【Lucene实验1】构建索引
一.实验名称:构建索引 二.实验日期:2013/9/21 三.实验目的: 1) 能理解Lucene中的Document-Field结构的数据建模过程: 2) 能编针对特定数 ...
- 构建NCBI本地BLAST数据库 (NR NT等) | blastx/diamond使用方法 | blast构建索引 | makeblastdb
参考链接: FTP README 如何下载 NCBI NR NT数据库? 下载blast:ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+ 先了解 ...
- OpenACC 《大规模并行处理器编程实战》教材讲解
▶ <大规模并行处理器编程实战>第15章,关于OpenACC 的部分,散点 ● OpenACC 中,主机存储器和设备存储器是分开处理的,程序员只要制定要传输的存储器对象即可,编译器会自动生 ...
- 【Lucene】Apache Lucene全文检索引擎架构之构建索引2
上一篇博文中已经对全文检索有了一定的了解,这篇文章主要来总结一下全文检索的第一步:构建索引.其实上一篇博文中的示例程序已经对构建索引写了一段程序了,而且那个程序还是挺完善的.不过从知识点的完整性来考虑 ...
- spark ml pipeline构建机器学习任务
一.关于spark ml pipeline与机器学习一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的流 ...
- Jenkins分布式构建与并行构建
Jenkins分布式构建与并行构建 jenkins的架构 Jenkins采用的是"master+agent(slave)"架构.Jenkins master负责提供界面.处理HTT ...
- 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署
达梦数据库大规模并行集群MPP 2节点安装部署 1.环境准备 os 数据库版本 ip mpp角色 centos7.x86 DM8 192.168.30.100 mpp1 centos7.x86 ...
- Spark学习笔记——构建分类模型
Spark中常见的三种分类模型:线性模型.决策树和朴素贝叶斯模型. 线性模型,简单而且相对容易扩展到非常大的数据集:线性模型又可以分成:1.逻辑回归:2.线性支持向量机 决策树是一个强大的非线性技术, ...
随机推荐
- 压缩图片大小(Java源码)
/** * * 直接指定压缩后的宽高: * @param oldFile * 要进行压缩的文件 * @param width * 压缩后的宽度 * @param height * 压缩后的高度 * @ ...
- 后缀自动机求字典序第k小的串——p3975
又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机 后缀树用来划分endpos集合,并且维护后缀之间的关系,此时每个结点代表的是一些后缀相同且长度连续的子串 自 ...
- 二分图hall定理应用+二分+双指针——cf981F(好题)
/* 二分答案,判mid是否合法 如何判断:如果是在直线上,那么遍历匹配即可 现在在环上,即既可以向前匹配也可以向后匹配,那么将环拆开,扩展成三倍 显然a和b的匹配边是不可能交叉的,因为交叉必定没有不 ...
- 牛客多校第八场 B Beauty Values 水题
题意: 给定一个序列,问你子区间中不同数字数量,在所有子区间中之和为多少. 题解: 统计每个数字在多少个区间中出现即可.对于每个数字,直接枚举左右端点. 注意去重,因此要记录每个数字上一次出现在哪里, ...
- detours3.0文档翻译
拦截二进制函数 Detours库可以在运行过程中动态拦截函数调用.detours将目标函数前几个指令替换为一个无条件跳转,跳转到用户定义的detour函数.被拦截的函数保存在trampoline函数中 ...
- 关于group by的用法
重新回顾并理解group by. 首先设计一张表,表名为test 然后执行以下SQL语句: select name from test group by name 获得执行结果: 可是为了能够更好的理 ...
- jQuery 表单域选中选择器
复选框.单选按钮.下拉列表 /***********************************************/ <script type="text/javascrip ...
- spark入门到精通(后续开始学习)
早几年国内外研究者和业界比较关注的是在 Hadoop 平台上的并行化算法设计.然而, HadoopMapReduce 平台由于网络和磁盘读写开销大,难以高效地实现需要大量迭代计算的机器学习并行化算法. ...
- Intellij IDEA 撸码最头大的问题。。
想栈长我当初从 Eclipse 转用 IDEA 真是纠结,放弃然后尝试了N次,不过现在已经算是转型成功了,可以完全脱离 Eclipse 撸码了,虽然说我现在真的撸得非常少了.. 说到 IDEA 的痛点 ...
- Spring Cloud Feign设计原理
什么是Feign? Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直 ...