新增码云地址:https://gitee.com/hanmov5/mop-hbase-template

一、写在前面

业务架构用到HBase,但由于某些不可名状原因,没有用phoniex等上层工具,开发都是用原生的HBase Api来实现逻辑,原生API虽然使用不算困难,但是在复用性和可读性方便很差,在这样的背景下,根据现有业务和现在HBase的常用方式上封装了这个简易的ORM,说是ORM其实不是特别准确,只能算是一个轻量级的工具框架吧,我把它称之为easy-hbase,现已在本人所在事业部广泛使用。

二、设计思路

基于现有HBase存储业务的逻辑和使用方式来设计工具的思路

  1. HBase使用列簇设计不宜过多,一般为单个固定列簇。

  2. HBase存储的基础数据表,比如某个订单或者某个帖子之类的,rowKey类似为主键,然后固定单个列簇里面,某个column就是基础数据的一个字段,value就是对应的值,这个实际上和关系型数据库有点类似了,这样我们需要一个封装,根据主键返回一堆字段,再映射成我们需要的对象。

  3. 由于HBase是非关系型数据库,它的查询都是基于rowKey来进行的。一些关联查询需要建立相应的索引来实现(ps:复杂的HBase查询实现有多种方式,建立索引是比较常见的),比如某个用户的发帖列表,用户相关key为rowKey,column为Long最大值-发帖时间,value为帖子rowKey,这部分数据的column和value都不是固定的,区别于2的固定column值。

  4. HBase存储的基础单位也是字节,这点跟redis都是一致的,但是不同于redis客户端将value固定为String的字节数组,HBase提供的api是允许不同类型如Integer|Long|String等操作的,为方便管理和代码封装,实际业务上会规定尽量使用String来存储有关数据,特殊情况下用Long(主要是为了计数器的原子操作)。

  5. HBase基础数据表查询会返回指定PO,而一些索引表查询会返回不同的column和value,另外在条件查询时,我们有时候会限制返回我们需要的column或者是只取指定value(或者别的笔记关系:大于或不等于等)的column,我们需要一个基础的单元格类来承载这些功能。

  6. 一般基础数据相同的属性,我们可能会放多份,区分正序或者倒叙等,还有复杂索引的数据其也没特定的table,所以我们设计的时候是将HBase的table以参数的形式传入,而非注解,建议这些配置在统一的地方维护

三、代码实现

下面会介绍框架的整体架构和核心相关类设计

  1. 项目结构

  • easy-hbase-core:主要包括一些基础的Bean和Annotation,常量和工具类
  • easy-hbase-dao:主要代码,包括HBase相关操作代码封装和查询映射等,可直接spring集成使用
  • easy-hbase-spring-boot-starter:一个简单的spring-boot-starter,适合spring-boot项目集成使用
  • easy-hbase-spring-boot-demo:一个简单的spring-boot-demo项目,演示集成使用

2. 核心类

  • HBaseColumn:Field注解,用于注解PO的相关属性
  1. package com.gaoxin.mop.annotation;
  2. import java.lang.annotation.*;
  3. /**
  4. * Author: Mr.tan
  5. * Date: 2017/08/18
  6. * <p>
  7. * used on the field associate to the column from the hbase
  8. * </p>
  9. */
  10. @Documented
  11. @Retention(RetentionPolicy.RUNTIME)
  12. @Target(ElementType.FIELD)
  13. public @interface HBaseColumn {
  14. String family() default "";
  15. String column();
  16. boolean exist() default true;
  17. }

family:列簇属性,用于指定特殊的列簇,项目里面有默认的全局family

column::列属性,用于po属性和HBase对应column不匹配的情况,若一致无需指定

