版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
大数据系列文章目录
Hbase的官网
目录- Hbase的基本简介
- Hbase的基本介绍
- Hbase的应用场景
- Hbase的发展历程
- Hbase的特点
- Hbase与RDBMS、HDFS 、Hive的区别
- Hbase的表模型
- Hbase的相关 *** 作-命令式
- Hbase的基础 *** 作命令
- Hbase高级shell管理命令
- Hbase的相关 *** 作_JavaAPI方式
- 需求说明
- 准备工作
- 需求一: 使用java代码创建表
- 需求二: 往表中插入一条数据
- 需求三:查看一条数据
- 需求四:删除一条数据
- 需求五:删除表
- 需求六:导入数据
- 需求七:查询数据 查询2020年6月份所有用户的用水量 : C1:RECORD_DATE
- NoSQL是一个通用术语,泛指一个数据库并不是使用SQL作为主要语言的非关系型数据库
- Hbase是BigTable的开源java版本。是建立在HDFS之上,提供高可靠性、高性能、列存储、可伸缩、实时读写NoSQL的数据库系统
- Hbase仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务
- 主要用来存储结构化和半结构化的松散数据
- Hbase查询数据功能很简单,不支持join等复杂 *** 作,不支持复杂的事务(行级的事务),从技术上来说,Hbase更像是一个「数据
存储」而不是「数据库」,因为Hbase缺少RDBMS中的许多特性,例如带类型的列、二级索引以及高级查询语言等 - Hbase中支持的数据类型:byte[]
- 与Hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加存储和处理能力,例如,把集群从10个节点扩展到20个节点,存储能力和处理能力都会加倍
- Hbase中的表一般有这样的特点
大:一个表可以有上十亿行,上百万列
面向列:面向列(族)的存储和权限控制,列(族)独立检索
稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏
- 对象存储
不少的头条类、新闻类的新闻、网页、图片存储在Hbase之中, 一些病毒公司的病毒库也是存储在Hbase中
- 时序数据
Hbase之上有openTSDB模块, 可以满足时序类场景的需求
- 推荐画像
用户画像, 是一个比较大的稀疏矩阵, 蚂蚁金服的风控就是构建在Hbase之上
- 时空数据
主要是轨迹, 气象网格之类, 滴滴打车的轨迹数据主要存在Hbase之中, 另外在所有大一点的数据量的车联网企业, 数据也是存储
在Hbase
- CubeDb OLAP
kylin 一个cube分析工具, 底层的数据就是存储在Hbase之中, 不少客户自己基于离线计算构建cube存储在hbase之中, 满足在线报表查询的需求
- 消息/订单
在电信领域、银行领域, 不少的订单查询底层的存储, 另外不少通信、消息同步的应用构建Hbase之上
- Feeds流
典型的应用就是xx朋友圈类型的应用, 用户可以随时发布新内容, 评论、点赞
- NewSQL
之上有Phoenix的插件, 可以满足二级索引, SQL的查询, 对接传统数据需要SQL非事务的需求
- 其他
Hbase的发展历程 Hbase的特点存储爬虫数据
海量数据备份
短网址
…………
-
强一致性读/写: Hbase不是“最终一致的”数据存储 , 它非常适合于诸如高速计数器聚合等任务
-
自动分块: Hbase表通过Region分布在集群上,随着数据的增长,区域被自动拆分和重新分布
-
自动RegionServer故障转移
-
Hadoop/HDFS集成: Hbase支持HDFS开箱即用作为其分布式文件系统
-
MapReduce : Hbase通过MapReduce支持大规模并行处理,将Hbase用作源和接收器
-
Java Client API: Hbase支持易于使用的 Java API 进行编程访问
-
Thrift/REST API
-
块缓存和布隆过滤器 : Hbase支持块Cache和Bloom过滤器进行大容量查询优化
-
运行管理: Hbase为业务洞察和JMX度量提供内置网页。
在Hbase中,数据存储在具有行和列的表中。这是看起来关系数据库(RDBMS)一样,但将Hbase表看成是多个维度的Map结构更容易理解
术语:
- 表(Table) : Hbase中数据都是以表形式来组织的, Hbase中的表由多个行组成
- 行键(row key):
Hbase中的行有一个rowkey(行键)和 一个或者多个列组成, 列的值与rowkey、列相关联
行在存储是按行键的字典序排序
行键的设计非常重要, 尽量让相关的行存储在一起
- 列(Column): Hbase中的列有列族(column family) 和列限定符(列名)(Column Qualifier)组成
表示如下 : 列族名:列限定符 例如: C1:USER_ID C1:SEX
- 列族(Column Family):
出于性能原因, 列族将一组列及其值组织在一起
每个列族都有一组存储属性: 例如 是否应该换成在内存中, 数据如何被压缩等
表中的每一行都有相同的列族, 但在列族中不存储任何内容
所有的列族的数据全部都存储在一块(文件系统HDFS)
Hbase官方建议所有的列族保持一样的列, 并且将同一类的列放在一个列族中
- 列标识符(Column Qualifier)
列族中包含一个个的列限定符, 这样可以为存储的数据提供索引
列族在创建表的时候是固定的, 但列限定符是不做限制的
不同的列可能会存在不同的列标识符
- 单元格(Cell): 单元格是行、列族和列限定符的组合,包含一个值和一个时间戳, 数据以二进制存储
- 版本号(verson num): 每条数据都会有版本号的概念
每条数据都可以有多个版本号, 默认值为系统时间戳, 类型为Long
- 时间戳(timeStamp): 每个数据都会有时间戳的概念
Hbase的相关 *** 作-命令式在向Hbase插入更新数据的时候, Hbase默认会将当前 *** 作的时间记录下来, 当然也可以人为指定时间
不同版本的数据按照时间倒序排序, 即最新的数据排在最前面
我们可以以shell的方式来维护和管理Hbase。例如:执行建表语句、执行增删改查 *** 作等等
Hbase的基础 *** 作命令1、进入Hbase客户端命令 *** 作界面
bin/hbase shell
2、查看帮助命令
hbase(main):001:0> help
3、查看当前数据库中有那些表
hbase(main):002:0> list
4、创建一张表
hbase(main):010:0> create 'user', 'info', 'data' 或者 hbase(main):010:0> create 'user', {NAME => 'info', VERSIONS => '3'},{NAME => 'data'}
5、添加数据 *** 作
向user表中插入信息,row key为rk0001,列族info中添加name列标示符,值为zhangsan hbase(main):011:0> put 'user', 'rk0001', 'info:name', 'zhangsan' 向user表中插入信息,row key为rk0001,列族info中添加gender列标示符,值为female hbase(main):012:0> put 'user', 'rk0001', 'info:gender', 'female' 向user表中插入信息,row key为rk0001,列族info中添加age列标示符,值为20 hbase(main):013:0> put 'user', 'rk0001', 'info:age', 20 向user表中插入信息,row key为rk0001,列族data中添加pic列标示符,值为picture hbase(main):014:0> put 'user', 'rk0001', 'data:pic', 'picture
6、查询数据 *** 作
6.1、通过rowkey进行查询 获取user表中row key为rk0001的所有信息 hbase(main):015:0> get 'user', 'rk0001' 6.2 、查看rowkey下面的某个列族的信息 获取user表中row key为rk0001,info列族的所有信息 hbase(main):016:0> get 'user', 'rk0001', 'info' 6.3 、查看rowkey指定列族指定字段的值 获取user表中row key为rk0001,info列族的name、age列标示符的信息 hbase(main):017:0> get 'user', 'rk0001', 'info:name', 'info:age’ 6.4 、查看rowkey指定多个列族的信息 获取user表中row key为rk0001,info、data列族的信息 hbase(main):018:0> get 'user', 'rk0001', 'info', 'data' 或者你也可以这样写 hbase(main):019:0> get 'user', 'rk0001', {COLUMN => ['info', 'data']} 或者你也可以这样写,也行 hbase(main):020:0> get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic’]} 6.5 、指定rowkey与列值查询 获取user表中row key为rk0001,cell的值为zhangsan的信息 hbase(main):030:0> get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"} 6.6、查询所有数据 : 查询user表中的所有信息 scan 'user' scan 'user' , {FORMATTER => 'toString’} scan 'user' , {LIMIT => 3,FORMATTER => 'toString’} 6.7、列族查询: 查询user表中列族为info的信息 scan 'user', {COLUMNS => 'info'} scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5} scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3} 6.8 、多列族查询: 查询user表中列族为info和data的信息 scan 'user', {COLUMNS => ['info', 'data']} scan 'user', {COLUMNS => ['info:name', 'data:pic']} 6.9 、指定列族与某个列名查询 查询user表中列族为info、列标示符为name的信息 scan 'user', {COLUMNS => 'info:name’} 6.10、指定列族与列名以及限定版本查询 查询user表中列族为info、列标示符为name的信息,并且版本最新的5个 scan 'user', {COLUMNS => 'info:name', VERSIONS => 5} 6.11、指定多个列族与按照数据值模糊查询 查询user表中列族为info和data且列标示符中含有a字符的信息 scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"} 6.12、rowkey的范围值查询 查询user表中列族为info,rk范围是[rk0001, rk0003)的数据 scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'} 6.13、指定rowkey模糊查询 查询user表中row key以rk字符开头的 scan 'user',{FILTER=>"PrefixFilter('rk')"} 6.14、指定数据范围值查询 查询user表中指定范围的数据 scan 'user', {TIMERANGE => [1392368783980, 1392380169184]} 过滤器的查询地址: http://hbase.apache.org/2.2/devapidocs/index.html
7、更新数据 *** 作
1、更新数据值 更新 *** 作同插入 *** 作一模一样,只不过有数据就更新,没数据就添加 2、更新版本号 将user表的f1列族版本号改为5 hbase(main):050:0> alter 'user', NAME => 'info', VERSIONS => 5
8、删除数据以及删除表 *** 作
1、指定rowkey以及列名进行删除
删除user表row key为rk0001,列标示符为info:name的数据
hbase(main):045:0> delete ‘user’, ‘rk0001’, ‘info:name’
2、指定rowkey,删除一整行数据hbase(main):045:0>deleteall ‘user’, 'rk0001’
注意:
(1)deleteall 是在 hbase 2.0版本后出现的, 在2.0版本之前, 只需要使用delete这个命令即可完成所有的删除数据工作,
(2)delete删除数据时候, 只会删除最新版本的数据, 而deleteall 直接将对应数据的所有的历史版本全部删除
3、删除一个列族: alter ‘user’, NAME => ‘info’, METHOD => 'delete’ 或 alter
‘user’, ‘delete’ => ‘info’
4、清空表数据 hbase(main):017:0> truncate ‘user’
5、删除表 首先需要先让该表为disable状态,使用命令: hbase(main):049:0> disable ‘user’
然后才能drop这个表,使用命令:hbase(main):050:0> drop ‘user’ (注意:如果直接drop表,会报错:Drop
the named table. Table must first be disabled)
9、统计一张表有多少行数据
Hbase高级shell管理命令hbase(main):053:0> count ‘user’
- status 显示服务器状态 “例如:hbase(main):058:0> status ‘node01’
- whoami : 显示Hbase当前用户,例如: hbase> whoami
- list : 显示当前所有的表
- count: 统计指定表的记录数,例如: hbase> count ‘user’
- describe : 展示表结构信息
- exists: 检查表是否存在,适用于表量特别多的情况
- is_enabled、is_disabled: 检查表是否启用或禁用
- alter : 该命令可以改变表和列族的模式,
例如: 为当前表增加列族: hbase> alter ‘user’, NAME => ‘CF2’, VERSIONS => 2
为当前表删除列族: hbase(main):002:0> alter ‘user’, ‘delete’ => ‘CF2’ - disable/enable : 禁用一张表/启用一张表
- drop : 删除一张表,记得在删除表之前必须先禁用
- truncate : 禁用表-删除表-创建表
- 某某自来水公司,需要存储大量的缴费明细数据。以下截取了缴费明细的一部分内容
- 因为缴费明细的数据记录非常庞大,该公司的信息部门决定使用Hbase来存储这些数据。并且,他们希望能够 通过Java程序来访问这些数据。
创建IDEA Maven 项目
- 导入相关pom依赖
需求一: 使用java代码创建表aliyun http://maven.aliyun.com/nexus/content/groups/public/ true false never org.apache.hbase hbase-client2.1.0 commons-io commons-io2.6 junit junit4.12 test org.testng testng6.14.3 test org.apache.maven.plugins maven-compiler-plugin3.1 1.8
- 创建一个名为WATER_BILL的表,包含一个列蔟C1。
// 1) 如何创建表: WATER_BILL 列族为C1 和 C2 @Test public void test01() throws Exception { //1. 创建Java 连接hbase的连接对象Configuration conf = HbaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "node1:2181,node2:2181,node3:2181"); Connection hbaseConn = ConnectionFactory.createConnection(conf); //2. 根据连接对象获取相关的管理对象: admin | Table Admin admin = hbaseConn.getAdmin(); //3 . 执行相关的 *** 作: //3.1: 判断目标表是否存在, 如果不存在 才创建表 : 如果存在返回true 如果不存在 false TableName tableName = TableName.valueOf("WATER_BILL"); boolean flag = admin.tableExists(tableName); if (!flag) { // 说明表不存在: //3.3: 创建表的构建器 TableDescriptorBuilder descriptorBuilder = TableDescriptorBuilder.newBuilder(tableName); List需求二: 往表中插入一条数据families = new ArrayList<>(); families.add(ColumnFamilyDescriptorBuilder.newBuilder("C1".getBytes()).build()); //families.add(ColumnFamilyDescriptorBuilder.newBuilder("C2".getBytes()).build()); //3.4: 在表构建器中添加 表的列族信息 descriptorBuilder.setColumnFamilies(families); //3.5: 通过表构建器, 构建表信息对象 TableDescriptor desc = descriptorBuilder.build(); //3.2: 执行创建表的 *** 作 admin.createTable(desc); } //4. 释放资源admin.close(); hbaseConn.close(); }
@Test public void test02() throws Exception { //1. 根据连接工厂构建hbase的连接对象 Configuration conf = HbaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "node1:2181,node2:2181,node3:2181"); Connection hbaseConn = ConnectionFactory.createConnection(conf); //2. 根据连接对象, 获取相关的管理对象: admin table Table table = hbaseConn.getTable(TableName.valueOf("WATER_BILL")); //3. 执行相关的 *** 作 Put put = new Put("4944191".getBytes()); put.addColumn("C1".getBytes(), "name".getBytes(), " 登 卫 红 ".getBytes()); put.addColumn("C1".getBytes(), "address".getBytes(), "贵州省铜仁市德江县7单元267室".getBytes()); put.addColumn("C2".getBytes(), "sex".getBytes(), "男".getBytes()); table.put(put); //4. 释放资源 table.close(); hbaseConn.close(); }
- 优化 *** 作: 抽取公共方法
private Connection hbaseConn; private Admin admin; private Table table; private String tableName = "WATER_BILL"; @Before public void before() throws Exception { //1. 根据连接工厂构建hbase的连接对象 Configuration conf = HbaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "node1:2181,node2:2181,node3:2181"); hbaseConn = ConnectionFactory.createConnection(conf); //2. 根据连接对象, 获取相关的管理对象: admin table admin = hbaseConn.getAdmin(); table = hbaseConn.getTable(TableName.valueOf(tableName)); } @After public void after() throws Exception { //4. 释放资源 table.close(); admin.close(); hbaseConn.close(); }需求三:查看一条数据
//6. 查询rowkey 为 9990611 的数据 @Test public void test06() throws Exception { //3. 执行相关的 *** 作 //3.1: 执行查询 Get get = new Get("9990611".getBytes()); Result result = table.get(get); //3.2: 处理结果集 List需求四:删除一条数据cellList = result.listCells(); // 获取 这一行所有的单元格 for (Cell cell : cellList) { // 单元格: rowkey + 列族+ 列名+ 列值 byte[] rowkeyBytes = CellUtil.cloneRow(cell); byte[] familyBytes = CellUtil.cloneFamily(cell); byte[] qualifierBytes = CellUtil.cloneQualifier(cell); byte[] valueBytes = CellUtil.clonevalue(cell); String rowkey = Bytes.toString(rowkeyBytes); String family = Bytes.toString(familyBytes); String qualifier = Bytes.toString(qualifierBytes); if (qualifier.equals("NUM_CURRENT") || qualifier.equals("NUM_PREVIOUS") || qualifier.equals("TOTAL_MONEY") || qualifier.equals("NUM_USAGE")) { Double value2 = Bytes.toDouble(valueBytes); System.out.println("rowkey为:" + rowkey + "; family:" + family + "; qualifier:" + qualifier + "; value:" + value2); } else { String value1 = Bytes.toString(valueBytes); System.out.println("rowkey为:" + rowkey + "; family:" + family + "; qualifier:" + qualifier + "; value:" + value1); } } } |
//3. 删除数据: 4944191 @Test public void test03() throws Exception { //3. 执行相关 *** 作: Delete delete = new Delete("4944191".getBytes()); delete.addFamily("C2".getBytes()); delete.addColumn("C1".getBytes(), "name".getBytes()); table.delete(delete); }需求五:删除表
//4. 删除表: @Test public void test04() throws Exception { //3. 执行相关 *** 作 if (admin.isTableEnabled(TableName.valueOf(tableName))) { admin.disableTable(TableName.valueOf(tableName)); } admin.deleteTable(TableName.valueOf(tableName)); }需求六:导入数据
- 在资料中,有一份10W的抄表数据文件,我们需要将这里面的数据导入到Hbase中
在Hbase中,有一个import的MapReduce作业,可以专门用来将数据文件导入到Hbase中
- 用法
hbase org.apache.hadoop.hbase.mapreduce.import 表名 HDFS数据文件路径
开始导入:
- 将资料中数据文件上传到Linux中
- 再将文件上传到hdfs中
hadoop fs -mkdir -p /water_bill/output_ept_10W hadoop fs -put part-m-00000_10w /water_bill/output_ept_10W
执行命令:
hbase org.apache.hadoop.hbase.mapreduce.import WATER_BILL /water_bill/output_ept_10W
注意: 一定要启动yarn集群
hbase org.apache.hadoop.hbase.mapreduce.Export WATER_BILL /water_bill/output_ept_10W_export需求七:查询数据 查询2020年6月份所有用户的用水量 : C1:RECORD_DATE
@Test public void test05() throws Exception { //3. 执行相关的 *** 作: scan 扫描 Scan scan = new Scan(); //3.1: 封装过滤条件 SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter("C1".getBytes(), "RECORD_DATE".getBytes(), CompareOperator.GREATER_OR_EQUAL, new BinaryComparator("2020-06- 01".getBytes())); SingleColumnValueFilter singleColumnValueFilter2 = new SingleColumnValueFilter("C1".getBytes(), "RECORD_DATE".getBytes(), CompareOperator.LESS, new BinaryComparator("2020-07-01".getBytes())); FilterList filterList = new FilterList(); filterList.addFilter(singleColumnValueFilter1); filterList.addFilter(singleColumnValueFilter2); scan.setFilter(filterList); //3.2: 执行扫描 *** 作 返回多行结果数据 ResultScanner results = table.getScanner(scan); //3.3: 处理结果集 for (Result result : results) { ListcellList = result.listCells(); // 获取这一行所有的单元格 for (Cell cell : cellList) { // 单元格: rowkey + 列族+ 列名+ 列值 byte[] rowkeyBytes = CellUtil.cloneRow(cell); byte[] familyBytes = CellUtil.cloneFamily(cell); byte[] qualifierBytes = CellUtil.cloneQualifier(cell); byte[] valueBytes = CellUtil.clonevalue(cell); String rowkey = Bytes.toString(rowkeyBytes); String family = Bytes.toString(familyBytes); String qualifier = Bytes.toString(qualifierBytes); if (qualifier.equals("NUM_CURRENT") || qualifier.equals("NUM_PREVIOUS") || qualifier.equals("TOTAL_MONEY") || qualifier.equals("NUM_USAGE")) { Double value = Bytes.toDouble(valueBytes); System.out.println("rowkey为:" + rowkey + "; family:" + family + "; qualifier:" + qualifier + "; value:" + value); } else { String value = Bytes.toString(valueBytes); System.out.println("rowkey为:" + rowkey + "; family:" + family + "; qualifier:" + qualifier + "; value:" + value); } } System.out.println(" "); } } |
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)