大数据之路系列之HBASE(06)

大数据之路系列之HBASE(06)



一、hbase是什么?

1.HBASE的特点

hbase是列储存数据库,更适合OLTP场景,能实现事务,行级别的增删、更新操作。它有以下几个特点

  • 高可靠——HBASE集群支撑多个节点,集群可靠性高;数据在hdfs上,数据可靠性高。
  • 高性能——HBASE在几十亿数据数据可以实现毫秒级别的查询
  • 面向列——HBASE的存储是列存储方式
  • 可伸缩——HBASE的节点可以方便增加或者删除

2.HBASE的增删改查

hdfs不支持增删改查,HBASE依赖的hdfs,为什么HBASE可以支持增删改查呢?
原因是HBASE自己封装了一个中间层,对于删除的数据,打上标记,查询进行了过滤。

二、行存储数据库

每一行作为一个存储单元进行存储
传统的MySQL、Oracle都是行存储数据库,使用sql进行查询。
select … from … where … 其中的where就是进行的行数过滤。
对于行数据库查询效率来说,查询的列数量影响不大;扫描的行数是决定效率的关键。即便只需要一列的数据,也是需要扫描所有行和所有列然后在对列进行过滤。

三、列存储数据库

每一列作为一个存储单元进行存储
列存储数据库对于查询某列的数据是快速的。但是,查询所有行就很慢了。
在大数据实际中更多的是查询某一列数据,或者是少数几列。所以说列存储更合适。
在这里插入图片描述

四、HBase典型应用场景

在这里插入图片描述

  • 适合半结构化非结构化数据——比如新闻,标签字段不固定有可能1个有可能10个,对于传统数据库,只能是放在一个字段里面拼接,但是这样不利于取;放10个字段中,又会导致冗余。HBASE可以方便的添加字段。
  • 纪录稀疏——HBASE中null值不会存储,这样这样节约空间又能提高读性能
  • 多版本数据——HBASE自带历史存储数据
  • 超大数据量——只需要加机器即可,HBase会自动水平切分扩展,跟Hadoop的无缝集成保障了其数据可靠性(HDFS)和海量数据分析的高性能(MapReduce)。

五、HBase常用的shell命令

1.DDL命令

命令	解释
create	创建表
list	列出所有表
disable / is_disabled	禁用表/验证表是否被禁用
enable / is_enabled	启用表/验证表是否已启用
desc	查看表的详细信息
alter	修改表结构
exists	验证表是否存在
drop / truncate	删除表/清空表(删除重建)
  • 创建表命令:
    create ‘表名’,‘列族1’,‘列族2’,'列族N’
    注意:单引号不能少,只能使用单引号,不能使用双引号。
    例子:create ‘student’,‘info’,‘level’
    解释:创建了一张名为student的表,表中有两个列族,分别是info和level。create后面的第一个参数是表名,后面的都是列族的名称
    注意:创建表时不能指定列,只能指定列族。

  • 列出所有表
    命令:list

  • 禁用表/验证表是否被禁用
    禁用表
    命令:disable ‘表名’

  • 验证表是否被禁用
    命令:is_disabled '表名’
    解释:返回true表示此表被禁用,此时这个表不能被操作,因为表中的数据是存在Region中的,当Region中的数据达到一定量级的时候会进行分裂,产生多个Region,多个Region会分到其它节点上面。这个时候,数据是不能被操作的,所以会有disabled这个状态。

  • 启用表/验证表是否已启用
    启用表
    命令:enable '表名’
    解释:当表被手工禁用之后,想要恢复使用,需要启动表

  • 禁用表/验证表是否被禁用
    禁用表
    命令:disable ‘表名’

  • 查看表的详细信息
    命令:desc ‘表名’ 或者 desc ‘表名’

  • 修改表结构(修改列族)
    使用alter命令可以完成更改列族参数信息、增加列族、删除列族以及更改表等操作,在这里主要演示一下增加列族、修改列族和删除列族
    修改列族的参数信息,例如:修改列族的版本
    通过desc命令可以看到student表中列族的版本个数:
    NAME => ‘info’, VERSIONS => ‘1’
    NAME => ‘level’, VERSIONS => ‘1’
    alter ‘student’,{NAME=>‘level’,VERSIONS=>‘3’}
    这里显示的这两个列族版本个数都是1,说明这两个列族中的所有列的值只能保存最新的1份数据,如果想要保存level列族中所有列的最近3个数据历史版本,可以这样操作:
    注意:1.如果数据很大的时候,修改会很长时间。2.这个版本是和列族绑定的,不是和某一列绑定的。

  • 修改表结构(增加列族)
    在已存在的表的基础之上增加列族,在这我们向student表中增加一个列族:about
    alter ‘student’,‘about’

  • 修改表结构(删除列族)
    删除表中已有的列族,在这我们删除student中的about这个列族
    alter ‘student’,{NAME=>‘about’,METHOD=>‘delete’}
    注意:HBase 中的表至少要包含一个列族,因此当表中只有一个列族时,无法将其删除。

  • 验证表是否存在
    命令:exists '表名’ exists ‘student’
    解释:表存在返回true,否则返回false

  • 删除表
    命令:drop ‘表名’ drop ‘t1’
    -清空表
    清空表其实包含了两步,删除+重建
    命令:truncate ‘表名’
    truncate ‘t2’