exist:若po中某个字段不在HBase存在的话,需手动设置这个属性为false,但建议po类为纯净的po

  • RowKey:field注解,用于注解po中的rowKey,若po中的属性不为rowkey值的话,需手动指定这个注解,否则将会默认field为rowkey
  1. package com.gaoxin.mop.annotation;
  2. import java.lang.annotation.*;
  3. /**
  4. * Author: Mr.tan
  5. * Date: 2017/08/18
  6. * <p>
  7. * used on the field associate to the rowkey from the hbase
  8. * </p>
  9. */
  10. @Documented
  11. @Retention(RetentionPolicy.RUNTIME)
  12. @Target(ElementType.FIELD)
  13. public @interface RowKey {
  14. }
  • ColumnInfo:封装最基础的单元格类,columnFamily,column和对应的value
  1. package com.gaoxin.mop.bean;
  2. import com.gaoxin.mop.constants.HBaseConstant;
  3. import org.apache.hadoop.hbase.filter.CompareFilter;
  4. /**
  5. * Author: Mr.tan
  6. * Date: 2017/08/18
  7. * <p>
  8. * the base entity contains columnFamily and column、value、op
  9. * default value String.class,others set customize valueClass
  10. * used on limit the back columns and filter values
  11. * </p>
  12. */
  13. public class ColumnInfo {
  14. private String columnFamily;
  15. private String column;
  16. private String value;
  17. private CompareFilter.CompareOp compareOperator;
  18. private Class valueClass;
  19. public ColumnInfo() {
  20. }
  21. public ColumnInfo(String column) {
  22. this(HBaseConstant.DEFAULT_FAMILY, column, CompareFilter.CompareOp.EQUAL);
  23. }
  24. public ColumnInfo(String columnFamily, String column, CompareFilter.CompareOp compareOperator) {
  25. this.columnFamily = columnFamily;
  26. this.column = column;
  27. this.compareOperator = compareOperator;
  28. }
  29. public ColumnInfo(String columnFamily, String column, CompareFilter.CompareOp compareOperator,Class valueClass) {
  30. this(columnFamily, column, compareOperator);
  31. this.valueClass = valueClass;
  32. }
  33. public ColumnInfo(String column, String value) {
  34. this(HBaseConstant.DEFAULT_FAMILY, column, value, CompareFilter.CompareOp.EQUAL);
  35. }
  36. public ColumnInfo(String columnFamily, String column, String value) {
  37. this(columnFamily, column, value, CompareFilter.CompareOp.EQUAL);
  38. }
  39. public ColumnInfo(String columnFamily, String column, String value, CompareFilter.CompareOp compareOperator) {
  40. this(columnFamily, column, compareOperator);
  41. this.value = value;
  42. }
  43. public String getColumnFamily() {
  44. return columnFamily;
  45. }
  46. public CompareFilter.CompareOp getCompareOperator() {
  47. return compareOperator;
  48. }
  49. public void setCompareOperator(CompareFilter.CompareOp compareOperator) {
  50. this.compareOperator = compareOperator;
  51. }
  52. public void setColumnFamily(String columnFamily) {
  53. this.columnFamily = columnFamily;
  54. }
  55. public String getColumn() {
  56. return column;
  57. }
  58. public void setColumn(String column) {
  59. this.column = column;
  60. }
  61. public String getValue() {
  62. return value;
  63. }
  64. public void setValue(String value) {
  65. this.value = value;
  66. }
  67. public Class getValueClass() {
  68. return valueClass;
  69. }
  70. public void setValueClass(Class valueClass) {
  71. this.valueClass = valueClass;
  72. }
  73. }

value:依据前文的设计思路,这里我们默认value为String类型,大多数情况下也应该这样做,如果有特殊的类型,如Long之类的,需指定valueClass的class

