Spark读写Hbase示例代码

Spark与HBase交互实践
最少需要导入hbase以下4个jar:
  • hbase-client
  • hbase-common
  • hbase-protocol
  • hbase-server

写入Hbase
def writeHbaseFromRDD (tableName:String, columnFamily:String, column:String,rdd:RDD[(String, String)]): Unit ={
val hbaseConf = HBaseConfiguration.create()
// 新旧API都可以用 ,大部分Hadoop 版本包含新旧两版的 API
/** hadoop API写法*/
// val jobConf = new org.apache.hadoop.mapred.JobConf(hbaseConf)
// jobConf.setOutputFormat(classOf[org.apache.hadoop.hbase.mapred.TableOutputFormat])
// jobConf.set(org.apache.hadoop.hbase.mapred.TableOutputFormat.OUTPUT_TABLE,tableName)
// rdd.map{
// case(key,value) =>
// val p = new Put(Bytes.toBytes(key))
// p.add(Bytes.toBytes(columnFamily),Bytes.toBytes(column),Bytes.toBytes(value))
//// p.setWriteToWAL(false)
// (new ImmutableBytesWritable,p)
// }.saveAsHadoopDataset(jobConf)

/** hadoop API写法*/
val job = new org.apache.hadoop.mapreduce.Job(hbaseConf)
job.setOutputFormatClass(
classOf[org.apache.hadoop.hbase.mapreduce.TableOutputFormat[ImmutableBytesWritable]])
job.setOutputKeyClass(
classOf[ImmutableBytesWritable])
job.setOutputValueClass(
classOf[Writable])
job.getConfiguration.set(org.apache.hadoop.hbase.mapreduce.TableOutputFormat.
OUTPUT_TABLE,tableName)
rdd.map{
case (key,value) =>
val p = new Put(Bytes. toBytes(key))
p.add(Bytes.
toBytes(columnFamily)
 ,Bytes.toBytes (column), Bytes.toBytes(value))
// p.setWriteToWAL(false)
( new ImmutableBytesWritable, p)
}.saveAsNewAPIHadoopDataset(job.getConfiguration)
}

读取Hbase
def readAsRDD (): Unit ={
val sparkConf = new SparkConf().setAppName( "read-hbase-test").setMaster("local" )
sparkConf.set(
"spark.serializer" , "org.apache.spark.serializer.KryoSerializer" )
val sc = new SparkContext(sparkConf)
val hbaseConf = HandleHbase.conf
/** hbase 中的scan可以在这里当做参数传入*/
val scan = new Scan()
scan.setStartRow(Bytes.
toBytes(
 "row-1"))
scan.setStopRow(Bytes.
toBytes(
 "row-2"))
def convertScanToString (scan: Scan) = {
val proto: ClientProtos.Scan = ProtobufUtil. toScan(scan)
Base64.
encodeBytes(proto.toByteArray)
}
/** TableInputFormat 中有若干参数可以用来过滤 ,可以参考看一下TableInputFormat的静态常量*/
hbaseConf.set(org.apache.hadoop.hbase.mapreduce.TableInputFormat. SCAN,
convertScanToString(scan))

hbaseConf.set(org.apache.hadoop.hbase.mapreduce.TableInputFormat.
INPUT_TABLE,"spark_hbase_test")
val rdd = sc.newAPIHadoopRDD(hbaseConf,classOf[org.apache.hadoop.hbase.mapreduce.TableInputFormat] ,
classOf[ImmutableBytesWritable] ,classOf[org.apache.hadoop.hbase.client.Result])
rdd.foreach(
println)
}

