[博学谷学习记录] 超强总结,用心分享|HBase基础_2

本文详细介绍了HBase的高级Shell操作,包括使用不同类型的过滤器进行数据查询。接着,通过JavaAPI展示了如何进行HBase的增删改查操作,并提供了相关配置和代码示例。此外,文章还概述了HBase的集群架构和数据的读写流程,包括读取时的内存、blockCache、storeFile和HFile的处理,以及写入时的数据持久化过程。
摘要由CSDN通过智能技术生成

HBase

注:大家觉得博客好的话,别忘了点赞收藏呀,本人每周都会更新关于人工智能和大数据相关的内容,内容多为原创,Python Java Scala SQL 代码,CV NLP 推荐系统等,Spark Flink Kafka Hbase Hive Flume等等~写的都是纯干货,各种顶会的论文解读,一起进步。
今天继续和大家分享一下HBase
#博学谷IT学习技术支持



前言

接着上次未完成的内容,继续分享HBase


一、HBase的高级Shell操作

1.HBase的过滤器查询操作

格式:
scan ‘表名’,{FILTER=>“过滤器名称(比较运算符,比较器表达式)” }

常见的过滤器:
rowkey过滤器:
RowFilter : 实现行键字符串的比较和过滤操作
PrefixFilter : rowkey 前缀过滤器
列族过滤器:
FamilyFilter: 列族过滤器
列名过滤器:
QualifierFilter : 列名过滤器, 中显示对应列名的数据
列值过滤器:
ValueFilter: 列值过滤器, 找到符合值的数据
SingleColumnValueFilter: 在执行的列族和列名中进行比较具体的值, 将符合条数据整行数据全部都返回(包含条件的内容字段)
SingleColumnValueExcludeFilter: 在执行的列族和列名中进行比较具体的值, 将符合条数据整行数据全部都返回(去除条件内容的字段)
其他过滤器:
PageFilter : 用来执行分页操作

比较运算符 : = > < >= <= !=

比较器:
BinaryComparator : 完整匹配字节数组
BinaryPrefixComparator : 匹配字节数组前缀
NullComparator : 匹配Null
SubstringComparator : 模糊匹配字符串

比较器表达式:
BinaryComparator : binary:值
BinaryPrefixComparator : binaryprefix:值
NullComparator : null
SubstringComparator: substring:值

如果不知道过滤器的构造参数, 可以查看此地址:
http://hbase.apache.org/2.2/devapidocs/index.html

需求: 查询rowkey中以rk开头的数据
scan 'test01',{FILTER=>"PrefixFilter('rk')" }

需求: 查询在列名中包含a字母的列有那些呢?
scan 'test01',{FILTER=>"QualifierFilter(=,'substring:a')" }

需求: 查询 name的值包含z的数据,  带有Exclude 表示是否去除查询列
scan 'test01',{FILTER=>"SingleColumnValueFilter('f1','name',=,'substring:z')" } 
scan 'test01',{FILTER=>"SingleColumnValueExcludeFilter('f1','name',=,'substring:z')" } 

二、HBase的Java Api的操作

1.导入相关的pom文件

    <repositories><!--代码库-->
        <repository>
            <id>aliyun</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases><enabled>true</enabled></releases>
            <snapshots>
                <enabled>false</enabled>
                <updatePolicy>never</updatePolicy>
            </snapshots>
        </repository>
    </repositories>

    <dependencies>

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

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <target>1.8</target>
                    <source>1.8</source>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.代码实现增删改查操作

package com.itheima.hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.List;


public class HBasePra {

    private Connection hbaseConn;
    private Admin admin;
    private Table table;

    //初始化链接对象
    @Before
    public void init() throws Exception {
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","node1:2181,node2:2181,node3:2181");
        hbaseConn = ConnectionFactory.createConnection(conf);
        admin = hbaseConn.getAdmin();
        table = hbaseConn.getTable(TableName.valueOf("WATER_BILL"));
    }

