热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HBase封装easy-hbase设计实现

新增码云地址:https:gitee.comhanmov5mop-hbase-template一、写在前面业务架构用到HBase,但由于某些不可名状原因,没有用phoniex

新增码云地址: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的相关属性 
package com.gaoxin.mop.annotation;

import java.lang.annotation.*;

/**
 * Author: Mr.tan
 * Date:  2017/08/18
 * 

* used on the field associate to the column from the hbase *

*/ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface HBaseColumn { String family() default ""; String column(); boolean exist() default true; }

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

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

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

  •  RowKey:field注解,用于注解po中的rowKey,若po中的属性不为rowkey值的话,需手动指定这个注解,否则将会默认field为rowkey
package com.gaoxin.mop.annotation;

import java.lang.annotation.*;

/**
 * Author: Mr.tan
 * Date:  2017/08/18
 * 

* used on the field associate to the rowkey from the hbase *

*/ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface RowKey { }
  •  ColumnInfo:封装最基础的单元格类,columnFamily,column和对应的value
package com.gaoxin.mop.bean;


import com.gaoxin.mop.constants.HBaseConstant;
import org.apache.hadoop.hbase.filter.CompareFilter;

/**
 * Author: Mr.tan
 * Date:  2017/08/18
 * 

* the base entity contains columnFamily and column、value、op * default value String.class,others set customize valueClass * used on limit the back columns and filter values *

*/ public class ColumnInfo { private String columnFamily; private String column; private String value; private CompareFilter.CompareOp compareOperator; private Class valueClass; public ColumnInfo() { } public ColumnInfo(String column) { this(HBaseConstant.DEFAULT_FAMILY, column, CompareFilter.CompareOp.EQUAL); } public ColumnInfo(String columnFamily, String column, CompareFilter.CompareOp compareOperator) { this.columnFamily = columnFamily; this.column = column; this.compareOperator = compareOperator; } public ColumnInfo(String columnFamily, String column, CompareFilter.CompareOp compareOperator,Class valueClass) { this(columnFamily, column, compareOperator); this.valueClass = valueClass; } public ColumnInfo(String column, String value) { this(HBaseConstant.DEFAULT_FAMILY, column, value, CompareFilter.CompareOp.EQUAL); } public ColumnInfo(String columnFamily, String column, String value) { this(columnFamily, column, value, CompareFilter.CompareOp.EQUAL); } public ColumnInfo(String columnFamily, String column, String value, CompareFilter.CompareOp compareOperator) { this(columnFamily, column, compareOperator); this.value = value; } public String getColumnFamily() { return columnFamily; } public CompareFilter.CompareOp getCompareOperator() { return compareOperator; } public void setCompareOperator(CompareFilter.CompareOp compareOperator) { this.compareOperator = compareOperator; } public void setColumnFamily(String columnFamily) { this.columnFamily = columnFamily; } public String getColumn() { return column; } public void setColumn(String column) { this.column = column; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public Class getValueClass() { return valueClass; } public void setValueClass(Class valueClass) { this.valueClass = valueClass; } }

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

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

  • HBaseFactoryBean:HBase的连接初始化工厂Bean,用于初始化HBase连接
package com.gaoxin.mop.config;

import com.gaoxin.mop.constants.HBaseConstant;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HConnection;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * Author: Mr.tan
 * Date:  2017/08/18
 * 

* HBaseConstant 配置载入。初始化连接 */ @Component public class HBaseFactoryBean { private static HBaseFactoryBean factoryBean = null; private HBaseFactoryBean() { } public static HBaseFactoryBean getInstance() { if (factoryBean == null) { factoryBean = new HBaseFactoryBean(); } return factoryBean; } private static List connections; private List hbaseConfigs; public static void setConnections(List connections) { HBaseFactoryBean.cOnnections= connections; } public void setHbaseConfigs(List hbaseConfigs) { this.hbaseCOnfigs= hbaseConfigs; } public void initializeConnections() throws Exception { cOnnections= new ArrayList<>(); if (hbaseCOnfigs== null) { throw new RuntimeException("hbase config is null error"); } for (HBaseConfig config : hbaseConfigs) { Configuration cOnfiguration= HBaseConfiguration.create(); configuration.set("hbase.zookeeper.quorum", config.getZookeeperQuorum()); configuration.set("hbase.zookeeper.property.clientPort", StringUtils.isBlank(config.getZookeeperClientPort()) ? HBaseConstant.DEFAULT_HBASE_PORT : config.getZookeeperClientPort()); HConnection cOnnection= HConnectionManager.createConnection(configuration); connections.add(connection); } } public static HConnection getDefaultConnection() { return connections.get(0); } public static HConnection getSpecifyConnection(int index) { if (index > connections.size() - 1) { throw new RuntimeException("hbase connection is not exist"); } return connections.get(index); } }

  •  HBaseDao:HBase基础操作核心类
package com.gaoxin.mop.dao;


import com.gaoxin.mop.bean.ColumnInfo;

import java.util.List;

/**
 * Author: Mr.tan
 * Date:  2017/08/18
 */
public interface HBaseDao {

     T get(String tableName, String rowKey, List columns, List filters, Class clazz);

     T get(String tableName, String rowKey, Class clazz);

     T get(String tableName, String rowKey, List columns, Class clazz);

    String getSingleColumnValue(String tableName, String rowKey, String column);

     T getSingleColumnValue(String tableName, String rowKey, String column, Class clazz);

    List getRowKeys(String tableName);

    List getRowKeys(String tableName, String startRow, String endRow);

    List getRowKeys(String tableName, String startRow, String endRow, Integer pageSize, String separate, Integer index);

    List getRowKeys(String tableName, String startRow, String endRow, Integer pageSize, String separate);

    List getRowKeys(String tableName, String startRow, String endRow, Integer pageSize);

    List getRowKeysByPrefix(String tableName, String prefix);

    List getRowKeysByPrefix(String tableName, String startRow, String endRow, String prefix);

    List getColumns(String tableName, String rowKey, String columnFamily, List columns, List filters);

    List getColumns(String tableName, String rowKey, List columns, List filters);

    List getColumns(String tableName, String rowKey, String columnFamily);

    List getColumns(String tableName, String rowKey);

     List getList(String tableName, List rowKeys, Class clazz);

     List getList(String tableName, List rowKeys,List columns, List filters, Class clazz);

     List getList(String tableName, Class clazz);

     List getList(String tableName, List columns, List filters, Class clazz);

     List getList(String tableName, List columns, List filters, String start, String end, Class clazz);

     List getPageList(String tableName, String startRow, String endRow, Integer pageSize, Class clazz);

    List getColumnsByPage(String tableName, String rowKey, Integer pageNo, Integer pageSize);

    List getColumnsByPage(String tableName, String rowKey, Integer pageNo, Integer pageSize, List columns, List filters);

     T getColumnObj(String tableName, String rowKey, String column,Class clazz);

     List getColumnObjList(String tableName, String rowKey, List columns,Class clazz);

     List getPageColumnObjList(String tableName, String rowKey, Integer pageNo,Integer pageSize,Class clazz);

     boolean put(String tableName, List objects);

     boolean put(String tableName, T object);

    boolean put(String tableName, String rowKey, String column, String value);

    boolean put(String tableName, String rowKey, ColumnInfo columnInfo);

    boolean put(String tableName, String rowKey, List columnInfos);

    boolean delete(String tableName, String rowKey);

    boolean delete(String tableName, String rowKey, List list);

    boolean delete(String tableName, String rowKey, ColumnInfo columnInfo);

    boolean delete(String tableName, String rowKey, String column);

    long addCounter(String tableName, String rowKey, String column, long num);
}

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

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


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
author-avatar
也许_枉然
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有