HBase知识总结
学习了新的东西总要记点什么,以前看过很多文章也总结了一些笔记,由于知识比较零散所有没有分享出来。现在开始梳理一下以前的笔记和大家分享,如发现有什么不对请大家多多指正,相互学习。
基本概念
1.Row key
行主键,在对HBase进行查询时候只能依靠Row key,HBase不支持条件查询等类似于一些主流数据库的查询方式,读取记录只能依赖行主键以及进行全局扫面,可以将行主键想象成主流数据库查询过程中用到的主键(例如,id)。
2.Column Family
列族,可以将列族想象成日常主流数据库中的表结构的所有列的一个大管家,列族中存储了所有列的名称,整个表包括多少列,列族就包括多少(除去Row key和Timestamp列)。
3.Column
列,HBase的每个列都隶属于一个列族,以列族名称作为前缀,同一列族中的所有列会聚集在一个存储单元上,同时按照Column key进行排序。
4.Timestamp
在HBase中,通过row key 和 Colum Family确定一份数据,同一个row key和Colum Family可能有多份不同的数据,HBase通过时间戳来区分这些数据,同时按照时间戳对左右的数据进行排序,最新的数据排在最前面,时间戳默认为系统当前时间(精确到毫秒),同时也可以人为设置该值。
5.Value
我们在HBase表中精确查询数据时,通过TableName找到表,接着通过Row key找到对应的行,然后通过ColumnKey找到相应的列,最后根据时间戳找到最新的需要查询的值,这个值就是value。
6.存储类型
在HBase中,表名称是字符串,行键和列名称是二进制值(即就是Java中的Byte[]),时间戳是一个64为的整数(Java中的long类型),最后的查询结果Value是字节数组(Java中的byte[]类型)。
7.存储结构
在HBase中,整个数据表是按照行键进行排序,每行包括任意数量的列,列和列之间通过列键进行排序,每列包括若干的数据,整个HBase的存储结构可以理解如下:
Table (
Row key,List(
SortedMap(
Column,list(
Value,Timestamp
)
)
)
)
基础知识
- Java友好提供了全面的java客户端库
- HBase中所有数据都是作为原始数据,使用数组的形式存储
- 行健是唯一标识符,类似数据库的主键
- 表中确定一个单元的坐标是[rowkey,cloumn fanmily,column qualifier]
- 5个基本命令来访问HBase;Get(读)、Put(写)、Delete(删除)、Scan(扫描)、Increment(递增)
- HFile是存储文件,对应列族,一个列族可以有多少HFile文件,但是一个HFile不能存多个列族的数据
- 写的操作会写入预写式日志(WAL)和称为MemStore的内存写入缓冲区,当两者都确认写入后才认为写的动作成功完成
- 不建议禁用WAL,禁用后RegionServer故障时会导致数据丢失
基本操作
Java连接HBase
HBaseAdmin这个类负责什么,创建表、删除表等,HTable类负责相关的增删改查
1. 加载配置
Configuration conf = new Configuration();
// conf.addResource("hbase-site-cluster.xml");//指定文件加载
conf = HBaseConfiguration.create(conf);
HBaseAdmin admin = new HBaseAdmin(conf);//HBaseAdmin负责跟表相关的操作如create,drop等
HTable table = new HTable(conf, Bytes.toBytes("blog"));//HTabel负责跟记录相关的操作如增删改查等
2. 创建表
if (admin.tableExists("blog")) {// 如果存在要创建的表,先删除,再创建
admin.disableTable("blog");
admin.deleteTable("blog");
System.out.println("blog" + " is exist,detele....");
}
HTableDescriptor desc = new HTableDescriptor("blog");
desc.addFamily(new HColumnDescriptor("article"));//增加article列族
desc.addFamily(new HColumnDescriptor("author"));//增加author列族
admin.createTable(desc);
3. 增加记录(更新记录相同操作)
Put put = new Put(Bytes.toBytes("1"));///增加一条行键是“1”的数据
put.add(Bytes.toBytes("article"), Bytes.toBytes("title"), Bytes.toBytes("Head First HBase"));//在“article”列族中往单元“title”存入“Head First HBase”
put.add(Bytes.toBytes("article"), Bytes.toBytes("content"), Bytes.toBytes("HBase is the Hadoop database. Use it when you need random, realtime read/write access to your Big Data."));//在“article”列族往单元“//在“article”列族中往单元“content”存入“HBase is the...”
put.add(Bytes.toBytes("article"), Bytes.toBytes("tags"), Bytes.toBytes("Hadoop,HBase,NoSQL"));
put.add(Bytes.toBytes("author"), Bytes.toBytes("name"), Bytes.toBytes("hujinjun"));
put.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), Bytes.toBytes("一叶渡江"));
table.put(put);
4. 根据RowKey查询
Result result = table.get(Bytes.toBytes("RowKey"));
for (KeyValue kv : result.list()) {
System.out.println("family:" + Bytes.toString(kv.getFamily()));
System.out.println("qualifier:" + Bytes.toString(kv.getQualifier()));
System.out.println("value:" + Bytes.toString(kv.getValue()));
System.out.println("Timestamp:" + kv.getTimestamp());
}
你还可以在Get的实例中设定限制条件来获取自己想要的数据量。
为了返回指定的列,可以执行命令addColumn()。
Get get = new Get(Bytes.toBytes("RowKey"));
get.addColumn(
Bytes.toBytes("article"),
Bytes.toBytes("author")
);
Result result =table.get.(get);
对于列族可执行命令addFamily()。检索特定值,如下所示
Get get = new Get(Bytes.toBytes("RowKey"));
get.addFamily(Bytes.toBytes("article"));
byte[] b = r.getValue(
Bytes.toBytes("article"),
Bytes.toBytes("title")
);
String title = Bytes.toString(b);//"Head First HBase"
5. 遍历查询与迭代
Scan scan = new Scan();
ResultScanner rs = null;
try
{
rs = table.getScanner(scan);
for (Result r : rs) {
for (KeyValue kv : r.list()) {
System.out.println("family:" + Bytes.toString(kv.getFamily()));
System.out.println("qualifier:" + Bytes.toString(kv.getQualifier()));
System.out.println("value:" + Bytes.toString(kv.getValue()));
}
}
} finally
{
rs.close();
}
6. 删除记录
删除指定的列
Delete delete = new Delete(Bytes.toBytes("行键"));
delete.deleteColumns(
Bytes.toBytes("列族"),
Bytes.toBytes("列名"));
table.delete(delete);
deleteColumns()方法从行中删除一个单元,这个和deleteColumn()方法不同(尾部少了s)。deleteColumn()方法删除单元的内容。
删除一条记录
Delete deleteAll = new Delete(Bytes.toBytes("行键"));
table.delete(deleteAll);
删除一张表
admin.disableTable("表名");
admin.delete("表名");
### 创建一张表的实例开销很大使用连接池比直接创建表句柄好 ###
推荐的创建HConnection的方法
//Configuration conf = HBaseConfiguration.create();
//conf.set("hbase.zookeeper.quorum", QUORUM);
//conf.set("hbase.zookeeper.property.clientPort", CLIENTPORT);
Configuration conf = new Configuration();
conf.addResource("hbase-site-cluster.xml");//指定文件加载
HConnection connection = HConnectionManager.createConnection(conf);
HTableInterface table = connection.getTable("tablename");
try {
// Use the table as needed, for a single operation and a single thread
} finally {
table.close();
connection.close();
}
注意:
HTablePool是HBase连接池的老用法,该类在0.94,0.95和0.96中已经不建议使用,在0.98.1版本以后已经移除。