    // 如何创建一张表
    @Test
    public void createTableTest() throws Exception{
        boolean flag = admin.tableExists(TableName.valueOf("WATER_BILL"));
        if (!flag){

            ColumnFamilyDescriptor familyDescriptor =
                    ColumnFamilyDescriptorBuilder.newBuilder("C1".getBytes()).build();

            TableDescriptor tableDescriptor = TableDescriptorBuilder
                    .newBuilder(TableName.valueOf("WATER_BILL"))
                    .setColumnFamily(familyDescriptor).build();

            admin.createTable(tableDescriptor);
        }
    }

    // 如何添加一条数据
    @Test
    public void addDataTest() throws Exception {
        Put put = new Put("4944191".getBytes());
        put.addColumn("C1".getBytes(),"NAME".getBytes(),"登为红".getBytes());
        put.addColumn("C1".getBytes(),"ADDRESS".getBytes(),"贵州省".getBytes());
        put.addColumn("C1".getBytes(),"SEX".getBytes(),"男".getBytes());
        table.put(put);
    }

    @Test
    // 根据rowkey如何查询一条数据
    public void getDataTest() throws Exception {
        Get get = new Get("4944191".getBytes());
        Result result = table.get(get);

        List<Cell> cellList = result.listCells();
        for (Cell cell : cellList) {

            byte[] cloneRow = CellUtil.cloneRow(cell);
            String row = new String(cloneRow);

            byte[] cloneFamily = CellUtil.cloneFamily(cell);
            String family = new String(cloneFamily);

            byte[] cloneQualifier = CellUtil.cloneQualifier(cell);
            String qualifier = new String(cloneQualifier);

            byte[] cloneValue = CellUtil.cloneValue(cell);
            String value = new String(cloneValue);

            System.out.println("rowkey: " + row + "columnFamily: " + family + "columnQualifier: " + qualifier + "value: " + value);


        }
    }

    // 如何删除数据
    @Test
    public void deleteDataTest() throws Exception {
        Delete delete = new Delete("4944191".getBytes());
        delete.addColumn("C1".getBytes(), "SEX".getBytes());
        table.delete(delete);
    }

    // 如何删除表
    @Test
    public void dropTableTest() throws Exception {
        if (admin.tableExists(TableName.valueOf("WATER_BILL")) &&
            admin.isTableEnabled(TableName.valueOf("WATER_BILL"))
        ){
            admin.disableTable(TableName.valueOf("WATER_BILL"));
            admin.deleteTable(TableName.valueOf("WATER_BILL"));
        }

    }

    // 如何扫描表
    @Test
    public void scanTest() throws Exception {
        Scan scan = new Scan();
        scan.setLimit(10);

        // 设置过滤器
        // 方法1:
        SingleColumnValueFilter filter1 = new SingleColumnValueFilter(
                "C1".getBytes(),
                "RECORD_DATE".getBytes(),
                CompareOperator.GREATER_OR_EQUAL,
                new BinaryComparator("2020-06-01".getBytes()));

        SingleColumnValueFilter filter2 = new SingleColumnValueFilter(
                "C1".getBytes(),
                "RECORD_DATE".getBytes(),
                CompareOperator.LESS_OR_EQUAL,
                new BinaryComparator("2020-06-30".getBytes()));

        FilterList filterList = new FilterList();
        filterList.addFilter(filter1);
        filterList.addFilter(filter2);
        scan.setFilter(filterList);

        //方法2
//        SingleColumnValueFilter filter3 = new SingleColumnValueFilter(
//                "C1".getBytes(),
//                "RECORD_DATE".getBytes(),
//                CompareOperator.EQUAL,
//                new BinaryPrefixComparator("2020-06".getBytes())
//        );
//
//        scan.setFilter(filter3);

        ResultScanner results = table.getScanner(scan);

        // 遍历得到每一行的数据
        for (Result result : results) {
            List<Cell> cellList = result.listCells();

            // 遍历得到每一个单元格的数据
            for (Cell cell : cellList) {

                byte[] cloneQualifier = CellUtil.cloneQualifier(cell);
                String qualifier = Bytes.toString(cloneQualifier);

                if ("NAME".equalsIgnoreCase(qualifier) ||
                    "NUM_USAGE".equalsIgnoreCase(qualifier) ||
                    "RECORD_DATE".equalsIgnoreCase(qualifier)
                )
                {
                    byte[] cloneRow = CellUtil.cloneRow(cell);
                    String row = Bytes.toString(cloneRow);

                    byte[] cloneFamily = CellUtil.cloneFamily(cell);
                    String family = Bytes.toString(cloneFamily);

                    byte[] cloneValue = CellUtil.cloneValue(cell);

                    Object value;
                    if ("NUM_USAGE".equalsIgnoreCase(qualifier)){
                        value = Bytes.toDouble(cloneValue);
                    }
                    else {
                        value = Bytes.toString(cloneValue);

                    }
                    System.out.println("rowkey: " + row + " columnFamily: "
                            + family + " columnQualifier: " +  qualifier +" value: " + value);
                }

            }
            System.out.println("------------------------------------------------");

        }
    }
    //关闭操作
    @After
    public void close() throws Exception {
        admin.close();
        table.close();
        hbaseConn.close();
    }
}