2.增删改查命令

命令	解释
put	添加数据/修改数据
get	查看数据
count	查看表中数据总条数
scan	扫描表中的数据
delete / deleteall	删除数据
  • 添加数据/修改数据
    HBase中没有insert方法,它也属于key-value类型的NoSQL数据库,类似于HashMap这种数据结构,所以它提供了put方法添加数据
    命令:put ‘表名’,‘Rowkey’,‘列族:列’,'value’
    添加2条数据,rowkey分别为:jack和tom
hbase(main):001:0> put 'student','jack','info:sex','man'
Took 0.8415 seconds                                                   
hbase(main):002:0> put 'student','jack','info:age','22'
Took 0.0295 seconds                                                   
hbase(main):003:0> put 'student','jack','level:class','A'
Took 0.0300 seconds                                                   
hbase(main):004:0> put 'student','tom','info:sex','woman'
Took 0.0286 seconds                                                   
hbase(main):005:0> put 'student','tom','info:age','20'
Took 0.0275 seconds                                                   
hbase(main):006:0> put 'student','tom','level:class','B'
Took 0.0228 seconds 

注意:HBase中没有修改方法,重复执行put就是修改操作了。put操作在执行的时候,如果指定的数据已经存在,则更新,否则就新增。

  • 查看数据
    查看数据的时候有这么几种用法
    命令:get ‘表名’,'Rowkey’
    命令:get ‘表名’,‘Rowkey’,'列族’
    命令:get ‘表名’,‘Rowkey’,‘列族:列’

    查询student中rowkey等于jack的所有列族中的数据
    get ‘student’,‘jack’

    查询student中rowkey等于jack的info列族中的数据
    get ‘student’,‘jack’,‘info’

    查询student中rowkey等于jack的info列族中的age列的数据
    get ‘student’,‘jack’,‘info:age’

  • 查看表中数据总条数
    命令:count ‘表名’ count ‘student’

  • 扫描表中的数据
    命令:scan '表名’ scan ‘student’
    扫描表中的所有数据

  • 删除数据
    delete有这么几种用法:
    命令:delete ‘表名’,‘Rowkey’,'列族:列’
    命令:delete ‘表名’,‘Rowkey’,‘列族:列’,时间戳

    删除指定Rowkey中指定列族中指定列的数据
    delete ‘student’,‘jack’,‘info:age’

    删除指定Rowkey中指定列族中指定列中时间戳小于2的数据
    delete ‘student’,‘jack’,‘info:age’,2
    注意:delete 操作并不会马上删除数据,只会将对应的数据打上删除标记,只有在HBase底层合并数据时,数据才会被真正删除。

