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 中加入了 Connection,HAdmin成了Admin,HTable成了Table,而Admin和Table只能通过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)
}

spark 操作hbase的更多相关文章

  1. Spark操作hbase

    于Spark它是一个计算框架,于Spark环境,不仅支持单个文件操作,HDFS档,同时也可以使用Spark对Hbase操作. 从企业的数据源HBase取出.这涉及阅读hbase数据,在本文中尽快为了尽 ...

  2. Spark操作HBase问题:java.io.IOException: Non-increasing Bloom keys

    1 问题描述 在使用Spark BulkLoad数据到HBase时遇到以下问题: 17/05/19 14:47:26 WARN scheduler.TaskSetManager: Lost task ...

  3. Spark操作HBase报:org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException异常解决方案

    一.异常信息 19/03/21 15:01:52 WARN scheduler.TaskSetManager: Lost task 4.0 in stage 21.0 (TID 14640, hnte ...

  4. spark 对hbase 操作

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

  5. Spark读取Hbase中的数据

    大家可能都知道很熟悉Spark的两种常见的数据读取方式(存放到RDD中):(1).调用parallelize函数直接从集合中获取数据,并存入RDD中:Java版本如下: JavaRDD<Inte ...

  6. spark(2.1.0) 操作hbase(1.0.2)

    一.写操作 1.spark中引入外部jar包 1)创建/usr/software/spark_jars目录,把hbase里的lib里的以下七个jar放入/usr/software/spark_jars ...

  7. Spark-读写HBase,SparkStreaming操作,Spark的HBase相关操作

    Spark-读写HBase,SparkStreaming操作,Spark的HBase相关操作 1.sparkstreaming实时写入Hbase(saveAsNewAPIHadoopDataset方法 ...

  8. Spark 下操作 HBase(1.0.0 新 API)

    hbase1.0.0版本提供了一些让人激动的功能,并且,在不牺牲稳定性的前提下,引入了新的API.虽然 1.0.0 兼容旧版本的 API,不过还是应该尽早地来熟悉下新版API.并且了解下如何与当下正红 ...

  9. PySpark操作HBase时设置scan参数

    在用PySpark操作HBase时默认是scan操作,通常情况下我们希望加上rowkey指定范围,即只获取一部分数据参加运算.翻遍了spark的python相关文档,搜遍了google和stackov ...

随机推荐

  1. django+nginx+supervisor+gunicorn+gevent 网站部署

    django+nginx+supervisor+gunicorn+gevent 网站部署 django,nginx,supervisor,gunicorn,gevent这几个都是在本领域大名鼎鼎的软件 ...

  2. Python3 如何优雅地使用正则表达式(详解一)

    注:本文翻译自 Regular Expression HOWTO,小甲鱼童鞋对此做了一些注释和修改. 正则表达式介绍 正则表达式(Regular expressions 也称为 REs,或 regex ...

  3. connect函数

    TCP客户用connect函数来建立与TCP服务器的连接 int connect (int sockfd, const sockaddr * servaddr, socklen_t addrlen); ...

  4. 转:ElasticSearch 简单入门

    原文来自于:http://www.oschina.net/translate/elasticsearch-getting-started?cmp 教程样例 我们将要部署一个非常简单的应用--在一个部门 ...

  5. hdu 4407 Sum

    http://acm.hdu.edu.cn/showproblem.php?pid=4407 题意:给定初始n个数1..n,两个操作,①1 x y p  询问第x个数到第y个数中与p互质的数的和; ② ...

  6. (2015年郑州轻工业学院ACM校赛题) G 矩阵

    看这道题的时候就感觉用一点动归思想+暴力 就能过了. #include<stdio.h> #include<iostream> #include<stack> #i ...

  7. 将银行读卡设备读取到的身份证头像Bitmap属性转换成路径

    需求是这样的,在项目开发的时候要求读取身份证,读到身份证的所有信息(信息里面包括头像属性,类型是Bitmap的).然后服务器要求我传过去的头像信息是String类型的Uri路径. 这是读卡器读到的身份 ...

  8. 乱译文档--Musca介绍

    胡乱翻译的,信,达,雅只能到达的水平.发现错误的话望留言好修改. 原文地址:http://aerosuidae.net/musca.html aerosuidae.net Musca 果蝇 A sim ...

  9. Java中Websocket使用实例解读

    介绍 现在很多网站为了实现即时通讯,所用的技术都是轮询(polling).轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器 ...

  10. arc4random和arc4random_uniform

    Objective-C 中有个arc4random()函数用来生成随机数且不需要种子,但是这个函数生成的随机数范围比较大,需要用取模的算法对随机值进行限制,有点麻烦. 其实Objective-C有个更 ...