Spark 下操作 HBase(1.0.0 新 API)

本文介绍了HBase 1.0.0版本的新API特性及其与Spark的集成方法。首先展示了如何使用新API完成基本的CRUD操作,随后详细解释了如何利用Spark进行数据的写入与读取。

HBase经过七年发展,终于在今年2月底,发布了 1.0.0 版本。这个版本提供了一些让人激动的功能,并且,在不牺牲稳定性的前提下,引入了新的API。虽然 1.0.0 兼容旧版本的 API,不过还是应该尽早地来熟悉下新版API。并且了解下如何与当下正红的 Spark 结合,进行数据的写入与读取。鉴于国内外有关 HBase 1.0.0 新 API 的资料甚少,故作此文。

本文将分两部分介绍,第一部分讲解使用 HBase 新版 API 进行 CRUD 基本操作;第二部分讲解如何将 Spark 内的 RDDs 写入 HBase 的表中,反之,HBase 中的表又是如何以 RDDs 形式加载进 Spark 内的。

环境配置

为了避免版本不一致带来不必要的麻烦,API 和 HBase环境都是 1.0.0 版本。HBase 为单机模式,分布式模式的使用方法类似,只需要修改HBaseConfiguration的配置即可。

开发环境中使用 SBT 加载依赖项

name := "SparkLearn"

version := "1.0"

scalaVersion := "2.10.4"

libraryDependencies += "org.apache.spark" %% "spark-core" % "1.3.0"

libraryDependencies += "org.apache.hbase" % "hbase-client" % "1.0.0"

libraryDependencies += "org.apache.hbase" % "hbase-common" % "1.0.0"

libraryDependencies += "org.apache.hbase" % "hbase-server" % "1.0.0"

HBase 的 CRUD 操作

新版 API 中加入了 ConnectionHAdmin成了AdminHTable成了Table,而AdminTable只能通过Connection获得。Connection的创建是个重量级的操作,由于Connection是线程安全的,所以推荐使用单例,其工厂方法需要一个HBaseConfiguration

val conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.property.clientPort", "2181")
conf.set("hbase.zookeeper.quorum", "master")

//Connection 的创建是个重量级的工作,线程安全,是操作hbase的入口
val conn = ConnectionFactory.createConnection(conf)

创建表

使用Admin创建和删除表

val userTable = TableName.valueOf("user")

//创建 user 表
val tableDescr = new HTableDescriptor(userTable)
tableDescr.addFamily(new HColumnDescriptor("basic".getBytes))
println("Creating table `user`. ")
if (admin.tableExists(userTable)) {
  admin.disableTable(userTable)
  admin.deleteTable(userTable)
}
admin.createTable(tableDescr)
println("Done!")

插入、查询、扫描、删除操作

HBase 上的操作都需要先创建一个操作对象Put,Get,Delete等,然后调用Table上的相对应的方法

try{
  //获取 user 表
  val table = conn.getTable(userTable)

  try{
    //准备插入一条 key 为 id001 的数据
    val p = new Put("id001".getBytes)
    //为put操作指定 column 和 value (以前的 put.add 方法被弃用了)
    p.addColumn("basic".getBytes,"name".getBytes, "wuchong".getBytes)
    //提交
    table.put(p)

    //查询某条数据
    val g = new Get("id001".getBytes)
    val result = table.get(g)
    val value = Bytes.toString(result.getValue("basic".getBytes,"name".getBytes))
    println("GET id001 :"+value)

    //扫描数据
    val s = new Scan()
    s.addColumn("basic".getBytes,"name".getBytes)
    val scanner = table.getScanner(s)

    try{
      for(r <- scanner){
        println("Found row: "+r)
        println("Found value: "+Bytes.toString(
          r.getValue("basic".getBytes,"name".getBytes)))
      }
    }finally {
      //确保scanner关闭
      scanner.close()
    }

    //删除某条数据,操作方式与 Put 类似
    val d = new Delete("id001".getBytes)
    d.addColumn("basic".getBytes,"name".getBytes)
    table.delete(d)

  }finally {
    if(table != null) table.close()
  }

}finally {
  conn.close()
}