3.HBase的namespace(命名空间)

  • HBase的命名空间相当于MySQL中的Database
    HBase默认有2个命名空间:分别是hbase和default
    其中hbase存放系统表,default是存放用户表
    使用list_namespace命令可以查看所有的命名空间,我们创建的表默认在default这个命名空间里面

  • 可以选择创建一个新的namespace
    create_namespace ‘n1’

  • 在创建表的时候可以选择创建到n1这个namespace中,如何实现呢?
    使用这种格式即可:‘命名空间名称:表名’
    针对default这个命名空间,在使用的时候可以省略不写
    create ‘n1:t1’,‘info’,‘level’

  • 如果只想查看n1这个命名空间中的表,如何实现呢?
    可以使用命令list_namespace_tables
    list_namespace_tables ‘n1’

4.HBase JavaAPI的使用

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>2.2.7</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.10</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.10</version>
</dependency>


package com.imooc.hbase;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 操作HBase
 * 表:创建、删除
 * 数据:增、删、改、查
 * Created by xuwei
 */
public class HBaseOp {
    public static void main(String[] args) throws Exception {
        //获取HBase数据库连接
        Connection conn = getConn();
        //添加数据
        //put(conn);

        //查询数据
        //get(conn);

        /**
         * 查询多版本的数据
         * 当列的值有多个历史版本的时候
         *
         * 修改列族info的最大历史版本存储数量
         * alter 'student',{NAME=>'info',VERSIONS=>3}
         *
         * 然后再执行下面命令,向列族info中的age列中添加几次数据,实现多历史版本数据存储
         * put 'student','laowang','info:age','19'
         * put 'student','laowang','info:age','20'
         *
         */
        //getMoreVersion(conn);

        //修改数据--同添加数据

        //删除数据
        //delete(conn);

        //==============================分割线======================

        //获取管理权限,负责对HBase中的表进行操作(DDL操作)
        Admin admin = conn.getAdmin();
        //创建表
        //createTable(admin);

        //删除表
        //deleteTable(admin);

        //关闭admin连接
        admin.close();
        //关闭连接
        conn.close();

    }

    /**
     * 删除表
     * @param admin
     * @throws IOException
     */
    private static void deleteTable(Admin admin) throws IOException {
        //删除表,先禁用表
        admin.disableTable(TableName.valueOf("test"));
        admin.deleteTable(TableName.valueOf("test"));
    }

