hbase学习----基本操作

断更只是为了更好的出现,这里带来最详细的hbase的笔记。这里我们详细的来看hbase的教学,今天这一章节主要对hbase做了基本的介绍和一些基本的使用。

hbase的简介

一、Hadoop和Hbase

  • HBase是基于Hadoop集群之上来搭建的
  • Hadoop有一些局限性的:
    • 做一些批量的数据处理,吞吐量比较高,但是它对随机查询、实时操作性能是不行的
  • HBase是NoSQL数据库的一种,它跟传统的RDBMS有很大的差别
  • 不支持JOIN的,摒弃了关系型模型,而且在HBase中只有一种数据类型:byte[]
  • HBase可以用来存储非常大的表,上亿行的数据、有超过百万列,而且它常用在实时数据处理中。因为它的读写是很快的。

二、HBase的应用场景

  • HBase只要有海量数据存储,而且需要快速的写入以及快速的读取场景,就很适合HBase
  • 但要记住NoSQL的特点:对事务的支持性较弱的
  • 可以用来存储爬虫的数据、点赞/转发、银行转账订单…

三、Hbase对于RDBMS对比Hive

  • RDBMS是关系型数据库支持join、ACID、有schema(创建表的时候必须要指定有哪些列、列是什么类型)…、支持二级索引
  • HBase不支持join的、也不支持ACID、对事务支持有限,无schema(创建表的时候,无需去指定列、列类型)、原生就支持分布式存储的,所以可以用来存储海量数据,同时也兼顾了快速查询、写入的功能

对比Hive:

  • Hive主要用于OLAP,HBase主要用于OLTP,HBase是可以直接接入到业务系统的

四、HBase的安装

安装的过程看我的另外一个
注意:

  • HBase依赖于:ZooKeeper、HDFS,在启动HBase之前必须要启动ZK、HDFS,否则HBase无法启动

五、HBase的数据模型

  • HBase中是有表的概念的
  • 一个表中可以包含多个列族
  • 一个列族可以包含很多的列
  • 每一个列对应的单元格(值、timestamp)

Hbase的一些操作

创建表

  • HBase是没有schema的,就是在创建表的时候不需要指定表中有哪些列,只需要指定有多少个列蔟
create "表名","列蔟1", "列蔟2"

删除表

	删除表之前我们首先要禁用表,如果不禁用表这里会出现无法删除的情况
* 禁用表

disable “表名”

  • 删除表

  • drop “删除表”

新增数据/更新数据/删除数据/查询数据

  • 新增:put “表名”,“rowkey”,“列簇:列名”,“值”
    • 新增一列
  • 更新:和新增的 一样的
  • 删除数据
    • delete"表名",“rowkey”,“列簇:列名”
      • delete也是删除一个列
        *deleteall “表名”,“rowkey”
      • 删除一行
  • 查询数据
    • get"表名",“rowkey”
      • get是查询一行的数据
  • 删除数据的时候,其实HBase不是真的直接把数据删除了,而是给某个列设置成一个标记,然后查询数据的时候,有这个标记的数据,就不显示出来。
  • 什么时候真的删除数据呢?
    *后台进程,专门来执行删除数据的操作。
执行delete的时候
	1. 如果表中的某个列有对一个的几次修改,他会删除最近一次的修改
	2. 默认是保存1个保存的时间戳
	3. 有一个version的属性

计数器和简单的scan扫描操作

计算器

  • count “表名”:hbase就会将这个表对应的所有数据都扫描一遍,得到最终的记录条数(慎用)
  • 执行HBase提供的基于MR的RowCount的程序(用于做大批量的数据的查询)
  • 启动yarn集群
  • 启动mr-historyserver

scan扫描

  • 全表扫描:scan"表名"(慎用,效率很低)
  • 限定只显示多少条数据:scan " 表名",{LIMIT => XXX}
  • 指查询某几个列:scan “表名”,{LIMIT => XX,COLUMNS => []}
  • 根据ROWKEY来查询:scan"表名",{LIMIT => XXX,COLUMNS =>[],POWPREFIXFILTER => ‘ROWKEY’}

