Hbase是针对海量数据而生的,它的原型为bigtable,他可以用来存储各种格式的数据,我们对Hbase的操作常常是在Hbase的shell界面下利用指令对其操作的,但是这远远不能够满足我们的需求,所以,Hbase的Java API就得到了广泛的应用。其中,使用率最高的当属Put和Get,也就是在表中添加数据,和从表中查询数据。如果我们向Hbase中插入的数据是字符串的类型,那么我们直接通过Hbase shell的put指令即可,但是,如果是针对图片、视频等非结构化的数据该怎么办呢?在这里我以添加一张图片为例子,我用到的表名为talk,里面就一个列簇为file。
我们先说如何添加一张图片到表的列簇中,我们都知道数据是以二进制的行书存储在HDFS上的,所以我们最主要的是先将图片转换成byte[ ]格式的数据,然后将其添加到Hbase中。代码如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
public class Put_data {
public static Connection connection;
public static Configuration configuration;
//参数配置,主要用来到zookeeper中寻找regionServer的信息
public static void init(){
configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "hdfsvm001.hogpu.cc,hdfsvm002.hogpu.cc");
configuration.set("hbase.zookeeper.property.clientPort","2181");
configuration.set("zookeeper.znode.parent","/hbase-unsecure");
try {
connection = ConnectionFactory.createConnection(configuration);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
putRows();
}
public static void putRows() throws IOException{
init();
//得到表名为talk的表
Table table = connection.getTable(TableName.valueOf("talk"));
int i = 1;
//读取图片
File file = new File("/home/laipeng.han/oozie-result.png");
//这里为什么要设置为40961,因为图片的大小是40kb
byte[] img = new byte[40961];
//利用输入流将图片转换成二进制的形式
InputStream a = null;
a = new FileInputStream(file);
a.read(img);
//创建put对象,括号中的为插入的行键
Put put = new Put(Bytes.toBytes("row"+i));
//将图片插入指定列中,参数为(列簇,列,值)
put.addColumn(Bytes.toBytes("file"), null, img);
table.put(put);
table.close();
System.out.println("done put rows");
}
}
好,我们现在已经将图片插入到制定的列中了,如果我们想get这张图片该怎么办呢?很明显Hbase shell并不能满足我们的需求,所以,我们用到了Get api。其中,重点就是我们get到底的结果是一个二进制的结果,我们需要将其转化成图片的形式,代码如下:
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
public class Get_data {
public static Connection connection;
public static Configuration configuration;
public static void init(){
configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "hdfsvm001.hogpu.cc,hdfsvm002.hogpu.cc");
configuration.set("hbase.zookeeper.property.clientPort","2181");
configuration.set("zookeeper.znode.parent","/hbase-unsecure");
try {
connection = ConnectionFactory.createConnection(configuration);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
getData();
}
public static void getData() throws IOException{
init();
//首先我们需要先定位到表,到哪一行,如果想多行读取的话可以用scan,单行这里用的是get
Table table = connection.getTable(TableName.valueOf("talk"));
String rowid = "row1";
//创建Get对象,并将结果读出到result中
Get get = new Get(Bytes.toBytes(rowid));
get.addFamily(Bytes.toBytes("file"));
Result result = table.get(get);
show(result);
table.close();
}
//将读出的二进制结果转换成图片文件
public static void show(Result result) throws IOException{
byte[] image = new byte[40961];
Cell[] cells = result.rawCells();
//在这里我们先将二进制格式的value值取出
for(Cell cell:cells){
image = CellUtil.cloneValue(cell);
}
//利用文件的输入输出流的将其转换成图片文件
if(image != null && image.length > 0){
InputStream in = new ByteArrayInputStream(image);
File img_file = new File("/home/laipeng.han/data/", "oozie.png");
FileOutputStream out = new FileOutputStream(img_file);
byte[] b = new byte[40961];
int read = 0;
while((read = in.read(b)) != -1){
out.write(b, 0, read);
}
out.flush();
out.close();
in.close();
}
}
}
注:代码经过测试,大家只需要修改路径即可跑通,代码写的很不通用,很多参数都是可以从命令行传进来的,希望大家给予指点与改进。