Hbase增删改查、关联查询、关系型数据库转化

时间:2021-09-01 14:47:30

写在前面

主要的目的是想直接通过Hbase 将上面上面的Mysql 替换成Hbase, 这样能够对我们维护的负担压力减轻更多(调研), 实际过程中遇到了非常多的问题.

  1. 处理多表之间的问题的时候出现了很多问题. 主要是在列式数据库中 对每一行的定义都是非结构化的, 只是对column family 进行严格的规定而已.这样一来我们就没有了我们需要的外键/相关联的, 更多的操作都是通过全表扫描.
  2. 对rowKey 的设计需要有非常高要求. 学习OpenTSDB 中rowKey的巧妙设计, 虽然丢弃了版本号的使用,但是能够更加快的找到timeseries data,这也是一个非常好的一种设计之一.

Hbase 实践

CRUD 操作

1.增加一条记录

public void testPut() throws IOException {
HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("people"));
HTable table = (HTable) conn.getTable(TableName.valueOf("people"));
//设置rowkey 为 rk0001
Put put = new Put(Bytes.toBytes("rk0001"));
//在info 的column family----> name:zhangsan
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"),
Bytes.toBytes("zhangsan"));
//在info column family -----> age:25
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"),
Bytes.toBytes("25"));
//在info column family -----> money:10w
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("money"),
Bytes.toBytes("10w"));
table.put(put);
}

2.删除一条记录

public void testDelete() throws IOException {
HTable table = (HTable) conn.getTable(TableName.valueOf("people"));
//通过指定某行的rowkey 来删除整行的数据. (Q:是否将所有版本的删除?还是将最新版本删除?)
Delete delete = new Delete(Bytes.toBytes("rk9999"));
table.delete(delete);
table.close();
}

3.修改一条记录

因为hbase底层实现是hdfs 在保证高并发的同时, 会牺牲一些一致性, 只需要保证了最终的一致性即可, 所以更新的操作可以看做为通过对某个行直接覆盖写, 同时利用时间戳来保证获取到的数据是最新的.

4.查询一条记录

查询就是重点. 虽然看着没有join 的操作.但是丰富的api能够快速的实现join并且这个也是hbase的优势. 列式存储的优势能够在join 的时候体现出来.(具体从文件存储、索引、实现 需要认真考证)

4.1 通过Rowkey 进行查询

这个操作非常简单, 直接知道 RowKey 然后就能够提取出来所在的行

public void testScan() throws IOException {
HTable table = (HTable) conn.getTable(TableName.valueOf("people"));
//这里需要写出 rowkey的一个范围, 也可以直接写.
Scan scan = new Scan(Bytes.toBytes("rk29990"), Bytes.toBytes("rk30000"));
ResultScanner resultScaner = table.getScanner(scan);
for (Result result : resultScaner) {
System.out.println(Bytes.toString(result.getRow()));
//String str = Bytes.toString(result.getValue(Bytes.toBytes("info"),Bytes.toBytes("money")));
//System.out.println(str);
}
table.close();
}

4.2 通过正则来查询Rowkey

实现的方式是 在scan 的时候同时做filter (RowFilter)

//代码片段
Scan scan = new Scan();

Filter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator(login+"_"+"*"));

scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for (Result res : scanner) {
u = new User(res);
}

4.3 单列查询

很多时候我们并不知道我们的rowkey是什么, 但是我们知道我们现在要找到某一列的某一个值.在哪一行. 这个时候就需要用到单列查询 SingleColumnValueFilter
同理在hbase 里面的所有操作都是通过scan & filter 找到, 如果没有设计 Secondary Index 这样scan 的结果在效率上是比较慢的.

Filter filter = new SingleColumnValueFilter(Bytes.toBytes("info"),Bytes.toBytes(column), CompareFilter.CompareOp.EQUAL,Bytes.toBytes(query));

5.思考

整个重构项目写了一半, 但是发现有非常多的问题, 从关系型数据库迁移到hbase 不是说不可能, 但是又很多东西需要重新写.比如一些最简单的join count 等等都是人工的api 操作. 虽然可操作性非常高, 但是非常不利于我的快速迭代和开发, 维护成本也不低. 另外关系型数据库有很多非常友好和成熟的操作 不是hbase所擅长的, 尤其是事务型数据.

之后应该也会有更多的对hbase方面的学习,会一直更加认真的写一些分享.
写总结不是一件容易的事情.