    /**
     * 创建表
     * @param admin
     * @throws IOException
     */
    private static void createTable(Admin admin) throws IOException {
        //指定列族信息
        ColumnFamilyDescriptor familyDesc1 = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("info"))
                //在这里可以给列族设置一些属性
                .setMaxVersions(3)//指定最多存储多少个历史版本数据
                .build();
        ColumnFamilyDescriptor familyDesc2 = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("level"))
                //在这里可以给列族设置一些属性
                .setMaxVersions(2)//指定最多存储多少个历史版本数据
                .build();
        ArrayList<ColumnFamilyDescriptor> familyList = new ArrayList<ColumnFamilyDescriptor>();
        familyList.add(familyDesc1);
        familyList.add(familyDesc2);

        //获取TableDescriptor对象
        TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf("test"))//指定表名
                .setColumnFamilies(familyList)//指定列族
                .build();
        //创建表
        admin.createTable(desc);
    }

    /**
     * 删除数据
     * @param conn
     * @throws IOException
     */
    private static void delete(Connection conn) throws IOException {
        //获取Table,指定要操作的表名,表需要提前创建好
        Table table = conn.getTable(TableName.valueOf("student"));
        //指定Rowkey,返回Delete对象
        Delete delete = new Delete(Bytes.toBytes("laowang"));
        //【可选】可以在这里指定要删除指定Rowkey数据哪些列族中的列
        //delete.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"));

        table.delete(delete);
        //关闭table连接
        table.close();
    }

    /**
     * 查询多版本的数据
     * @param conn
     * @throws IOException
     */
    private static void getMoreVersion(Connection conn) throws IOException {
        //获取Table,指定要操作的表名,表需要提前创建好
        Table table = conn.getTable(TableName.valueOf("student"));
        //指定Rowkey,返回Get对象
        Get get = new Get(Bytes.toBytes("laowang"));
        //读取cell中的所有历史版本数据,不设置此配置的时候默认只读取最新版本的数据
        //可以通过get.readVersions(2)来指定获取多少个历史版本的数据
        get.readAllVersions();

        Result result = table.get(get);

        //获取指定列族中指定列的所有历史版本数据,前提是要设置get.readAllVersions()或者get.readVersions(2),否则只会获取最新数据
        List<Cell> columnCells = result.getColumnCells(Bytes.toBytes("info"), Bytes.toBytes("age"));
        for (Cell cell: columnCells) {
            byte[] value_bytes = CellUtil.cloneValue(cell);
            long timestamp = cell.getTimestamp();
            System.out.println("值为:"+new String(value_bytes)+",时间戳:"+timestamp);
        }
        //关闭table连接
        table.close();
    }

    /**
     * 查询数据
     * @param conn
     * @throws IOException
     */
    private static void get(Connection conn) throws IOException {
        //获取Table,指定要操作的表名,表需要提前创建好
        Table table = conn.getTable(TableName.valueOf("student"));
        //指定Rowkey,返回Get对象
        Get get = new Get(Bytes.toBytes("laowang"));
        //【可选】可以在这里指定要查询指定Rowkey数据哪些列族中的列
        //如果不指定,默认查询指定Rowkey所有列的内容
        get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"));
        get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("sex"));

        Result result = table.get(get);
        //如果不清楚HBase中到底有哪些列族和列,可以使用listCells()获取所有cell(单元格),cell对应的是某一列的数据
        List<Cell> cells = result.listCells();
        for (Cell cell : cells) {
            //注意:下面获取的信息都是字节类型的,可以通过new String(bytes)转为字符串
            //列族
            byte[] famaily_bytes = CellUtil.cloneFamily(cell);
            //列
            byte[] column_bytes = CellUtil.cloneQualifier(cell);
            //值
            byte[] value_bytes = CellUtil.cloneValue(cell);
            System.out.println("列族:"+new String(famaily_bytes)+",列:"+new String(column_bytes)+",值:"+new String(value_bytes));
        }
        System.out.println("==============================================");
        //如果明确知道HBase中有哪些列族和列,可以使用getValue(family,qualifier)直接获取指定列族中指定列的数据
        byte[] age_bytes = result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age"));
        System.out.println("age列的值:"+new String(age_bytes));
        //关闭table连接
        table.close();
    }

    /**
     * 添加数据
     *
     * @param conn
     * @throws IOException
     */
    private static void put(Connection conn) throws IOException {
        //获取Table,指定要操作的表名,表需要提前创建好
        Table table = conn.getTable(TableName.valueOf("student"));
        //指定Rowkey,返回put对象
        Put put = new Put(Bytes.toBytes("laowang"));
        //向put对象中指定列族、列、值
        //put 'student','laowang','info:age','18'
        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"), Bytes.toBytes("18"));
        //put 'student','laowang','info:sex','man'
        put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("sex"), Bytes.toBytes("man"));
        //put 'student','laowang','level:class','A'
        put.addColumn(Bytes.toBytes("level"), Bytes.toBytes("class"), Bytes.toBytes("A"));
        //向表中添加数据
        table.put(put);
        //关闭table连接
        table.close();
    }

    /**
     * 获取连接
     *
     * @return
     * @throws IOException
     */
    private static Connection getConn() throws IOException {
        //获取配置
        Configuration conf = HBaseConfiguration.create();
        //指定HBase使用的zk的地址,多个用逗号隔开
        conf.set("hbase.zookeeper.quorum", "bigdata01:2181,bigdata02:2181,bigdata03:2181");
        //指定HBase在hdfs上的根目录
        conf.set("hbase.rootdir", "hdfs://bigdata01:9000/hbase");
        //创建HBase连接,负责对HBase中的数据的一些增删改查(DML操作)
        return ConnectionFactory.createConnection(conf);
    }
}



总结

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

居高声自远,非是藉秋风

千山万水总是情,赏个一块行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值