Spark 操作 HBase

写入 HBase

首先要向 HBase 写入数据,我们需要用到PairRDDFunctions.saveAsHadoopDataset。因为 HBase 不是一个文件系统,所以saveAsHadoopFile方法没用。

def saveAsHadoopDataset(conf: JobConf): Unit
Output the RDD to any Hadoop-supported storage system, using a Hadoop JobConf object for that storage system

这个方法需要一个 JobConf 作为参数,类似于一个配置项,主要需要指定输出的格式和输出的表名。

Step 1:我们需要先创建一个 JobConf。

//定义 HBase 的配置
val conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.property.clientPort", "2181")
conf.set("hbase.zookeeper.quorum", "master")

//指定输出格式和输出表名
val jobConf = new JobConf(conf,this.getClass)
jobConf.setOutputFormat(classOf[TableOutputFormat])
jobConf.set(TableOutputFormat.OUTPUT_TABLE,"user")

Step 2: RDD 到表模式的映射
在 HBase 中的表 schema 一般是这样的:

row     cf:col_1    cf:col_2

而在Spark中,我们操作的是RDD元组,比如(1,"lilei",14)(2,"hanmei",18)。我们需要将 RDD[(uid:Int, name:String, age:Int)] 转换成 RDD[(ImmutableBytesWritable, Put)]。所以,我们定义一个 convert 函数做这个转换工作

def convert(triple: (Int, String, Int)) = {
      val p = new Put(Bytes.toBytes(triple._1))
      p.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes(triple._2))
      p.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes(triple._3))
      (new ImmutableBytesWritable, p)
}

Step 3: 读取RDD并转换

//read RDD data from somewhere and convert
val rawData = List((1,"lilei",14), (2,"hanmei",18), (3,"someone",38))
val localData = sc.parallelize(rawData).map(convert)

Step 4: 使用saveAsHadoopDataset方法写入HBase

localData.saveAsHadoopDataset(jobConf)

读取 HBase

Spark读取HBase,我们主要使用SparkContext 提供的newAPIHadoopRDDAPI将表的内容以 RDDs 的形式加载到 Spark 中。

val conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.property.clientPort", "2181")
conf.set("hbase.zookeeper.quorum", "master")

//设置查询的表名
conf.set(TableInputFormat.INPUT_TABLE, "user")

val usersRDD = sc.newAPIHadoopRDD(conf, classOf[TableInputFormat],
  classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable],
  classOf[org.apache.hadoop.hbase.client.Result])

val count = usersRDD.count()
println("Users RDD Count:" + count)
usersRDD.cache()

//遍历输出
usersRDD.foreach{ case (_,result) =>
  val key = Bytes.toInt(result.getRow)
  val name = Bytes.toString(result.getValue("basic".getBytes,"name".getBytes))
  val age = Bytes.toInt(result.getValue("basic".getBytes,"age".getBytes))
  println("Row key:"+key+" Name:"+name+" Age:"+age)
}

附录

更完整的代码已上传到 Gist 。