使用过滤器的重点

  • 语法:
    • 其实在hbase shell中,执行的ruby脚本,背后还是调用hbase提供的 javaAPI。
    • 在HBase中会有很多的过滤器,语法格式看起来会比较复杂,所以重点理解这个语法是什么意思
    • 过滤器在hbase shell中是使用一个表达式来描述,在java中new何种对象
scan "ORDER_INFO", {FILTER => "RowFilter(=,'binary:02602f66-adc7-
40d4-8485-76b5632b5b53')", COLUMNS => ['C1:STATUS', 'C1:PAYWAY'], 
FORMATTER => 'toString'}

其中:
`"RowFilter(=,'binary:02602f66-adc7-40d4-8485-76b5632b5b53')"`这个就是一个表达式

语法解析

  • RowFilter就是Java API中Filter的构造器名称
  • 可以理解为RowFilter()就是创建一个过滤器对象
  • =是JRuby一个特殊记号,表示是一个比较运算符,还可以是>、<、>=…
  • binary:02602f66-adc7-40d4-8485-76b5632b5b53是一个比较器的表达式,为了方便大家理解,可以将比较器理解为配置值的地方,binary:xxxx表示直接和值进行毕节

使用HBase的计数器

  • 要使用incr来去初始化一个列,一定不能使用put操作
  • 可以使用get_couter的指令来获取计数器的操作,使用get是获取不到计数器的数据
  • incr"表名",“rowkey”,“列簇:列”,xxx

Hbase一些管理命令

  • status:常用命令,可以查看整个集群的运行的节点数
  • whoami:查看当前的用户
  • disable/enable:禁用/开启表
  • drop:删除表
  • exists:判断表是否存在
  • truncate:清空表

HBase的建表操作

创建链接

  1. 建立Hbase链接
  2. 创建admin对象
    Connection connection;
    Admin admin;
    @BeforeTest
    public void beforeTest() throws Exception{
        //1.创建Hbase配置,使用HBaseConfiguration.create();来进行创建
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum", "192.168.3.67:2181,192.168.3.68:2181,192.168.3.69:2181");
        //2.使用 ConnectionFactory.createConnection创建Hbase链接
        connection = ConnectionFactory.createConnection(conf);
        //3.要创建表,需要基于Hbase链接获取admin管理对象
        //要创建表、删除表需要和HMaster进行链接,所以需要有一个admin对象
        admin = connection.getAdmin();
    }

创建表

  1. 调用tableExists判断表是否存在
  2. 在HBase中,要去创建表,需要构建TableDescriptor(表描述器)、ColumnFamilyescriptor(列簇描述器),这两个对象不是直接new出来的,是通过builder来创建的
  3. 将列簇描述器添加到表描述器中
  4. 使用admin.creatTable创建表
@Test
public void CreateTable() throws Exception{
	//创建表
	//2.使用HtableDescriptor
	HTableDescriptor testAPI = new HTableDescriptor(TableName.valueOf("testAPI"));	

	//创建列簇
	HColumnDescriptor cf1 = new HcolumnDescriptor("info");
	//对列簇进行配置
	cf1.setMaxVersions(3);
	
	//给testAPI表添加一个列簇
	testAPI.addFamily(cf1);

	//创建testAPI表
	admin.createTable(testAPI);
} 

在HBase中所有的书就都是以byte[]形式来存储的,所以需要将java的数据类型进行转换

// 经常会使用到一个工具类:Bytes(hbase包下的Bytes工具类)
// 这个工具类可以将字符串、long、double类型转换成byte[]数组
// 也可以将byte[]数组转换为指定类型

插入数据

  • 首先要获取一个Table对象,这个对象是要和HRegionServer节点连接,所以将来HRegionServer负载是比较高的
  • HBase的connection对象是一个重量级的对象,将来编写代码(Spark、Flink)的时候,避免频繁创建,使用一个对象就OK,因为它是线程安全的
