需求

将HDFS上的数据解析出来,然后通过hfile方式批量写入Hbase(需要多列写入)

写入数据的关键api:

  1. rdd.saveAsNewAPIHadoopFile(
  2. stagingFolder,
  3. classOf[ImmutableBytesWritable],
  4. classOf[KeyValue],
  5. classOf[HFileOutputFormat2],
  6. job.getConfiguration)

特殊地方:

1):

最初写hfile警告⚠️:

  1. Does it contain files in subdirectories that correspond to column family names

这个原因大概3种:

A:代码问题

B:数据源问题

C:setMapOutputKeyClass 和 saveAsNewAPIHadoopFile中的Class不一致

(我的是数据源问题)

2):

正常些put操作的时候,服务端自动帮助排序,因此在使用put操作的时候没有涉及到这样的错误:

  1. Added a key not lexically larger than previous

但是在写hfile的时候如果出现报错:

  1. Added a key not lexically larger than previous

这样的错误,一般会认为rowkey没有做好排序,然后傻fufu的去验证了一下,rowkey的确做了排序

真正原因:

spark写hfile时候是按照rowkey+列族+列名进行排序的,因此在写入数据的时候,要做到整体有序

(事情还没完)

3):

因为需要多列写入,最好的方式:要么反射来动态获取列名称和列值 、 要么通过datafame去获取(df.columns)

反射方式:

  1. val listData: RDD[(ImmutableBytesWritable, ListBuffer[KeyValue])] = rdd.map {
  2. line =>
  3. val rowkey = line.vintime
  4. val clazz = Class.forName(XXXXXXXXXXXXXXXX)
  5. val fields = clazz.getDeclaredFields
  6. var list = new ListBuffer[String]()
  7. var kvlist = new ListBuffer[KeyValue]()//
  8. if (fields != null && fields.size > ) {
  9. for (field <- fields) {
  10. field.setAccessible(true)
  11. val column = field.getName
  12. list.append(column)
  13. }
  14. }
  15.  
  16. val newList = list.sortWith(_ < _)
  17. val ik = new ImmutableBytesWritable(Bytes.toBytes(rowkey))
  18. for(column <- newList){
  19. val declaredField: Field = line.getClass.getDeclaredField(column)
  20. declaredField.setAccessible(true)
  21. val value = declaredField.get(line).toString
  22. val kv: KeyValue = new KeyValue(
  23. Bytes.toBytes(rowkey),
  24. Bytes.toBytes(columnFamily),
  25. Bytes.toBytes(column),
  26. Bytes.toBytes(value))
  27. kvlist.append(kv)
  28. }
  29. (ik, kvlist)
  30. }

datafame方式:

  1. val tmpData: RDD[(ImmutableBytesWritable, util.LinkedList[KeyValue])] = df.rdd.map(
  2. line =>{
  3. val rowkey = line.getAs[String]("vintime")
  4. val ik = new ImmutableBytesWritable(Bytes.toBytes(rowkey))
  5. var linkedList = new util.LinkedList[KeyValue]()
  6. for (column <- columns) {
  7. val kv: KeyValue = new KeyValue(
  8. Bytes.toBytes(rowkey),
  9. Bytes.toBytes(columnFamily),
  10. Bytes.toBytes(column),
  11. Bytes.toBytes(line.getAs[String](column)))
  12. linkedList.add(kv)
  13. }
  14. (ik, linkedList)
  15. })
  16.  
  17. val result: RDD[(ImmutableBytesWritable, KeyValue)] = tmpData.flatMapValues(
  18. s => {
  19. val values: Iterator[KeyValue] = JavaConverters.asScalaIteratorConverter(s.iterator()).asScala
  20. values
  21. }
  22. ).sortBy(x =>x._1 , true)

仔细观察可以发现,其实两者都做了排序操作,但是即便经过(1)步骤后仍然报错:

  1. Added a key not lexically larger than previous

那么在回想一下之前写hfile的要求:

rowkey+列族+列都要有序,那么如果出现数据的重复,也不算是有序的操作!

因为,做一下数据的去重:

  1. val key: RDD[(String, TransferTime)] = data.reduceByKey((x, y) => y)
  2. val unitData: RDD[TransferTime] = key.map(line => line._2)

果然,这样解决了:Added a key not lexically larger than previous这个异常

但是会报如下另一个异常:

  1. Kryo serialization failed: Buffer overflow

这个是因为在对一些类做kryo序列化时候,数据量的缓存大小超过了默认值,做一下调整即可

  1. sparkConf.set("spark.kryoserializer.buffer.max" , "256m")
  2. sparkConf.set("spark.kryoserializer.buffer" , "64m")