转自:http://www.wuchong.me/blog/2015/04/06/spark-on-hbase-new-api/
<think> 根据用户查询,需要连接Spark 3.x与HBase 2.1.0(CDH6版本)。参考引用[2]和[3]: 引用[2]提到CDH6.2.0HBase版本是2.1.0,并且提供了Maven仓库配置和版本管理。 引用[3]展示了Spark 3.3.1通过hbase-connectors连接CDH6.3.2的HBase(注意CDH6.3.2的HBase版本也是2.1.0)的示例代码。 步骤: 1. 确认版本:Spark 3.x 与 HBase 2.1.0 (CDH6) 连接,需要使用对应的hbase-connectors。根据引用[3],连接器使用格式为`org.apache.hadoop.hbase.spark`。 2. 添加依赖:在项目的pom.xml中添加hbase-connectors依赖,并指定与CDH版本对应的依赖版本(注意:CDH6.3.2和CDH6.2.0HBase版本都是2.1.0,但小版本可能有差异,需确保依赖版本与集群一致)。 3. 复制配置文件:如引用[1]所述,需要将HBase的配置文件(hbase-site.xml)和Hadoop的配置文件(core-site.xml, hdfs-site.xml)复制到项目的资源目录(src/main/resources)。 4. 编写代码:使用Spark DataFrame API或者Spark SQL,通过指定数据源格式为`org.apache.hadoop.hbase.spark`,并配置映射关系。 示例代码(基于引用[3]的Scala脚本): ```scala import org.apache.spark.sql.SparkSession val spark = SparkSession.builder() .appName("SparkHBaseConnectorExample") .getOrCreate() // 读取HBase表 val hbaseDF = spark.read .format("org.apache.hadoop.hbase.spark") .option("hbase.columns.mapping", "col1 STRING :key, col2 STRING cf:col2, col3 INT cf:col3") .option("hbase.table", "your_table_name") .load() hbaseDF.show() ``` 注意事项: - 映射关系:`hbase.columns.mapping`中,需指定列族和列名,以及对应的Spark数据类型,并且键(rowkey)用`:key`表示。 - 配置ZooKeeper:在hbase-site.xml中已经配置了ZooKeeper集群地址,因此代码中无需重复设置。但若未在配置文件中指定,则需在代码中通过`conf.set`设置(如引用[3]中所示)。 - 依赖版本:必须使用与CDH6.3.2(或CDH6.2.0)匹配的hbase-connectors版本。由于CDH并未直接提供hbase-connectors,通常使用Apache HBase Connectors并选择与HBase版本兼容的版本(如hbase-connectors-1.0.0对应HBase2.x)。但根据引用[3],CDH6.3.2环境下使用`org.apache.hadoop.hbase.spark`包,说明可能使用了特定的适配包。 依赖配置(示例): 在pom.xml中添加: ```xml <dependencies> <!-- Spark 3.x 核心依赖 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.12</artifactId> <version>3.1.3</version> <scope>provided</scope> </dependency> <!-- HBase Connector for Spark --> <dependency> <groupId>org.apache.hbase.connectors.spark</groupId> <artifactId>hbase-spark</artifactId> <version>1.0.0</version> <!-- 注意:1.0.0版本支持HBase2.x和Spark3.x --> </dependency> </dependencies> ``` 注意:上述依赖中,hbase-spark1.0.0版本是Apache官方发布的,但需确保与CDH的HBase2.1.0兼容。如果CDH有定制,可能需要使用Cloudera仓库中的依赖。根据引用[2],需要添加Cloudera仓库: ```xml <repositories> <repository> <id>cloudera</id> <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url> </repository> </repositories> ``` 另外,引用[3]中使用了`spark.read.format("org.apache.hadoop.hbase.spark")`,对应的包在hbase-spark-connector中。 但是,请注意:hbase-connectors在1.0.0版本后改名为hbase-spark,并且包路径为`org.apache.hadoop.hbase.spark`。 如果遇到版本不兼容问题,可以考虑使用Cloudera提供的依赖,但Cloudera并未单独发布hbase-spark-connector,因此可能需要使用Apache官方版本并确保与CDH的HBase兼容。 另一种方案:使用Cloudera提供的Spark on HBase(通过Spark SQL访问HBase),但需要启用HBase Service for Spark,这需要Cloudera Manager的支持。此处不展开。 总结步骤: 1. 添加依赖(hbase-spark:1.0.0)和Cloudera仓库。 2.HBase和Hadoop配置文件放入项目的resources目录。 3. 在代码中配置映射关系并读取。 如果使用CDH6.3.2,其自带的Spark2可能不支持Spark3,因此需要自行部署Spark3集群,并确保与CDH的HDFS、YARN等兼容。然后提交Spark3作业。 注意:如果集群是CDH6.3.2,引用[3]中使用的Spark版本是3.3.1,说明需要自行安装Spark3(CDH6默认是Spark2),并确保与CDH的Hadoop版本兼容(CDH6.3.2的Hadoop版本是3.0.0)。 因此,除了上述步骤,还需要确保Spark3的运行环境正确配置了CDH的Hadoop依赖。 最后,关于HBase永久RIT的问题,引用[4]提供了一些解决方案,但与本问题无直接关联。 相关问题: 1. 如何配置Spark3与CDH6的HDFS和YARN集成? 2. 在CDH6中,如何为HBase表设计Spark读取的列映射? 3. 使用Spark读写HBase时遇到版本兼容性问题如何解决? </think> 要连接 Spark 3.x 与 HBase 2.1.0 (CDH6版本),需使用 HBase Connectors 并正确配置版本依赖。以下是具体步骤: ### 1. 添加 Maven 依赖 在项目的 `pom.xml` 中添加以下依赖(版本需与 CDH 集群一致): ```xml <dependencies> <!-- Spark 3.x 核心依赖 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.12</artifactId> <version>3.1.3</version> <!-- 与CDH6兼容的Spark3版本 --> </dependency> <!-- HBase Spark Connector --> <dependency> <groupId>org.apache.hbase.connectors.spark</groupId> <artifactId>hbase-spark</artifactId> <version>1.0.0</version> <!-- 兼容HBase 2.x --> </dependency> <!-- CDH HBase 依赖 --> <dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.1.0-cdh6.3.2</version> <!-- 与集群版本一致 --> </dependency> </dependencies> <!-- 添加Cloudera仓库 --> <repositories> <repository> <id>cloudera</id> <url>https://repository.cloudera.com/artifactory/cloudera-repos</url> </repository> </repositories> ``` ### 2. 复制配置文件 将 CDH 集群的配置文件复制到项目资源目录: - `core-site.xml` (Hadoop) - `hbase-site.xml` (HBase) - `hdfs-site.xml` (HDFS) 路径示例(需替换实际主机名): ```bash cp /etc/hadoop/conf/core-site.xml src/main/resources/ cp /etc/hbase/conf/hbase-site.xml src/main/resources/ ``` ### 3. Scala 连接示例 ```scala import org.apache.spark.sql.SparkSession import org.apache.hadoop.hbase.HBaseConfiguration val spark = SparkSession.builder() .appName("Spark3-HBase2.1-Connector") .config("spark.serializer", "org.apache.spark.serializer.KryoSerializer") .getOrCreate() // 加载HBase配置 val conf = HBaseConfiguration.create() conf.set("hbase.zookeeper.quorum", "zk-node1,zk-node2") // ZK集群地址 // 读取HBase表 val hbaseDF = spark.read .format("org.apache.hadoop.hbase.spark") .option("hbase.columns.mapping", "id STRING :key, name STRING cf:name") .option("hbase.table", "test_table") .load() hbaseDF.show() ``` ### 4. 关键配置说明 | 配置项 | 说明 | |-------------------------|----------------------------------------------------------------------| | `hbase.zookeeper.quorum` | HBase Zookeeper 集群地址(逗号分隔) | | `hbase.columns.mapping` | 列映射规则,格式:`列名 数据类型 :key或列族:列名` | | `spark.serializer` | 必须使用 `KryoSerializer` 避免序列化问题 | | `hbase.table` | 要读取的 HBase 表名 | ### 5. 提交 Spark 作业 使用 `spark-submit` 时需包含 HBase 配置: ```bash spark-submit \ --master yarn \ --deploy-mode cluster \ --files /etc/hbase/conf/hbase-site.xml \ # 动态加载配置 --class com.example.HBaseConnectorApp \ your-application.jar ``` ### 注意事项 1. **版本匹配**:确保 `hbase-spark` 版本与 HBase 2.1.x 兼容,推荐 `1.0.0` 2. **RIT 问题**:如遇 Region in Transition 错误,检查 HBase Master 日志并重启 RegionServer[^4] 3. **CDH 仓库**:必须配置 Cloudera Maven 仓库获取 CDH 定制依赖[^2] [^1]: 配置文件需与集群版本严格一致 [^2]: Cloudera 仓库是获取 CDH 组件的关键 [^3]: 列映射需匹配表结构 [^4]: RIT 问题可能导致连接超时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值