Connection creation is a heavy-weight operation. Connection implementations are thread-safe
  • Table这个对象是一个轻量级的,用完Table需要close,因为它是非线程安全的
Lightweight. Get as needed and just close when done.
  • 需要构建Put对象,然后往Put对象中添加列蔟、列、值

  • 当执行一些繁琐重复的操作用列标记:

    • ctrl + shift + ←/→,可以按照单词选择,非常高效

获取数据(通过ROWKEY)

方式一
  1. 构建一个PUT对象,根据rowkey来查询一行数据
  2. 遍历单元格,使用Bytes.toString来进行类型转换
  3. 如何判断是getmian还是gettable呢,就看是否和数据有关系,如果和数据没有关系的话,就用getAdmin(),这里是获取数据,和数据明显的有关系,所以我们使用getTable()方法。
@Test
public void getTest() throws Exception {
	//1.获取HTable
	Table testAPI = connection.getTable(TableName.valueOf("testAPI"));
	// 2.	使用rowkey构建Get对象
	Get get = new Get("001".getBytes());

	//3.执行get请求
	Result rs = table.get(get)

	//4.获取所有单元格,列出所有的单元格
	这里有两种方法,第一种是打印所有的cell,第二种方法,下面贴上
	这里打印所有的cell来获取数据
	List<Cell> cellList = result.listCells();

	//5、打印rowkey
	 byte[] rowkey = result.getRow();
     System.out.println(Bytes.toString(rowkey));
     //6.迭代单元格列表
      for (Cell cell : cells) {
            String value = Bytes.toString(CellUtil.cloneValue(cell));
            System.out.println(value);
        }
}
方式二:
 @Test
    //get
    public void GetDataOne() throws Exception{
        Table testAPI = connection.getTable(TableName.valueOf("testAPI"));
        Get get = new Get("001".getBytes());

        get.setMaxVersions(10);

        Result rs = testAPI.get(get);

        //获取rowkey
        byte[] row = rs.getRow();

        byte[] name = rs.getValue("cf1".getBytes(), "name".getBytes());
        byte[] age = rs.getValue("cf1".getBytes(), "age".getBytes());
        byte[] clazz = rs.getValue("cf1".getBytes(), "clazz".getBytes());

        System.out.println(Bytes.toString(row)+","+ Bytes.toString(name)+","+Bytes.toString(age)+","+Bytes.toString(clazz));
    }

查看表结构

  • 如何判断是getmian还是gettable呢,就看是否和数据有关系,如果和数据没有关系的话,就用getAdmin()
@Test
    //查看表结构,使用desc方法进行查看
    public void descList() throws  Exception{
        //如何判断是getmian还是gettable呢,就看是否和数据有关系。
        // 如果和数据没有关系的话,就用getAdmin()
        Admin admin = connection.getAdmin();


        HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf("testAPI"));
        //添加表结构是addFamily。查询表结构是getFamily

        //获取方法1:getFamilies返回的是集合
        Collection<HColumnDescriptor> families = tableDescriptor.getFamilies();
        //获取方法2:getColumnFamilies(),这里返回的是一个数组
        HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();

        //如果是数组的话可以进行遍历数组进行
        for (HColumnDescriptor columnFamily : columnFamilies) {
            System.out.println(columnFamily.getNameAsString());
            System.out.println(columnFamily.getMaxVersions());
            System.out.println(columnFamily.getTimeToLive());
        }
    }