三、HBase的集群架构

在这里插入图片描述
在这里插入图片描述

四、HBase的读写流程

1.HBase的读取数据的流程

1) 客户端发起读取数据的请求, 首先会先连接zookeeper

2) 从zookeeper中获取一张 hbase:meta 表目前被哪个RegionSerer所管理
		说明: hbase:meta 是HBase专门用于存储元数据的表, 此表只会有一个Region,也就是说这个Region只能被一个RegionServer所管理
3) 连接Meta表对应的RegionServer, 从这个表中获取, 要读取的表有哪些Region, 以及这些Region对应被哪些RegionServer所管理,从而确认要操作的RegionServer
	注意: 
		如果执行Scan, 返回这个表所有Region对应的RegionServer的地址 
		如果执行get,  返回查询rowkey对应Region所在RegionServer的地址

4- 连接对应的RegionServer, 从RegionServer中对应Region中读取数据即可 
	读取顺序:  先内存 ---> blockCache(块缓存) ----> storeFile ---> 大HFile
	
	注意: 读取块缓存只有在get操作才有效, 如果scan扫描 基本无意义

2.HBase的写入数据的流程

1- 由客户端发起写入数据的请求, 首先先连接zookeeper

2- 从zookeeper中获取hbase:meta表被那个RegionServer所管理

3- 连接对应RegionServer, 从Meta表获取要写入数据的表有哪些Region, 以及每个Region被那个RegionServer所管理, 然后根据Region的起始Rowkey 和 结束rowkey, 获取要写入数据的Region对应RegionServer的地址
	大白话: 查询写入到那个Region, 这个Region被那个RegionServer所管理

4- 连接对应RegionServer, 开始进行数据写入操作, 写入时, 先将数据写入到这个RegionServer的HLog, 然后将数据写入到对应的Store模块下的MemStore中(可能写入多个MemStore), 当这两个位置都写入成功的时候, 客户端认为数据写入完成了

---------------以上 为客户端写入流程------------------------

异步操作: 上面客户端可能执行了多次后, 后续才会干活

  1. 随着客户端不断的写入操作, MemStore中数据会越来越多, 当MemStore的数据达到一定的阈值(128M/1h)后, 就会启动flush刷新线程, 将内存中数据"最终"刷新到HDFS上, 形成一个StoreFile文件

  2. 随着不断的进行Flush的刷新, 在HDFS上StoreFile文件会越来越多, 当StoreFlie文件达到一定的阈值(3个及以上)后,就会启动compact合并压缩机制, 将多个StoreFlie"最终"合并为一个大的HFile

  3. 随着不断的合并, HFile文件会越来越大, 当这个大的HFile文件达到一定的阈值("最终"10GB)后,就会触发Split机制, 将大的HFile进行一分为二的操作, 形成两个新的大HFile文件, 此时Region也会进行一分为二,形成两个新的Region, 一个Region管理一个新的大Hfile, 旧的大HFile和对应Region就会被下线


总结

今天和大家分享了一下HBase基础的API和一些概念的内容,下次会接着分享HBase的核心工作机制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值