compareOperator:比较器属性,可以设置这个值用于在HBase限制返回column和值过滤的时候传入,可取的值:EQUAL|NOT EQUAL|GREATER等,我们这个类默认EQUAL

  • HBaseFactoryBean:HBase的连接初始化工厂Bean,用于初始化HBase连接
  1. package com.gaoxin.mop.config;
  2. import com.gaoxin.mop.constants.HBaseConstant;
  3. import org.apache.commons.lang.StringUtils;
  4. import org.apache.hadoop.conf.Configuration;
  5. import org.apache.hadoop.hbase.HBaseConfiguration;
  6. import org.apache.hadoop.hbase.client.HConnection;
  7. import org.apache.hadoop.hbase.client.HConnectionManager;
  8. import org.springframework.stereotype.Component;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. /**
  12. * Author: Mr.tan
  13. * Date: 2017/08/18
  14. * <p>
  15. * HBaseConstant 配置载入。初始化连接
  16. */
  17. @Component
  18. public class HBaseFactoryBean {
  19. private static HBaseFactoryBean factoryBean = null;
  20. private HBaseFactoryBean() {
  21. }
  22. public static HBaseFactoryBean getInstance() {
  23. if (factoryBean == null) {
  24. factoryBean = new HBaseFactoryBean();
  25. }
  26. return factoryBean;
  27. }
  28. private static List<HConnection> connections;
  29. private List<HBaseConfig> hbaseConfigs;
  30. public static void setConnections(List<HConnection> connections) {
  31. HBaseFactoryBean.connections = connections;
  32. }
  33. public void setHbaseConfigs(List<HBaseConfig> hbaseConfigs) {
  34. this.hbaseConfigs = hbaseConfigs;
  35. }
  36. public void initializeConnections() throws Exception {
  37. connections = new ArrayList<>();
  38. if (hbaseConfigs == null) {
  39. throw new RuntimeException("hbase config is null error");
  40. }
  41. for (HBaseConfig config : hbaseConfigs) {
  42. Configuration configuration = HBaseConfiguration.create();
  43. configuration.set("hbase.zookeeper.quorum", config.getZookeeperQuorum());
  44. configuration.set("hbase.zookeeper.property.clientPort", StringUtils.isBlank(config.getZookeeperClientPort()) ? HBaseConstant.DEFAULT_HBASE_PORT : config.getZookeeperClientPort());
  45. HConnection connection = HConnectionManager.createConnection(configuration);
  46. connections.add(connection);
  47. }
  48. }
  49. public static HConnection getDefaultConnection() {
  50. return connections.get(0);
  51. }
  52. public static HConnection getSpecifyConnection(int index) {
  53. if (index > connections.size() - 1) {
  54. throw new RuntimeException("hbase connection is not exist");
  55. }
  56. return connections.get(index);
  57. }
  58. }
  • HBaseDao:HBase基础操作核心类
  1. package com.gaoxin.mop.dao;
  2. import com.gaoxin.mop.bean.ColumnInfo;
  3. import java.util.List;
  4. /**
  5. * Author: Mr.tan
  6. * Date: 2017/08/18
  7. */
  8. public interface HBaseDao {
  9. <T> T get(String tableName, String rowKey, List<ColumnInfo> columns, List<ColumnInfo> filters, Class<? extends T> clazz);
  10. <T> T get(String tableName, String rowKey, Class<? extends T> clazz);
  11. <T> T get(String tableName, String rowKey, List<ColumnInfo> columns, Class<? extends T> clazz);
  12. String getSingleColumnValue(String tableName, String rowKey, String column);
  13. <T> T getSingleColumnValue(String tableName, String rowKey, String column, Class<? extends T> clazz);
  14. List<String> getRowKeys(String tableName);
  15. List<String> getRowKeys(String tableName, String startRow, String endRow);
  16. List<String> getRowKeys(String tableName, String startRow, String endRow, Integer pageSize, String separate, Integer index);
  17. List<String> getRowKeys(String tableName, String startRow, String endRow, Integer pageSize, String separate);
  18. List<String> getRowKeys(String tableName, String startRow, String endRow, Integer pageSize);
  19. List<String> getRowKeysByPrefix(String tableName, String prefix);
  20. List<String> getRowKeysByPrefix(String tableName, String startRow, String endRow, String prefix);
  21. List<ColumnInfo> getColumns(String tableName, String rowKey, String columnFamily, List<ColumnInfo> columns, List<ColumnInfo> filters);
  22. List<ColumnInfo> getColumns(String tableName, String rowKey, List<ColumnInfo> columns, List<ColumnInfo> filters);
  23. List<ColumnInfo> getColumns(String tableName, String rowKey, String columnFamily);
  24. List<ColumnInfo> getColumns(String tableName, String rowKey);
  25. <T> List<T> getList(String tableName, List<String> rowKeys, Class<? extends T> clazz);
  26. <T> List<T> getList(String tableName, List<String> rowKeys,List<ColumnInfo> columns, List<ColumnInfo> filters, Class<? extends T> clazz);
  27. <T> List<T> getList(String tableName, Class<? extends T> clazz);
  28. <T> List<T> getList(String tableName, List<ColumnInfo> columns, List<ColumnInfo> filters, Class<? extends T> clazz);
  29. <T> List<T> getList(String tableName, List<ColumnInfo> columns, List<ColumnInfo> filters, String start, String end, Class<? extends T> clazz);
  30. <T> List<T> getPageList(String tableName, String startRow, String endRow, Integer pageSize, Class<? extends T> clazz);
  31. List<ColumnInfo> getColumnsByPage(String tableName, String rowKey, Integer pageNo, Integer pageSize);
  32. List<ColumnInfo> getColumnsByPage(String tableName, String rowKey, Integer pageNo, Integer pageSize, List<ColumnInfo> columns, List<ColumnInfo> filters);
  33. <T> T getColumnObj(String tableName, String rowKey, String column,Class<? extends T> clazz);
  34. <T> List<T> getColumnObjList(String tableName, String rowKey, List<String> columns,Class<? extends T> clazz);
  35. <T> List<T> getPageColumnObjList(String tableName, String rowKey, Integer pageNo,Integer pageSize,Class<? extends T> clazz);
  36. <T> boolean put(String tableName, List<T> objects);
  37. <T> boolean put(String tableName, T object);
  38. boolean put(String tableName, String rowKey, String column, String value);
  39. boolean put(String tableName, String rowKey, ColumnInfo columnInfo);
  40. boolean put(String tableName, String rowKey, List<ColumnInfo> columnInfos);
  41. boolean delete(String tableName, String rowKey);
  42. boolean delete(String tableName, String rowKey, List<ColumnInfo> list);
  43. boolean delete(String tableName, String rowKey, ColumnInfo columnInfo);
  44. boolean delete(String tableName, String rowKey, String column);
  45. long addCounter(String tableName, String rowKey, String column, long num);
  46. }