<think>我们有两个任务: 1. 使用Spark读取HBase数据 2. 使用Spark写入HBase数据 参考引用内容,我们知道Spark可以与HBase集成。通常,我们使用`org.apache.hadoop.hbase.spark`包中的API(如`HBaseContext`)或者使用`newAPIHadoopRDD`来读写HBase。 ### 读取HBase数据步骤 1. **配置HBase连接参数**:设置ZooKeeper的地址、表名等。 2. **定义Scan对象**:设置扫描条件(可选)。 3. **创建HBase RDD**:使用`newAPIHadoopRDD`或`HBaseContext`将HBase表转换为RDD。 ### 写入HBase数据步骤 1. **配置HBase连接参数**:同样需要ZooKeeper地址和表名。 2. **将RDD转换为`Put`对象**:将数据转换为HBase的Put操作。 3. **使用`HBaseContext`或`saveAsNewAPIHadoopDataset`**:将数据写入HBase。 ### 示例代码(Scala) #### 读取HBase表 ```scala import org.apache.hadoop.hbase.{HBaseConfiguration, HConstants} import org.apache.hadoop.hbase.client.Scan import org.apache.hadoop.hbase.mapreduce.TableInputFormat import org.apache.spark.SparkContext // 创建SparkContext val sc: SparkContext = ... // 配置HBase val conf = HBaseConfiguration.create() conf.set(HConstants.ZOOKEEPER_QUORUM, "zk1,zk2,zk3") // ZooKeeper地址 conf.set(TableInputFormat.INPUT_TABLE, "tableName") // 表名 // 可选:设置Scan对象(例如,限制列族或列) val scan = new Scan() scan.addFamily("cf".getBytes) conf.set(TableInputFormat.SCAN, convertScanToString(scan)) // 需要将Scan转为String // 读取HBase表,创建RDD val hbaseRDD = sc.newAPIHadoopRDD( conf, classOf[TableInputFormat], classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable], classOf[org.apache.hadoop.hbase.client.Result] ) // 转换RDD为可读格式 val resultRDD = hbaseRDD.map { case (_, result) => val rowkey = Bytes.toString(result.getRow) val value = Bytes.toString(result.getValue("cf".getBytes, "column".getBytes)) (rowkey, value) } resultRDD.take(10).foreach(println) ``` #### 写入HBase表 ```scala import org.apache.hadoop.hbase.{HBaseConfiguration, HConstants} import org.apache.hadoop.hbase.client.Put import org.apache.hadoop.hbase.mapreduce.TableOutputFormat import org.apache.hadoop.hbase.spark.HBaseContext import org.apache.hadoop.hbase.util.Bytes import org.apache.spark.SparkContext // 创建SparkContext val sc: SparkContext = ... // 配置HBase val conf = HBaseConfiguration.create() conf.set(HConstants.ZOOKEEPER_QUORUM, "zk1,zk2,zk3") conf.set(TableOutputFormat.OUTPUT_TABLE, "tableName") // 假设有一个RDD[(String, String)],表示(rowkey, value) val dataRDD = sc.parallelize(Seq(("row1", "value1"), ("row2", "value2"))) // 将数据转换为Put对象 val putRDD = dataRDD.map { case (rowkey, value) => val put = new Put(Bytes.toBytes(rowkey)) put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("column"), Bytes.toBytes(value)) (new org.apache.hadoop.hbase.io.ImmutableBytesWritable, put) } // 使用saveAsNewAPIHadoopDataset写入 putRDD.saveAsNewAPIHadoopDataset( conf, classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable], classOf[org.apache.hadoop.hbase.client.Put], classOf[TableOutputFormat[org.apache.hadoop.hbase.io.ImmutableBytesWritable]] ) ``` ### 注意事项 1. **依赖**:需要将HBase的相关Jar包(如`hbase-client`, `hbase-common`, `hbase-server`, `hbase-spark`等)添加到Spark的类路径中。可以使用`--jars`参数或者在构建工具中添加依赖。 2. **ZooKeeper地址**:根据实际集群配置设置。 3. **列族和列名**:需要提前在HBase中创建表和列族。 4. **Scan转换工具函数**:需要将Scan对象转换为Base64编码的字符串,工具函数如下: ```scala import org.apache.hadoop.hbase.protobuf.ProtobufUtil import org.apache.hadoop.hbase.util.Base64 def convertScanToString(scan: Scan): String = { val proto = ProtobufUtil.toScan(scan) Base64.encodeBytes(proto.toByteArray) } ``` ### 使用HBaseContext(简化操作) `HBaseContext`是Spark-HBase集成库提供的工具,可以简化操作: #### 读取示例 ```scala import org.apache.hadoop.hbase.spark.HBaseContext val hbaseContext = new HBaseContext(sc, conf) val scan = new Scan() val rdd = hbaseContext.hbaseRDD("tableName", scan) ``` #### 写入示例 ```scala hbaseContext.bulkPut[(String, String)]( dataRDD, "tableName", (record) => { val put = new Put(Bytes.toBytes(record._1)) put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col"), Bytes.toBytes(record._2)) put }, false) // 是否自动创建不存在的列族,通常设为false ``` ### 性能优化 1. **批量写入**:使用`bulkPut`批量写入,减少RPC调用[^1]。 2. **调整Scan缓存**:在Scan对象中设置`setCaching`,控制每次从RegionServer读取的行数。 3. **分区**:通过调整Scan的分区策略(如设置`setStartRow`和`setStopRow`)实现并行读取。 ### 总结 Spark读写HBase的核心在于正确配置HBase连接参数,并通过Hadoop的MapReduce格式(`TableInputFormat`/`TableOutputFormat`)或`HBaseContext`实现数据转换。注意依赖管理和集群配置的一致性[^2][^3]。 §§相关问题§§ 1. 如何优化Spark读取HBase的性能? 2. 在Spark中如何处理HBase表的结构化数据转换? 3. Spark读写HBase时遇到依赖冲突如何解决? 4. 如何使用PySpark读写HBase? </think> # Spark读写HBase数据库数据的方法 SparkHBase集成可以实现高效的数据处理,尤其适用于大规模非结构化或半结构化数据场景。以下是完整的Spark读写HBase方法指南: ## 一、环境准备 ### 1.1 依赖配置(Maven) ```xml <dependencies> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.12</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.4.17</version> </dependency> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-spark</artifactId> <version>2.4.17</version> </dependency> </dependencies> ``` ### 1.2 HBase配置 ```scala import org.apache.hadoop.hbase.HBaseConfiguration val conf = HBaseConfiguration.create() conf.set("hbase.zookeeper.quorum", "zk1,zk2,zk3") // ZooKeeper集群地址 conf.set("hbase.zookeeper.property.clientPort", "2181") conf.set("zookeeper.znode.parent", "/hbase") ``` ## 二、读取HBase数据 ### 2.1 基础读取方法 ```scala import org.apache.spark.SparkContext import org.apache.hadoop.hbase.mapreduce.TableInputFormat import org.apache.hadoop.hbase.client.Result import org.apache.hadoop.hbase.util.Bytes val sc: SparkContext = ... // SparkContext实例 // 配置表名和列族 conf.set(TableInputFormat.INPUT_TABLE, "books") conf.set(TableInputFormat.SCAN_COLUMNS, "cf:title cf:sales") // 创建RDD val hbaseRDD = sc.newAPIHadoopRDD( conf, classOf[TableInputFormat], classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable], classOf[Result] ) // 处理结果 val result = hbaseRDD.map { case (_, result) => val title = Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("title"))) val sales = Bytes.toInt(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("sales"))) (title, sales) } ``` ### 2.2 高级方法(使用HBaseContext) ```scala import org.apache.hadoop.hbase.spark.HBaseContext val hbaseContext = new HBaseContext(sc, conf) val scan = new Scan().addColumn(Bytes.toBytes("cf"), Bytes.toBytes("title")) val rdd = hbaseContext.hbaseRDD( TableName.valueOf("books"), scan, (result: Result) => { val title = Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("title"))) val sales = Bytes.toInt(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("sales"))) (title, sales) } ) ``` ## 三、写入HBase数据 ### 3.1 基础写入方法 ```scala import org.apache.hadoop.hbase.mapreduce.TableOutputFormat import org.apache.hadoop.hbase.client.Put import org.apache.hadoop.hbase.io.ImmutableBytesWritable // 准备数据RDD val data = sc.parallelize(Seq( ("spark", 5), ("hadoop", 8) )) // 转换为Put操作 val puts = data.map { case (title, sales) => val put = new Put(Bytes.toBytes(title)) put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("sales"), Bytes.toBytes(sales)) (new ImmutableBytesWritable, put) } // 配置输出表 conf.set(TableOutputFormat.OUTPUT_TABLE, "books") // 保存到HBase puts.saveAsNewAPIHadoopFile( "hdfs://path/to/temp", classOf[ImmutableBytesWritable], classOf[Put], classOf[TableOutputFormat[ImmutableBytesWritable]], conf ) ``` ### 3.2 批量写入(推荐) ```scala import org.apache.hadoop.hbase.spark.HBaseContext val hbaseContext = new HBaseContext(sc, conf) val data = sc.parallelize(Seq( (Bytes.toBytes("spark"), Bytes.toBytes("cf"), Bytes.toBytes("sales"), Bytes.toBytes(5)), (Bytes.toBytes("hadoop"), Bytes.toBytes("cf"), Bytes.toBytes("sales"), Bytes.toBytes(8)) )) hbaseContext.bulkPut[(Array[Byte], Array[Byte], Array[Byte], Array[Byte])]( data, TableName.valueOf("books"), (record) => { val put = new Put(record._1) put.addColumn(record._2, record._3, record._4) put } ) ``` ## 四、性能优化技巧 1. **批量操作**:使用`bulkPut`替代单条写入,减少RPC调用次数 2. **预分区**:提前规划好HBase表的分区策略 3. **扫描优化**: - 设置Scan缓存:`scan.setCaching(500)` - 指定扫描范围:`scan.setStartRow(...)`和`scan.setStopRow(...)` 4. **列裁剪**:只读取需要的列族和列限定符 5. **内存管理**:调整Spark执行器内存和HBase客户端缓存 ## 五、常见问题解决 1. **类路径冲突**:确保SparkHBase使用兼容的Hadoop版本 2. **连接超时**: ```scala conf.set("hbase.rpc.timeout", "60000") conf.set("hbase.client.operation.timeout", "60000") ``` 3. **RegionServer负载不均**:使用合适的RowKey设计策略 ## 六、Spark SQL集成 ```scala // 定义HBase表结构 spark.sql( s"""CREATE TABLE books USING org.apache.hadoop.hbase.spark |OPTIONS ( | 'hbase.table.name'='books', | 'hbase.columns.mapping'=':key, cf:title, cf:sales', | 'hbase.spark.use.hbasecontext'='false' |)""".stripMargin) // 执行SQL查询 val results = spark.sql("SELECT title, AVG(sales) FROM books GROUP BY title") ``` > **注意**:Spark SQL集成需要额外的配置和兼容性检查,适合结构化查询场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值