完整代码:

  1. /**
  2. * Created by angel
  3. */
  4. object WriteTransferTime extends WriteToHbase{
  5. /**
  6. * @param data 要插入的数据
  7. * @param tableName 表名
  8. **/
  9. override def bulkLoadData(data: RDD[Any], tableName: String , columnFamily:String): Unit = {
  10.  
  11. val bean: RDD[TransferTime] = data.map(line => line.asInstanceOf[TransferTime])
  12. val map: RDD[(String, TransferTime)] = bean.map(line => (line.vintime , line))
  13. val key: RDD[(String, TransferTime)] = map.reduceByKey((x, y) => y)
  14. val map1: RDD[TransferTime] = key.map(line => line._2)
  15. val by1: RDD[TransferTime] = map1.sortBy(f => f.vintime)
  16. val listData: RDD[(ImmutableBytesWritable, ListBuffer[KeyValue])] = by1.map {
  17. line =>
  18. val rowkey = line.vintime
  19. val clazz = Class.forName("com.dongfeng.code.Bean.message.TransferTime")
  20. val fields = clazz.getDeclaredFields
  21. var list = new ListBuffer[String]()
  22. var kvlist = new ListBuffer[KeyValue]()//
  23. if (fields != null && fields.size > 0) {
  24. for (field <- fields) {
  25. field.setAccessible(true)
  26. val column = field.getName
  27. list.append(column)
  28. }
  29. }
  30.  
  31. val newList = list.sortWith(_ < _)
  32. val ik = new ImmutableBytesWritable(Bytes.toBytes(rowkey))
  33. for(column <- newList){
  34. val declaredField: Field = line.getClass.getDeclaredField(column)
  35. declaredField.setAccessible(true)
  36. val value = declaredField.get(line).toString
  37. val kv: KeyValue = new KeyValue(
  38. Bytes.toBytes(rowkey),
  39. Bytes.toBytes(columnFamily),
  40. Bytes.toBytes(column),
  41. Bytes.toBytes(value))
  42. kvlist.append(kv)
  43. }
  44. (ik, kvlist)
  45. }
  46. val result: RDD[(ImmutableBytesWritable, KeyValue)] = listData.flatMapValues(
  47. s => {
  48. val values: Iterator[KeyValue] = s.iterator
  49. values
  50. }
  51. )
  52. val resultDD: RDD[(ImmutableBytesWritable, KeyValue)] = result.sortBy(x =>x._1 , true)
  53. WriteToHbaseDB.hfile_load(result , TableName.valueOf(tableName) , columnFamily)
  54. }
  55. }

WriteTransferTime

  1. def hfile_load(rdd:RDD[(ImmutableBytesWritable , KeyValue)] , tableName: TableName , columnFamily:String): Unit ={
  2. //声明表的信息
  3. var table: Table = null
  4. try{
  5. val startTime = System.currentTimeMillis()
  6. println(s"开始时间:-------->${startTime}")
  7. //生成的HFile的临时保存路径
  8. val stagingFolder = "hdfs://cdh1:9000/hfile/"+tableName+new Date().getTime//
  9.  
  10. table = connection.getTable(tableName)
  11. //如果表不存在,则创建表
  12. if(!admin.tableExists(tableName)){
  13. createTable(tableName , columnFamily)
  14. }
  15.  
  16. //开始导入
  17. val job = Job.getInstance(config)
  18. job.setJobName("DumpFile")
  19. job.setMapOutputKeyClass(classOf[ImmutableBytesWritable])
  20. job.setMapOutputValueClass(classOf[KeyValue])
  21.  
  22. rdd.sortBy(x => x._1, true).saveAsNewAPIHadoopFile(
  23. stagingFolder,
  24. classOf[ImmutableBytesWritable],
  25. classOf[KeyValue],
  26. classOf[HFileOutputFormat2],
  27. job.getConfiguration)
  28.  
  29. val load = new LoadIncrementalHFiles(config)
  30. val regionLocator = connection.getRegionLocator(tableName)
  31. HFileOutputFormat2.configureIncrementalLoad(job, table, regionLocator)
  32. load.doBulkLoad(new Path(stagingFolder), table.asInstanceOf[HTable])
  33. // load.doBulkLoad(new Path(stagingFolder) , connection.getAdmin , table , regionLocator)
  34.  
  35. val endTime = System.currentTimeMillis()
  36. println(s"结束时间:-------->${endTime}")
  37. println(s"花费的时间:----------------->${(endTime - startTime)}ms")
  38. }catch{
  39. case e:IOException =>
  40. e.printStackTrace()
  41. }finally {
  42. if (table != null) {
  43. try {
  44. // 关闭HTable对象 table.close();
  45. } catch {
  46. case e: IOException =>
  47. e.printStackTrace();
  48. }
  49. }
  50. if (connection != null) {
  51. try { //关闭hbase连接.
  52. connection.close();
  53. } catch {
  54. case e: IOException =>
  55. e.printStackTrace();
  56. }
  57. }
  58. }
  59. }
  60. }

