Spark 读取HDFS存入 HBase(1.0.0 新 API)
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 1.0 变化介绍
新版 API 中加入了 Connection,HAdmin成了Admin,HTable成了Table,而Admin和Table只能通过Connection获得。
Connection的创建是个重量级的操作,由于Connection是线程安全的,所以推荐使用单例,其工厂方法需要一个HBaseConfiguration。
//通过工厂创建connection
Connection connection = ConnectionFactory.createConnection(config);
connection.close();
//表名
String tableName = "Table";
TableName tableNameObj = TableName.valueOf(tableName);
//通过connection获取
Table table = connection.getTable(tableNameObj);
BufferedMutator mutator = connection.getBufferedMutator(tableNameObj);
RegionLocator regionLocator = connection.getRegionLocator(tableNameObj);
Admin admin = connection.getAdmin();
具体过程
首先要向 HBase 写入数据,我们需要用到PairRDDFunctions.saveAsHadoopDataset。因为 HBase 不是一个文件系统,所以saveAsHadoopFile方法没用。
def saveAsHadoopDataset(conf: JobConf): Unit
这个方法需要一个 JobConf 作为参数,类似于一个配置项,主要需要指定输出的格式和输出的表名。
step1:读取HDFS文件内容
文件格式:
代码:
val sparkConf = new SparkConf().setAppName("HBaseTest").setMaster("local")
val sc = new SparkContext(sparkConf)
val readtxt=sc.textFile("hdfs://127.0.0.1:8020/user/hdfs/from_mysql/recommend_base_data_day/data_20160222")
val rddpro=readtxt.map(_.split(";")).map(p=>(p(0),p(1),p(2),p(3),p(4),p(5),p(6),try{p(7)} catch{
case ex:ArrayIndexOutOfBoundsException=>{""}
}))
step2:HBase创建表
val conf = HBaseConfiguration.create()
conf.set("hbase.zookeeper.quorum", "127.0.0.1")
conf.set("hbase.zookeeper.property.clientPort", "2181")
conf.set("hbase.defaults.for.version.skip", "true")
// conf.set(TableInputFormat.INPUT_TABLE, "b_user")
var conn=ConnectionFactory.createConnection(conf)
var admin=conn.getAdmin //得到admin(操作数据库)
var tabname=TableName.valueOf("recommend_base_data_day")
if(admin.tableExists(tabname)){
admin.disableTable(tabname)
admin.deleteTable(tabname)
}
var descrip=new HTableDescriptor(tabname)
descrip.addFamily(new HColumnDescriptor("info".getBytes()))//创建名为info的列族
admin.createTable(descrip)
step3:HBase配置输入表
val jobconf=new JobConf(conf,this.getClass)
jobconf.setOutputFormat(classOf[TableOutputFormat])
jobconf.set(TableOutputFormat.OUTPUT_TABLE,"recommend_base_data_day")
step4:数据处理函数
def convert(triple: (String, String, String,String, String, String,String, String)) = {
val p = new Put(Bytes.toBytes(triple._1))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("platform_id"),Bytes.toBytes(triple._2))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("dt"),Bytes.toBytes(triple._3))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("user_id"),Bytes.toBytes(triple._4))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("user_ip"),Bytes.toBytes(triple._5))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("goods_name"),Bytes.toBytes(triple._6))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("total_num"),Bytes.toBytes(triple._7))
p.addColumn(Bytes.toBytes("info"),Bytes.toBytes("etl_insert"),Bytes.toBytes(triple._8))
(new ImmutableBytesWritable, p)
}
step5: 执行,并查看结果
val localData =rddpro.map(convert)
localData.saveAsHadoopDataset(jobconf)
主要内容转载于:http://www.wuchong.me/blog/2015/04/06/spark-on-hbase-new-api/