上述代码为主要核心代码,封装了总共八大类的方法:

1.获取单个PO的get方法,column用于限制返回的column,filter用于批量过滤

2.获取多个PO的getList方法

3.获取单个signleColumn、多个Column的getColumns方法,支持分页(HBase的宽表分页,基于偏移量设计)

4.支持批量PUT的put方法

5.支持批量DELETE的delete方法

6.支持原子操作的addCounter计数器方法

7.支持只获取RowKey的分页方法(基于KeyOnlyFilter,减少数据传输,适用于仅需要RowKey情况)

8.支持getColumsObj适用于value是一个json对象的查询方法

3. 说明

Retrieve an HTableInterface implementation for access to a table. The returned HTableInterface is not thread safe, a new instance should be created for each using thread. This is a lightweight operation, pooling or caching of the returned HTableInterface is neither required nor desired. Note that the HConnection needs to be unmanaged (created with HConnectionManager.createConnection(Configuration)).

  • 如上述引用,HBase官方推荐HConnecton全局维护,而HTablePool也被废弃,不建议使用,所以我们这里也是维护了全局的HConnection,在HTable的使用上市即用即关的。
  • 以上是主要的核心类,其主要映射也是通过反射来建立关系的,这里就不多说了
  • 由于公司使用的hbase-client版本为0.96,所以这版本也只针对0.96,如果是更高版本的,由于部分api的改变暂不支持
  • 在dao的模块里面,有相应的demo用例和对应的测试用例,测试用例写的也不规范,主要是当初内部快速开发校验下,可以作为一个验证。
  • spring-boot-starter版本也很简单,只是集成了一个扫描注入而已,也有相应的DEMO
  • 最后,奉上源码地址,有不足的地方还望海涵,敬请斧正。

https://github.com/Kelin92/easy-hbase