HBase的Java API scan + filer过滤操作

  • ResultScanner需要手动关闭,这个操作是比较消耗资源的,用完了 就应该关掉,不能一直开着
  • 扫描使用的是Scan对象
  • SingleColumnValueFilter ----过滤单列值的过滤器
  • FilterList——是可以用来组合多个过滤器
 @Test
    public void scanFilterTest() throws IOException {
        // 1.	获取表
        Table table = connection.getTable(TABLE_NAME);

        // 2.	构建scan请求对象
        Scan scan = new Scan();

        // 3.	构建两个过滤器
        // a)	构建两个日期范围过滤器(注意此处请使用RECORD_DATE——抄表日期比较
        SingleColumnValueFilter startFilter = new SingleColumnValueFilter(Bytes.toBytes("C1")
                , Bytes.toBytes("RECORD_DATE")
                , CompareOperator.GREATER_OR_EQUAL
                , new BinaryComparator(Bytes.toBytes("2020-06-01")));

        SingleColumnValueFilter endFilter = new SingleColumnValueFilter(Bytes.toBytes("C1")
                , Bytes.toBytes("RECORD_DATE")
                , CompareOperator.LESS_OR_EQUAL
                , new BinaryComparator(Bytes.toBytes("2020-06-30")));

        // b)	构建过滤器列表
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL, startFilter, endFilter);

        // 4.	执行scan扫描请求
        scan.setFilter(filterList);
        ResultScanner resultScanner = table.getScanner(scan);
        Iterator<Result> iterator = resultScanner.iterator();

        // 5.	迭代打印result
        while(iterator.hasNext()) {
            Result result = iterator.next();

            // 列出所有的单元格
            List<Cell> cellList = result.listCells();

            // 5.	打印rowkey
            byte[] rowkey = result.getRow();
            System.out.println(Bytes.toString(rowkey));
            // 6.	迭代单元格列表
            for (Cell cell : cellList) {
                // 将字节数组转换为字符串
                // 获取列蔟的名称
                String cf = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
                // 获取列的名称
                String columnName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());

                String value = "";

                // 解决乱码问题:
                // 思路:
                // 如果某个列是以下列中的其中一个,调用toDouble将它认为是一个数值来转换
                //1.	NUM_CURRENT
                //2.	NUM_PREVIOUS
                //3.	NUM_USAGE
                //4.	TOTAL_MONEY
                if(columnName.equals("NUM_CURRENT")
                    || columnName.equals("NUM_PREVIOUS")
                    || columnName.equals("NUM_USAGE")
                    || columnName.equals("TOTAL_MONEY")) {
                    value = Bytes.toDouble(cell.getValueArray()) + "";
                }
                else {
                    // 获取值
                    value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
                }

                System.out.println(cf + ":" + columnName + " -> " + value);
            }
        }

        // 7.	关闭ResultScanner(这玩意把转换成一个个的类似get的操作,注意要关闭释放资源)
        resultScanner.close();
        // 8.	关闭表
        table.close();

    }

HBase的存储架构

  • 进程角色
    • client:客户端,写的Java程序、hbase shell都是客户端(Flink、MapReduce、Spark)
    • HMaster:主要是负责表的管理操作(创建表、删除表、Region分配),不负责具体的数据操作
    • HRegionServer:负责数据的管理、数据的操作(增删改查)、负责接收客户端的请求来操作数据
  • HBase架构的一些关键概念
    • Region:一个表由多个Region组成,每个Region保存一定的rowkey范围的数据,Region中的数据一定是有序的,是按照rowkey的字典序来排列的
    • Store:存储的是表中每一个列蔟的数据
      • MemStore:所有的数据都是先写入到MemStore中,可以让读写操作更快,当MemStore快满的时候,需要有一个线程定期的将数据Flush到磁盘中
      • HFile:在HDFS上保存的数据,是HBase独有的一种数据格式(丰富的结构、索引、DataBlock、BloomFilter布隆过滤器…)
      • WAL:WAL预写日志,当客户端连接RegionServer写数据的时候,会先写WAL预写日志,put/delete/incr命令写入到WAL,有点类似于之前Redis中的AOF,当某一个RegionServer出现故障时,还可以通过WAL来恢复数据,恢复的就是MemStore的数据。

HBase的存储架构这里单独来开一个笔记进行讲解,这里会通过xmind的形式进行总结,尽情期待下一篇博客

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值