落地部分

spark的bulkload报错及解决的更多相关文章

  1. Spark遇到的报错和坑

    1. Java版本不一致,导致启动报错. # 解决方法: 在启动脚本最前边添加系统参数,指定Java版本 export JAVA_HOME=/usr/java/jdk1..0_181-amd64/jr ...

  2. Spark程序编译报错error: object apache is not a member of package org

    Spark程序编译报错: [INFO] Compiling 2 source files to E:\Develop\IDEAWorkspace\spark\target\classes at 156 ...

  3. Springboot数据库连接池报错的解决办法

    Springboot数据库连接池报错的解决办法 这个异常通常在Linux服务器上会发生,原因是Linux系统会主动断开一个长时间没有通信的连接 那么我们的问题就是:数据库连接池长时间处于间歇状态,导致 ...

  4. window7下安装第三方包报错及解决

    window7 64位下安装第三方包,,比如安装yaml的exe执行文件,会 报错及解决:python version 2.7(3.4) required,which was not found in ...

  5. pom.xml里有红叉报错的解决办法

    pom.xml里有红叉报错的解决办法一: 1.把鼠标点在报的错上发现pom.xml报如下错误: Multiple annotations found at this line: - Failure t ...

  6. eclipes的Spring注解SequenceGenerator(name="sequenceGenerator")报错的解决方式

    eclipes的Spring注解SequenceGenerator(name="sequenceGenerator")报错的解决方式 右键项目打开Properties—>JA ...

  7. Can't bind to local 8700 for debugger报错和解决

    [2016-02-15 22:37:17 - ddms] Can't bind to local 8700 for debugger报错和解决 1.打开studio monitor是出错: Can't ...

  8. Loadrunner参数化连接oracle、mysql数据源报错及解决办法

    Loadrunner参数化连接oracle.mysql数据源报错及解决办法 (本人系统是Win7 64,  两位小伙伴因为是默认安装lr,安装在 最终参数化的时候,出现连接字符串无法自动加载出来: 最 ...

  9. ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法

    原文:ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法 群里好几个朋友都提到过这样的问题,说他们在Silverlight中调用了WebServi ...

随机推荐

  1. docker的安装,升级,与删除(最新版)

    docker安装在ubuntu上 以前叫做 Docker engine安装现在叫做docker-ce的 第一种安装办法: root下执行,sudo su - root apt-get update - ...

  2. 爬虫 requests 模块

    requests 模块 介绍 使用requests可以模拟浏览器的请求, 比起之前用到的urllib,requests模块的api更加便捷(本质就是封装了urllib3) ps: requests库发 ...

  3. centos6/7安装java和maven

    下载安装包并解压到相关目录即可 编辑环境变量vim /etc/profile.d/maven.sh export JAVA_HOME=/app/soft/java-1.8.0_181 export J ...

  4. 洛谷P5289 皮配

    解:观察一波部分分. 首先小数据直接暴力4n,然后考虑背包.设f[i][a][b][c]表示前i个学校中前三位导师分别有多少人,第四位导师可以直接推出来. 然后暴力枚举每一个人放在哪进行背包. 进一步 ...

  5. 简单的实现HTTP密码验证登陆

    1.首先需要安装 httpd-tools yum install -y httpd-tools 2.安装完成后设置用户名密码,我这里用的是NGINX htpasswd -bc /mypath/ngin ...

  6. bootstrap学习: 折叠插件和面板

    bootstrap提供了面板排版工具和折叠插件,能够用来实现新闻列表.留言板.博客分块等: 1.折叠插件: <a data-toggle="collapse" data-ta ...

  7. 剑指Offer_编程题_19

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2, ...

  8. Pandas系列(四)-文本数据处理

    内容目录 1. 为什么要用str属性 2. 替换和分割 3. 提取子串 3.1 提取第一个匹配的子串 3.2 匹配所有子串 3.3 测试是否包含子串 3.4 生成哑变量 3.5 方法摘要 一.为什么要 ...

  9. Git Gerrit使用

    Git Gerrit 操作都用 git bash操作: 如果想用 cmd 或者 PowerShell,系统环境变量 Path 添加 Git 安装路径,如: C:\Program Files (x86) ...

  10. 第十二节:Lambda、linq、SQL的相爱相杀(1)

    一. 谈情怀  Lambda.Linq.SQL伴随着我的开发一年又一年,但它们三者并没有此消彼长,各自占有这一定的比重,起着不可替代的作用. 相信我们最先接触的应该就是SQL了,凡是科班出身的人,大学 ...