HBase封装easy-hbase设计实现的更多相关文章

  1. (转)HBase 的原理和设计

    转自:HBase的原理和设计 HBase架构:

  2. HBase二级索引的设计(案例讲解)

    摘要 最近做的一个项目涉及到了多条件的组合查询,数据存储用的是HBase,恰恰HBase对于这种场景的查询特别不给力,一般HBase的查询都是通过RowKey(要把多条件组合查询的字段都拼接在RowK ...

  3. Hbase:原理和设计

    转载自:http://www.sysdb.cn/index.php/2016/01/10/hbase_principle/ ,感谢原作者. 简介 HBase —— Hadoop Database的简称 ...

  4. HBase之六:HBase的RowKey设计

    数据模型 我们可以将一个表想象成一个大的映射关系,通过行健.行健+时间戳或行键+列(列族:列修饰符),就可以定位特定数据,Hbase是稀疏存储数据的,因此某些列可以是空白的, Row Key Time ...

  5. HBase二级索引的设计

    摘要 最近做的一个项目涉及到了多条件的组合查询,数据存储用的是HBase,恰恰HBase对于这种场景的查询特别不给力,一般HBase的查询都是通过RowKey(要把多条件组合查询的字段都拼接在RowK ...

  6. HBase之八--(1):HBase二级索引的设计(案例讲解)

    摘要 最近做的一个项目涉及到了多条件的组合查询,数据存储用的是HBase,恰恰HBase对于这种场景的查询特别不给力,一般HBase的查询都是通过RowKey(要把多条件组合查询的字段都拼接在RowK ...

  7. HBase概念及表格设计

    HBase概念及表格设计 1. 概述(扯淡~) HBase是一帮家伙看了Google发布的一片名为“BigTable”的论文以后,犹如醍醐灌顶,进而“山寨”出来的一套系统. 由此可见: 1. 几乎所有 ...

  8. HBase之一:HBase原理和设计

    一.简介 HBase —— Hadoop Database的简称,Google BigTable的另一种开源实现方式,从问世之初,就为了解决用大量廉价的机器高速存取海量数据.实现数据分布式存储提供可靠 ...

  9. hbase表的高性能设计

    第7章 HBase优化 7.1 高可用 在HBase中Hmaster负责监控RegionServer的生命周期,均衡RegionServer的负载,如果Hmaster挂掉了,那么整个HBase集群将陷 ...

随机推荐

  1. eclipse maven install后查看报错信息

  2. jQuery CSS方法

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  3. JavaSE---多线程---线程的创建、启动

    1.概述 1.1 Java中使用Thread类表示线程:   所有的线程对象必须是Thread类 或 其子类的实例:   每条线程的作用:完成一定的任务:   Java中使用run方法来封装线程执行体 ...

  4. JavaSE---多线程---概述

    1.概述 1.1 进程: 系统进行资源分配.调度的一个独立单元: 进程的特征: 1.1.1 独立性: 系统中独立存在的实体,拥有自己独立的资源: 每个进程都拥有自己私有的地址空间,在没有经过进程本身允 ...

  5. 【leetcode】988. Smallest String Starting From Leaf

    题目如下: Given the root of a binary tree, each node has a value from 0 to 25representing the letters 'a ...

  6. 硬盘监控和分析工具:Smartctl

    https://linux.cn/article-4682-1.html Smartctl(S.M.A.R.T 自监控,分析和报告技术)是类Unix系统下实施SMART任务命令行套件或工具,它用于打印 ...

  7. vue基础七

    事件处理器 1.监听事件 可以用 v-on 指令监听 DOM 事件来触发一些 JavaScript 代码. <div id="example-1"> <butto ...

  8. java com.db4o 类

    <!--juan_zhai--> <dependency> <groupId>com.db4o</groupId> <artifactId> ...

  9. 88、使用tensorboard进行可视化学习,查看具体使用时间,训练轮数,使用内存大小

    ''' Created on 2017年5月23日 @author: weizhen ''' import os import tensorflow as tf from tensorflow.exa ...

  10. Linux命令 who

    who :显示当前登入系统的用户信息 显示的内容主要包括: 用户名,登录终端,上线时间,停留时间,动作,UID等 权限:所有使用者 语法: who  [option] ...[ file | arg1 ...