Hbase基础

一 HBase介绍

1 简介

	Apache HBase™是Hadoop数据库,这是一个分布式,可扩展的大数据存储。
	当您需要对大数据进行随机,实时的读/写访问时,请使用Apache HBase™。 该项目的目标是在商品硬件群集上托管超大型表-数十亿行X数百万列。 Apache HBase是一个开源的,分布式的,版本化的,非关系型数据库,其仿照Chang等人的Google的Bigtable:结构化数据的分布式存储系统。 正如Bigtable利用Google文件系统提供的分布式数据存储一样,Apache HBase在Hadoop和HDFS之上提供类似于Bigtable的功能。

2 Mysql与HBase的对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nn504CDC-1595216578183)(.\image\001.png)]

3 HBase的工作原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SB9rUrvH-1595216578188)(.\image\003.png)]

二 HBase的安装

1 单机节点安装

1.1 配置

[root@qphone01 software]# tar -zxvf hbase-1.2.1-bin.tar.gz -C /opt/apps/

[root@qphone01 conf]# vi hbase-env.sh

# The java implementation to use.  Java 1.7+ required.
export JAVA_HOME=/opt/apps/jdk1.8.0_45

# Tell HBase whether it should manage it's own instance of Zookeeper or not.
export HBASE_MANAGES_ZK=true

[root@qphone01 conf]# vi hbase-site.xml

<configuration>
        <property>
                <name>hbase.rootdir</name>
                <value>file:///opt/apps/hbase-1.2.1/hdata</value>
        </property>
        <property>
                <name>hbase.zookeeper.property.dataDir</name>
                <value>/opt/apps/hbase-1.2.1/zkdata</value>
        </property>
</configuration>

1.2 测试

[root@qphone01 hbase-1.2.1]# start-hbase.sh
[root@qphone01 hbase-1.2.1]# hbase shell

hbase(main):001:0> list
TABLE
0 row(s) in 0.2460 seconds

=> []
hbase(main):002:0> list_namespace
list_namespace          list_namespace_tables
hbase(main):002:0> list_namespace
NAMESPACE
default
hbase

2 伪分布式的安装

2.1 配置与安装

1. 打开HDFS集群
2. 修改hbase-site.xml

<configuration>
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://qphone01:9000/hbase</value>
        </property>
        <property>
                <name>hbase.zookeeper.property.dataDir</name>
                <value>/opt/apps/hbase-1.2.1/zkdata</value>
        </property>
</configuration>

2.2 测试伪分布式

1. webui
http://192.168.49.200:16010/master-status

2. 查看hdfs的分目录下,多出来一个hbase目录

3 全分布式安装

3.1 安装zookeeper

[root@qphone01 software]# tar -zxvf zookeeper-3.4.5.tar.gz -C /opt/apps/
[root@qphone01 zookeeper-3.4.5]# vi myid
1
[root@qphone01 conf]# mv zoo_sample.cfg zoo.cfg
[root@qphone01 conf]# vi zoo.cfg

dataDir=/opt/apps/zookeeper-3.4.5

server.1=qphone01:2888:3888
server.2=qphone02:2888:3888
server.3=qphone03:2888:3888

[root@qphone01 apps]# scp -r zookeeper-3.4.5/ qphone02:/opt/apps/
[root@qphone01 apps]# scp -r zookeeper-3.4.5/ qphone03:/opt/apps/

启动zookeeper并保证启动完成

3.2 安装HBase

1. hbase-env.sh
export HBASE_MANAGES_ZK=false

2. hbase-site.xml

<configuration>
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://qphone01:9000/hbase</value>
        </property>
        <property>
                <name>hbase.zookeeper.quorum</name>
                <value>qphone01,qphone02,qphone03</value>
        </property>
</configuration>

3. regionservers
qphone01
qphone02
qphone03

4. 将配置文件重新分发给集群的其他节点
[root@qphone01 hbase-1.2.1]# scp -r conf/ qphone02:/opt/apps/hbase-1.2.1/
[root@qphone01 hbase-1.2.1]# scp -r conf/ qphone03:/opt/apps/hbase-1.2.1/

5. 在qphone02的hbase的conf目录下创建backup-masters
qphone02
tip:
如果这里暂时不能自动启动,
[root@qphone02 bin]# ./hbase-daemon.sh start master

三 HBase 命令行操作

1 帮助命令

help : 查询出所有的hbase命令

help '命令' : 查看指定命令的帮助文档

2 general

status, 查看集群的状态
e.g.
hbase(main):003:0> status
1 active master, 1 backup masters, 3 servers, 0 dead, 0.6667 average load

table_help, 新的建表、插入数据等等的操作方式
e.g.
hbase> t = create 't', 'cf'

version, 
e.g.
hbase(main):005:0> version
1.2.1, r8d8a7107dc4ccbf36a92f64675dc60392f85c015, Wed Mar 30 11:19:21 CDT 2016

whoami, 查询当前连接的用户和组
hbase(main):006:0> whoami
root (auth:SIMPLE)
    groups: root

3 namespace(命名空间) : 相当于mysql中的database

3.1 修改namespace的属性

Alter namespace properties.

To add/modify a property:
  hbase> alter_namespace 'ns1', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}

To delete a property:
  hbase> alter_namespace 'ns1', {METHOD => 'unset', NAME=>'PROPERTY_NAME'}

3.2 创建namespace,指定属性

Create namespace; pass namespace name,and optionally a dictionary of namespace configuration.
Examples:
  hbase> create_namespace 'ns1'
  hbase> create_namespace 'ns1', {'PROPERTY_NAME'=>'PROPERTY_VALUE'}

3.3 查看namespace的详情

Describe the named namespace. 
For example:
  hbase> describe_namespace 'ns1'

3.4 删除为空的namespace,

Drop the named namespace. The namespace must be empty.
For example:
	hbase> drop_namespace 'ns1'

3.5 查询hbase中的所有的namespace,支持使用正则表达式

List all namespaces in hbase. Optional regular expression parameter could be used to filter the output. 
Examples:
  hbase> list_namespace
  hbase> list_namespace 'abc.*'

3.6 查询指定的namespace有多少表

List all tables that are members of the namespace.
Examples:
  hbase> list_namespace_tables 'ns1'

4 DDL

4.1 create:建表,至少得有一个列簇

创建表 namespace=ns1 and table 的列名为t1,这个t1的表有3个列簇,f1,列簇中列值可以存放5个版本
create 'ns1:t1', {NAME => 'f1', VERSIONS => 5}

创建表 namespace=default and table 的列名为t1,这个t1的表有3个列簇,f1,f2,f3
  hbase> create 't1', {NAME => 'f1'}, {NAME => 'f2'}, {NAME => 'f3'}
  hbase> create 't1', 'f1', 'f2', 'f3'
如果是要单独设置列簇的属性配置,就无法简写
  hbase>  create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}

4.2 list : 查询所有的用户表,也支持正则表达式

hbase(main):042:0> list
TABLE                                                                                                                   
ns2:t1                                                                                                                  
1 row(s) in 0.0120 seconds

=> ["ns2:t1"]

4.3 describe/desc : 查询表详情

hbase(main):055:0> describe 'ns2:t1'
Table ns2:t1 is ENABLED                                                                                                 
ns2:t1                                                                                                                  
COLUMN FAMILIES DESCRIPTION                                                                                             
{NAME => 'f1', BLOOMFILTER => 'ROW', VERSIONS => '5', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_EN
CODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '6553
6', REPLICATION_SCOPE => '0'}                                                                                           
1 row(s) in 0.1350 seconds

4.4 Drop/Disable/Enable:删除表/使表失效/使表生效

hbase(main):056:0> disable 'ns2:t1'
0 row(s) in 2.3110 seconds

hbase(main):057:0> drop 'ns2:t1'
0 row(s) in 1.2580 seconds

hbase(main):058:0> list
TABLE                                                                                                                   
0 row(s) in 0.0080 seconds

=> []

hbase(main):068:0> enable 't1'
0 row(s) in 1.2490 seconds

tip:
在hbase中删除表必须使表失效,否则无法删除

4.5 Drop_all/Disable_all/Enable_all

与4.4相同,不过他是批处理模式

4.6 exists : 判断一个表是否存在

hbase(main):069:0> exists 't1'
Table t1 does exist                                                                                                     
0 row(s) in 0.0070 seconds

hbase(main):070:0> exists 't2'
Table t2 does not exist                                                                                                 
0 row(s) in 0.0050 seconds

4.7 is_disabled和is_enabled

校验表是否失效/生效

4.8 alter

如果想要修改表,那么这个表必须得是enable
hbase(main):100:0> alter 't1', NAME => 'f1', VERSIONS => 5
Updating all regions with the new schema...
1/1 regions updated.

删除ns1中t1表的f1列簇,提供一下两种方式:

  hbase> alter 'ns1:t1', NAME => 'f1', METHOD => 'delete'
  hbase> alter 'ns1:t1', 'delete' => 'f1'

tip:
可以修改表的列簇信息,以及给表添加或者删除列簇

4.9 get_table(了解)

hbase(main):103:0> help 'get_table'
Get the given table name and return it as an actual object to
be manipulated by the user. See table.help for more information
on how to use the table.
Eg.

  hbase> t1 = get_table 't1'
  hbase> t1 = get_table 'ns1:t1'

tip:
将一个表,赋值给一个对象

4.10 locate_region : 查询指定的表中的指定的行间在那个region中(了解)

hbase> locate_region 'tableName', 'key0'

4.11 show_filters(了解)

hbase(main):105:0> show_filters

5 DML(在HBase中的数据只有byte[])

5.1 put : 插入一条记录

向ns1的namespace中的t1表插入一个行键为r1,列簇c1的cell
put 'ns1:t1', 'r1', 'c1', 'value'
hbase(main):009:0> put 't1','r1','f1:name','lixi'

向default的namespace中的t1表插入一个行键为r1,列簇c1的cell并指定这个值的时间戳为ts1
hbase> put 't1', 'r1', 'c1', 'value', ts1
hbase(main):002:0>  put 't1','r1','f1:name','rocklee86', 1594344061000

5.2 append:追加一条记录(大致上和put相同,但是不能指定时间戳)

hbase> append 't1', 'r1', 'c1', 'value', ATTRIBUTES=>{'mykey'=>'myvalue'}
hbase(main):005:0> append 't1','r1','f2:sex','woman'

5.3 get:查询单行记录

默认查询的是最新版的值
hbase> get 'ns1:t1', 'r1'
hbase(main):008:0> get 't1', 'r1'
COLUMN                                      CELL                                                                                                                        
 f1:                                        timestamp=1594343882369, value=name:lixi                                                                              
 f1:name                                    timestamp=1594344061000, value=rocklee86                                                                                    
 f2:sex                                     timestamp=1594344445836, value=woman  
 
 
查询指定时间戳范围的值
hbase> get 't1', 'r1', {TIMERANGE => [ts1, ts2]}
get 't1', 'r1', {TIMERANGE => [1594343953315, 1594343953316]}
hbase(main):001:0> get 't1', 'r1', {TIMERANGE => [1594343953315, 1594343953316]}
COLUMN                                      CELL                                                                                                                        
 f1:name                                    timestamp=1594343953315, value=lixi  
 
 如果说这个时间戳范围跨越了两个维度,那么他是以最新的维度来显示数据的
 hbase(main):001:0> get 't1', 'r1', {TIMERANGE => [1594343953315, 1594344061001]}
 
 查询指定时间戳的cell值
 get 't1', 'r1', {COLUMN => 'f1', TIMESTAMP => 1594343953315}

5.4 scan:查询多行记录

 分页查询
 hbase> scan 'ns1:t1', {COLUMNS => ['c1', 'c2'], LIMIT => 10, STARTROW => 'xyz'}
 
 hbase(main):012:0> scan 't1', {COLUMNS => ['f1', 'f2', 'f3'], LIMIT => 2, STARTROW => 'r1'}
ROW                                         COLUMN+CELL                                                                                                                 
 r1                                         column=f1:, timestamp=1594343882369, value=name:lixi                                                                        
 r1                                         column=f1:name, timestamp=1594344061000, value=rocklee86                                                                    
 r1                                         column=f2:sex, timestamp=1594344445836, value=woman                                                                         
 r2                                         column=f3:salary, timestamp=1594345729250, value=100w 

5.5 delete : 删除

hbase> delete 'ns1:t1', 'r1', 'c1', ts1

会删除指定的表中的行键的列簇的值,可以指定删除指定的时间戳的值

5.6 count : 统计表中的行键的个数

hbase(main):035:0> count 't1'

5.7 truncate:删除表中数据,先删除表,然后重新建表

truncate 't1'

5.8 incr:自增

hbase(main):042:0> incr 't1','r1','f1:age'
COUNTER VALUE = 2

5.9 get_counter : 查询指定的列的计数器的当前值

hbase(main):053:0> get_counter 't1', 'r1', 'f1:age'
COUNTER VALUE = 5 

四 HBase JavaAPI操作

1 导入依赖

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

2 获取到连接HBase的对象

/**
 * 测试HBase的代码类
 */
public class TestHBaseDemo1 {
    public static void main(String[] args) throws IOException {
        //1. 设置配置文件对象,并连接到hbase的zk
        Configuration configuration = new Configuration(); // HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "qphone01,qphone02,qphone03"); // 需要在本地的操作系统的hosts文件中配置对应的主机ip

        //2. 获取到操作Namespace
        HBaseAdmin admin = (HBaseAdmin) ConnectionFactory.createConnection(configuration).getAdmin(); // 这个admin对象,类似与jdbc的connection
        //3. 创建一个namespace
        //3.1 创建一个描述器对象
        NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create("ns1").build();
        namespaceDescriptor.setConfiguration("SEX", "WOMEN");
        //3.2 提交给admin
        admin.createNamespace(namespaceDescriptor);

        //4. 释放资源
        admin.close();
    }
}

3 提取工具类

3.1 HBaseUtils

package cn.qphone.hbase.utils;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ConnectionFactory;

/**
 * HBase的工具类
 */
public class HBaseUtils {

    private final static String ZK_CLUSTER_Value = "qphone01,qphone02,qphone03";
    private final static String ZK_CLUSTER_KEY = "hbase.zookeeper.quorum";


    private static Configuration configuration = new Configuration();

    static {
        configuration.set(ZK_CLUSTER_KEY, ZK_CLUSTER_Value); // 需要在本地的操作系统的hosts文件中配置对应的主机ip
    }

    /**
     * 获取Admin对象方法
     */
    public static Admin getAdmin() {
        try {
            Admin admin = ConnectionFactory.createConnection(configuration).getAdmin(); // 这个admin对象,类似与jdbc的connection
            return admin;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放admin
     */
    public static void close(Admin admin) {
        try {
            if (admin != null) admin.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}

3.2 重构TestHBaseDemo

package cn.qphone.hbase;

import cn.qphone.hbase.utils.HBaseUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.HBaseAdmin;

import java.io.IOException;

/**
 * 测试HBase的代码类
 */
public class TestHBaseDemo1 {
    public static void main(String[] args) throws IOException {
        //1. 获取到操作Namespace
        Admin admin = HBaseUtils.getAdmin();
        //2. 创建一个namespace
        //2.1 创建一个描述器对象
        NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create("ns4").build();
        namespaceDescriptor.setConfiguration("SEX", "WOMEN");
        //2.2 提交给admin
        admin.createNamespace(namespaceDescriptor);

        //3. 释放资源
        HBaseUtils.close(admin);
    }
}

4 Namespace的CRUD

4.1 create_namespace

 /**
     * 创建namespace
     */
    @Test
    public void create_namespace() throws IOException {
        //2. 创建Namespace的描述器对象
        NamespaceDescriptor descriptor = NamespaceDescriptor.create("ns5").build();
        descriptor.setConfiguration("MONEY","111");
        //3. 传递参数,创建namespace
        admin.createNamespace(descriptor);
    }

4.2 list_namespace

/**
     * list_namespace/describe_namespace
     * @throws IOException
     */
    @Test
    public void list_namespace() throws IOException {
        //1. 获取到当前HBase中的所有的namespace的数组对象
        NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();
        //2. 遍历
        for(NamespaceDescriptor descriptor : namespaceDescriptors) {
//            System.out.println(descriptor.getConfigurationValue(key)); 获取到指定的属性名称对应的属性值
            System.out.print(descriptor.getName() + "\t"); // 打印namespace的值
            // 打印namespace对用的属性值
            Map<String, String> configuration = descriptor.getConfiguration();// 获取到所有的属性的kv
            for (Map.Entry<String, String> entry : configuration.entrySet()) {
                System.out.print(entry.getKey() + "-->" + entry.getValue() + "\t");
            }
            System.out.println();
        }
    }

4.3 list_namespace_tables

/**
     * 获取到namespace对应的所有的表明
     */
    @Test
    public void list_namespace_tables() throws IOException {
        //1. 获取到ns2的下所有的表数组
        TableName[] tableNames = admin.listTableNamesByNamespace("default");
        //2. 遍历
        for (TableName tableName : tableNames) {
            System.out.println(tableName.getNamespaceAsString());//只是表的名字
            System.out.println(tableName.toString());//表的描述
        }
    }

4.4 drop_namespace

  /**
     * 删除指定的namespace
     */
    @Test
    public void drop_namespace() throws IOException {
        //1. 删除
        admin.deleteNamespace("ns4");
    }

4.5 alter_namespace

/**
     * 修改namespace指定的属性
     */
    @Test
    public void alter_namespace() throws IOException {
        //1. 获取到指定的NamespaceDescriptor
        NamespaceDescriptor ns1 = admin.getNamespaceDescriptor("ns1");
        //2. 修改
        ns1.removeConfiguration("SEX"); // 删除指定的属性值
        ns1.getConfigurationValue("SEX"); // 获取到属性的值
        ns1.getConfiguration(); // 获取所有的属性值
        ns1.setConfiguration("SEX", "MAN"); // 修改/添加属性
        //3. 提交修改
        admin.modifyNamespace(ns1);
    }

5 Table的CRUD

5.1 create

/**
     * 建表
     */
    @Test
    public void create() throws IOException {
        //1. 建表
        TableName tableName = TableName.valueOf("ns1:t2");
        HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
        //2. 创建列簇
        HColumnDescriptor hColumnDescriptor = new HColumnDescriptor("f1");
        hColumnDescriptor.setVersions(1, 5);
        tableDescriptor.addFamily(hColumnDescriptor);
        //3. 提交
        admin.createTable(tableDescriptor);
    }

5.2 list

@Test
    public void listTableNames() throws IOException {
        //1. 获取所有的表明
        TableName[] tableNames = admin.listTableNames();
        //2. 遍历
        for (TableName tableName : tableNames) {
            System.out.println(tableName.toString());
        }
    }

    /**
     * list/desc
     */
    @Test
    public void list() throws IOException {
        HTableDescriptor[] hTableDescriptors = admin.listTables();
        for (HTableDescriptor tableDescriptor : hTableDescriptors) {
            System.out.print(tableDescriptor.getNameAsString() + "\t"); // 表名
            HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies(); // 所有的列簇
            for (HColumnDescriptor columnDescriptor : columnFamilies) {
                System.out.print(columnDescriptor.getNameAsString() + "\t");
            }
            Map<String, String> configuration = tableDescriptor.getConfiguration();// 获取到所有的属性的kv
            for (Map.Entry<String, String> entry : configuration.entrySet()) {
                System.out.print(entry.getKey() + "-->" + entry.getValue() + "\t");
            }
            System.out.println();
        }
    }

5.3 alter

@Test
    public void alter() throws IOException {
        TableName tableName = TableName.valueOf("t1");
        //1. 读取之前的表的描述
        HTableDescriptor tableDescriptor = admin.getTableDescriptor(tableName);
        //2. 删除一个列簇
        tableDescriptor.removeFamily(Bytes.toBytes("f3"));
        tableDescriptor.removeFamily("f2".getBytes());
//        tableDescriptor.addFamily(columnDescriptor); // 添加列簇
//        tableDescriptor.getFamily(byte[] comlun); 修改列簇,先获取到指定的列簇,修改获取到的这个对象

        //3. 提交修改
        admin.modifyTable(tableName, tableDescriptor);
    }

5.4 drop

@Test
    public void drop() throws IOException {
        TableName tableName = TableName.valueOf("t2");
        //1. 判断表是否存在
        boolean isExist = admin.tableExists(tableName);
        if (isExist) {
            //2. 表是否失效
            boolean tableDisabled = admin.isTableDisabled(tableName);
            if (!tableDisabled) admin.disableTable(tableName); // 令表失效
            //3. 删除表
            admin.deleteTable(tableName);
        }else {
            System.out.println(tableName.toString() + "他不存在!!!");
        }
    }

6 DML

6.1 HBaseUtils

package cn.qphone.hbase.utils;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Table;

/**
 * HBase的工具类
 */
public class HBaseUtils {

    private final static String ZK_CLUSTER_Value = "qphone01,qphone02,qphone03";
    private final static String ZK_CLUSTER_KEY = "hbase.zookeeper.quorum";
    private final static String DEFAULT_TABLE = "t1";


    private static Configuration configuration = new Configuration();

    static {
        configuration.set(ZK_CLUSTER_KEY, ZK_CLUSTER_Value); // 需要在本地的操作系统的hosts文件中配置对应的主机ip
    }

    /**
     * 获取Admin对象方法
     */
    public static Admin getAdmin() {
        try {
            Admin admin = ConnectionFactory.createConnection(configuration).getAdmin(); // 这个admin对象,类似与jdbc的connection
            return admin;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取到指定表的table对象
     */
    public static Table getTable() {
        return getTable(DEFAULT_TABLE);
    }

    /**
     * 获取到指定表的table对象
     */
    public static Table getTable(String table_name) {
        try {
            Table table = ConnectionFactory.createConnection(configuration).getTable(TableName.valueOf(table_name));
            return table;
        }catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放admin
     */
    public static void close(Admin admin) {
        try {
            if (admin != null) admin.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放admin
     */
    public static void close(Table table) {
        try {
            if (table != null) table.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void close(Admin admin, Table table) {
        close(admin);
        close(table);
    }
}

6.2 put_append

 /**
     * 插入数据
     */
    @Test
    public void put_append() throws IOException {
        //1. 获取到Table对象
        table = HBaseUtils.getTable();
        //2. put ---------------------------------
        //2.1 创建put对象
//        Put put = new Put(Bytes.toBytes("002"), 1594621012395L);
//        put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("小李洛克"));
//        put.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("sex"), Bytes.toBytes("man"));
//        //3. 提交
//        table.put(put);

        //3. Append ---------------------------------
        Append append = new Append(Bytes.toBytes("003"));
        append.add(Bytes.toBytes("f1"), Bytes.toBytes("name"), Bytes.toBytes("悟空"));
        append.add(Bytes.toBytes("f1"), Bytes.toBytes("sex"), Bytes.toBytes("man"));
        table.append(append);
    }

6.3 get

@Test
    public void get() throws IOException {
        //1. 创建get对象
        Get get = new Get(Bytes.toBytes("001"));
        //2. 执行查询
        Result result = table.get(get);
        //3. 查看
        while (result.advance()) { // 判断如果有cell可以推进就返回true,否则为false
            Cell current = result.current(); // 获取到当前的cell
//            System.out.println(new String(current.getRowArray(), current.getRowOffset(), current.getRowLength())); // 行键
//            System.out.println(new String(current.getFamilyArray(), current.getFamilyOffset(), current.getFamilyLength())); // 列簇
//            System.out.println(new String(current.getQualifierArray(), current.getQualifierOffset(), current.getQualifierLength())); // 列名
//            System.out.println(new String(current.getValueArray(), current.getValueOffset(), current.getValueLength())); // 列值
            System.out.println(new String(CellUtil.cloneRow(current)));
            System.out.println(new String(CellUtil.cloneFamily(current)));
            System.out.println(new String(CellUtil.cloneQualifier(current)));
            System.out.println(new String(CellUtil.cloneValue(current)));
        }
    }

6.4 scan

@Test
    public void scan() throws IOException {
        //1. 创建scan对象
        Scan scan = new Scan();
        //2. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //3. 查看
        Iterator<Result> iterator = scanner.iterator();
        while (iterator.hasNext()) {
            Result result = iterator.next();
            while (result.advance()) { // 判断如果有cell可以推进就返回true,否则为false
                Cell current = result.current(); // 获取到当前的cell
                System.out.print(new String(CellUtil.cloneRow(current)) + "\t");
                System.out.print(new String(CellUtil.cloneFamily(current)) + "\t");
                System.out.print(new String(CellUtil.cloneQualifier(current)) + "\t");
                System.out.print(new String(CellUtil.cloneValue(current)) + "\t");
                System.out.println();
            }
        }
    }

6.5 重构HBaseUtils

6.5.1 HBaseUtils
/**
     * 打印result的结果
     */
    public static void println(Result result) {
        if (result == null) return;
        while (result.advance()) { // 判断如果有cell可以推进就返回true,否则为false
            Cell current = result.current(); // 获取到当前的cell
            System.out.print(new String(CellUtil.cloneRow(current)) + "\t");
            System.out.print(new String(CellUtil.cloneFamily(current)) + "\t");
            System.out.print(new String(CellUtil.cloneQualifier(current)) + "\t");
            System.out.print(new String(CellUtil.cloneValue(current)) + "\t");
            System.out.println();
        }
    }

    /**
     * 打印scanner中的结果
     */
    public static void println(ResultScanner scanner) {
        //3. 查看
        Iterator<Result> iterator = scanner.iterator();
        while (iterator.hasNext()) {
            Result result = iterator.next();
            HBaseUtils.println(result);
        }
    }
6.5.2 修改之前的测试方法
@Test
    public void get() throws IOException {
        //1. 创建get对象
        Get get = new Get(Bytes.toBytes("001"));
        //2. 执行查询
        Result result = table.get(get);
        //3. 查看
        HBaseUtils.println(result);
    }

    @Test
    public void scan() throws IOException {
        //1. 创建scan对象
        Scan scan = new Scan();
        //2. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //3. 打印
        HBaseUtils.println(scanner);
    }

6.6 incr

@Test
    public void incr() throws IOException {
        //1. 创建
        Increment increment = new Increment(Bytes.toBytes("004"));
        //1.1 设置字段
        increment.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("age"), 1L);
        //2. 自增
        Result res = table.increment(increment);
        //3. 打印
        HBaseUtils.println(res);
    }

6.7 delete

	@Test
    public void delelte() throws IOException {
        //1. 创建delete对象
        Delete delete = new Delete(Bytes.toBytes("004"));
        //2. 删除
        table.delete(delete);
    }

五 HBase JAVA API高级操作——过滤器查询

需求:
1. 在hbase中建立一个emp表
2. 表有一个列簇base_info
3. name,salary,job,dept

查询工资大于10000,并且部门是bigdata的所有的员工信息

1 Column Value

1.1 singleColumnValueFilter

package cn.qphone.hbase;

import cn.qphone.hbase.utils.HBaseUtils;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;

import java.io.IOException;

public class Demo4_Filter {

    /**
     * 查询工资大于10000,并且部门是bigdata的所有的员工信息
     * select * from emp where salary > 10000
     */
    @Test
    public void filter() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("emp");
        //2. 查询并给出条件
        //2.1 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("baseinfo"),
                Bytes.toBytes("salary"),
                CompareFilter.CompareOp.GREATER,
                Bytes.toBytes("10000")
        );
        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter); //设置过滤器
        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }
}

1.2 filterlist

 /**
     * 查询工资大于10000,并且部门是bigdata的所有的员工信息
     * select * from emp where salary > 10000 and/or dept = "bigdata"
     */
    @Test
    public void filterList() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("emp");
        //2. 查询并给出条件
        //2.1 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter(
                Bytes.toBytes("baseinfo"),
                Bytes.toBytes("salary"),
                CompareFilter.CompareOp.GREATER,
                Bytes.toBytes("10000")
        );
        SingleColumnValueFilter singleColumnValueFilter2 = new SingleColumnValueFilter(
                Bytes.toBytes("baseinfo"),
                Bytes.toBytes("dept"),
                CompareFilter.CompareOp.EQUAL,
                Bytes.toBytes("bigdata")
        );

        singleColumnValueFilter1.setFilterIfMissing(true); // 如果该行没有列,就自动过滤
        singleColumnValueFilter2.setFilterIfMissing(true);

        //2.2 两个单列值过滤器合并成一个过滤器链
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL, singleColumnValueFilter1, singleColumnValueFilter2);

        Scan scan = new Scan();
        scan.setFilter(filterList); //设置过滤器
        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }

1.3 ColumnValueFilter

ColumnValueFilter filter = new ColumnValueFilter(
  cf,
  column,
  CompareOperaor.EQUAL,
  Bytes.toBytes("my value")
  );
scan.setFilter(filter);

tip:
作为对SingleColumnValueFilter的补充,在HBase-2.0.0版本中引入了ColumnValueFilter仅获取匹配的单元格,而SingleColumnValueFilter获取匹配的单元格所属的整行(具有其他列和值)。 ColumnValueFilter的构造函数的参数与SingleColumnValueFilter相同。说白了其实就是,ColumnValueFilter过滤的如果是name,就只能查询出name的kv。SingleColumnValueFilter除了把自己本身过滤的列查询出来,还可以将整个这个name对应的rowkey的其他的列都查询出来

2 Column Value Comparators

2.1 RegexStringComparator

/**
     * 查询名字中包含l的所有的员工信息
     * select * from emp where name like "%李%"
     */
    @Test
    public void regexStringComparator() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("t1");

        //2. 查询并给出条件
        //2.1 创建正则比较器
        RegexStringComparator regexStringComparator = new RegexStringComparator(".*李.*");

        //2.2 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("f1"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                regexStringComparator
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter); //设置过滤器

        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }

2.2 SubstringComparator

@Test
    public void substringComparator() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("t1");

        //2. 查询并给出条件
        //2.1 创建字串比较器
        SubstringComparator substringComparator = new SubstringComparator("李");

        //2.2 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("f1"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                substringComparator
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter); //设置过滤器

        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }

2.3 BinaryComparator

@Test
    public void binaryComparator() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("emp");

        //2. 查询并给出条件
        //2.1 创建二进制比较器
        BinaryComparator binaryComparator = new BinaryComparator(Bytes.toBytes("10000"));

        //2.2 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("baseinfo"),
                Bytes.toBytes("salary"),
                CompareFilter.CompareOp.GREATER,
                binaryComparator
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter); //设置过滤器

        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }

2.4 BinaryPrefixComparator

@Test
    public void binaryPrefixComparator() throws IOException {
        //1. 获取表
        Table table = HBaseUtils.getTable("t1");

        //2. 查询并给出条件
        //2.1 创建二进制比较器
        BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator(Bytes.toBytes("李"));

        //2.2 创建过滤器
        SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
                Bytes.toBytes("f1"),
                Bytes.toBytes("name"),
                CompareFilter.CompareOp.EQUAL,
                binaryPrefixComparator
        );

        Scan scan = new Scan();
        scan.setFilter(singleColumnValueFilter); //设置过滤器

        //3. 执行查询
        ResultScanner scanner = table.getScanner(scan);
        //4. 打印
        HBaseUtils.println(scanner);
    }
}

3 KeyValue Metadata

3.1 FamilyFilter

alter 'emp', 'baseinfo', {NAME => 'extrainfo', IN_MEMORY => true}, {NAME => 'highinfo', VERSIONS => 5}

 /**
     * 列簇过滤器
     * 查询所有的列簇以e开头的所有的数据信息
     */
    @Test
    public void familyFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator(Bytes.toBytes("e"));
        FamilyFilter familyFilter = new FamilyFilter(CompareFilter.CompareOp.EQUAL, binaryPrefixComparator);
        Scan scan = new Scan();
        scan.setFilter(familyFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

3.2 QualifierFilter

 /**
     * 查询所有的job列字段的信息
     */
    @Test
    public void qualifierFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        BinaryComparator binaryComparator = new BinaryComparator(Bytes.toBytes("job"));
        QualifierFilter qualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL, binaryComparator);
        Scan scan = new Scan();
        scan.setFilter(qualifierFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

3.3 ColumnPrefixFilter

@Test
    public void columnPrefixFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("j"));
        Scan scan = new Scan();
        scan.setFilter(columnPrefixFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

3.4 MultipleColumnPrefixFilter

 @Test
    public void multipleColumnPrefixFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        byte[][] condition = {Bytes.toBytes("j"), Bytes.toBytes("n")};
        MultipleColumnPrefixFilter columnPrefixFilter = new MultipleColumnPrefixFilter(condition);
        Scan scan = new Scan();
        scan.setFilter(columnPrefixFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

3.5 ColumnRangeFilter

@Test
    public void columnRangeFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        ColumnRangeFilter rangeFilter = new ColumnRangeFilter(Bytes.toBytes("dept"), false, Bytes.toBytes("salary"), false);
        Scan scan = new Scan();
        scan.setFilter(rangeFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

4 RowFilter

4.1 RowFilter

@Test
    public void rowFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        BinaryComparator binaryComparator = new BinaryComparator(Bytes.toBytes("004"));
        RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.LESS, binaryComparator);
        Scan scan = new Scan();
        scan.setFilter(rowFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

4.2 FirstKeyOnlyFilter

@Test
    public void FirstKeyOnlyFilter() throws IOException {
        Table table = HBaseUtils.getTable("emp");
        FirstKeyOnlyFilter firstKeyOnlyFilter = new FirstKeyOnlyFilter();
        Scan scan = new Scan();
        scan.setFilter(firstKeyOnlyFilter);
        ResultScanner scanner = table.getScanner(scan);
        HBaseUtils.println(scanner);
        HBaseUtils.close(table);
    }

六 布隆过滤器

1 布隆过滤器的由来

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hukEpg7k-1595216578194)(F:\桌面\笔记\笔记\Hbase\image\006.png)]

2 HBase中布隆过滤器的应用

判断一个rowkey或者column family是否在一个指定的Store file中。

2.1 HBase中可以设置的值

	布隆过滤器是hbase中的高级功能,它能够减少特定访问模式(get/scan)下的查询时间。不过由于这种模式增加了内存和存储的负担,所以早期HBase被默认为关闭状态,现在的新版本中默认都是使用ROW的布隆过滤器。
hbase支持如下类型的布隆过滤器:

1、NONE          不使用布隆过滤器
2、ROW           行键使用布隆过滤器(默认)
3、ROWCOL    列键使用布隆过滤器
其中ROWCOL是粒度更细的模式。

七 寻址机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49pfEtgL-1595216578197)(F:\桌面\笔记\笔记\Hbase\image\007.png)]

八 regionserver的动态上下线

1 regionserver上线

1. 先杀死集群中的某台服务器
2. 一定得配置相同的hbase-site.xml(指定同一套zk和同一个master)
3. hbase-daemon.sh start regionserver

2 regionserver下线

tip:
	命令:hbase-daemons.sh stop regionserver
	tip:停止所有regionserver,我们的数据是会跟随我们的regionserver一起关闭
	
[root@qphone02 ~]# graceful_stop.sh qphone03
tip:
先将指定的regionserver的数据迁移到指定的服务器集群的的剩余的regionserver上,然后将指定的regionserver关闭。

九 HBase整合HDFS

1 HBase读去数据输出到HDFS

1.1 导入依赖

<dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.8.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.2.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>1.2.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.2.1</version>
        </dependency>

1.2 mapreudce的实战开发方式

package cn.qphone.hbase.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;
import java.util.Iterator;

public class WordCountDriver extends ToolRunner implements Tool {

    private Configuration configuration;

    public static void main(String[] args) throws Exception {
        ToolRunner.run(null, new WordCountDriver(), args); // 启动mr
    }

    public int run(String[] args) throws Exception {
        Job job = Job.getInstance(configuration);

        //2. 指定本作业需要使用的map阶段和reduce阶段的业务类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        //3. 指定map阶段输出的数据的key/value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //4. 指定最终输出数据的类型,其实就reduce处理之后的
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //5. 指定job的输入原始文件的目录
        FileInputFormat.setInputPaths(job, new Path(args[0]));

        //6. 指定job的输出目录
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //7. 指定运行的jar包的所在目录,在这里不使用string参数,是因为使用类额可以通过classloader动态的获取的jar路径
//        job.setJarByClass(W
        ordCountDriver.class);
        job.setJar("D:\\Codes\\workspaces\\worksparce4hzbigdata2002\\day08-hbase\\target\\day08-hbase-1.0-SNAPSHOT.jar");

        //8. 提交 : 将job中配置的相关的参数以及job中使用的jar做在目录等信息提交给yarn取运行
        Boolean res = job.waitForCompletion(true); // 这个方法的作用就是提交,然后把这个处理后的结果打印输出
        System.out.println(res ? "true" : "false");
        return 0;
    }

    public void setConf(Configuration configuration) {
        this.configuration = configuration;
        //1.1 指定yarn路径
//        configuration.set("mapreduce.framework.name", "yarn");
//        configuration.set("yarn.resourcemanager.hostname", "192.168.49.200");
//        configuration.set("mapreduce.app-submission.cross-platform", "true");
    }

    public Configuration getConf() {
        return configuration;
    }
}

class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

    private Text k = new Text();
    private IntWritable v = new IntWritable();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();
        String[] split = line.split(",");
        for (String word : split) {
            k.set(word);
            v.set(1);
            context.write(k, v);
        }
    }
}

class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {

    private IntWritable v = new IntWritable();

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        Iterator<IntWritable> iterator = values.iterator();
        int sum = 0;
        while (iterator.hasNext()) {
            int i = iterator.next().get();
            sum += i;
        }
        v.set(sum);
        context.write(key, v);
    }
}

1.3 HBase2HDFS

1.3.1 目标

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qT38rI9n-1595216578199)(F:\桌面\笔记\笔记\Hbase\image\008.png)]

1.3.2 代码
package cn.qphone.hbase.hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;

public class HBase2HDFS extends ToolRunner implements Tool {

    private Configuration configuration;

    public static void main(String[] args) throws Exception {
        ToolRunner.run(null, new HBase2HDFS(), args);
    }

    public int run(String[] args) throws Exception {
        Job job = Job.getInstance(configuration);

        //2. 指定本作业需要使用的map阶段和reduce阶段的业务类
        //3. 指定最终输出数据的类型,其实就reduce处理之后的
        //4. 指定job的输入原始文件的目录
        TableMapReduceUtil.initTableMapperJob("emp", new Scan(), HBase2HDFSMapper.class, Text.class, NullWritable.class, job);

        //5. 指定job的输出目录
        FileOutputFormat.setOutputPath(job, new Path(args[0]));

        //7. 指定运行的jar包的所在目录,在这里不使用string参数,是因为使用类额可以通过classloader动态的获取的jar路径
        job.setJarByClass(HBase2HDFS.class);

        //8. 提交 : 将job中配置的相关的参数以及job中使用的jar做在目录等信息提交给yarn取运行
        Boolean res = job.waitForCompletion(true); // 这个方法的作用就是提交,然后把这个处理后的结果打印输出
        System.out.println(res ? "true" : "false");
        return 0;
    }

    public void setConf(Configuration configuration) {
        this.configuration = configuration;
    }

    public Configuration getConf() {
        return configuration;
    }
}

class HBase2HDFSMapper extends TableMapper<Text, NullWritable> {

    private Text k = new Text();

    @Override
    protected void map(ImmutableBytesWritable key, Result result, Context context) throws IOException, InterruptedException {
        //1. 获取到result中的数据并处理
        StringBuffer sb = new StringBuffer();
        CellScanner cellScanner = result.cellScanner();
        while (cellScanner.advance()) {
            Cell cell = cellScanner.current();
            String column = new String(CellUtil.cloneValue(cell), "UTF-8");
            sb.append(column).append(",");
        }
        //2. 写出
        k.set(sb.toString());
        context.write(k, NullWritable.get());
    }
}

1.3.3 异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTy0gWV9-1595216578201)(F:\桌面\笔记\笔记\Hbase\image\009.png)]

分析异常原因:
	我们使用的hadoop jar命令属于hadoop工具的命令,那么在这个时候却调用hbase的scan类,hadoop是没有hbase的jar包资源的。
解决方案:
1.可以将hbase的jar包导入到hadoop的lib中(不推荐)
2.在打jar包的时候吧hbase的jar包打入到我们自己的jar包中(不推荐,因为会让自己的jar变动特别臃肿)
3.最好的方式是,引导hadoop去加载hbase的环境(推荐)
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/opt/apps/hbase-1.2.1/lib/*(只有一次生效)
4. 如果想要永久生效,该如何?
1.3.4 执行命令并测试
[root@qphone01 lib]# hadoop jar /home/hbase2hdfs.jar cn.qphone.hbase.hdfs.HBase2HDFS /output/hbase

2 HDFS读取数据输出到HBase

2.1 需求
统计每个部门的人数,然后存储到HBase
2.2 代码
package cn.qphone.hbase.hdfs;

import cn.qphone.hbase.utils.HBaseUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;
import java.util.Date;
import java.util.Iterator;

public class HDFS2HBase extends ToolRunner implements Tool {

    public static final String COLUMN_FAMILY = "f1";

    private Configuration configuration;

    public static void main(String[] args) throws Exception {
        ToolRunner.run(null, new HDFS2HBase(), args);
    }


    public int run(String[] args) throws Exception {
        Job job = Job.getInstance(configuration);

        //2. 指定本作业需要使用的map阶段和reduce阶段的业务类
        job.setMapperClass(HDFS2HBaseMapper.class);
        //3. 指定最终输出数据的类型,其实就reduce处理之后的
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //4. 指定job的输入原始文件的目录
        //5. 指定job的输入原始文件的目录
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        //6. 表操作
        String tbname = "emp_cnt";
        HBaseUtils.createTable(tbname, HDFS2HBase.COLUMN_FAMILY);

        //7. 指定job的输出目录
        TableMapReduceUtil.initTableReducerJob(tbname, HDFS2HBaseReducer.class, job);

        //8. 指定运行的jar包的所在目录,在这里不使用string参数,是因为使用类额可以通过classloader动态的获取的jar路径
        job.setJarByClass(HDFS2HBase.class);

        //9. 提交 : 将job中配置的相关的参数以及job中使用的jar做在目录等信息提交给yarn取运行
        Boolean res = job.waitForCompletion(true); // 这个方法的作用就是提交,然后把这个处理后的结果打印输出
        System.out.println(res ? "true" : "false");
        return 0;
    }

    public void setConf(Configuration configuration) {
        this.configuration = configuration;
    }

    public Configuration getConf() {
        return configuration;
    }
}

class HDFS2HBaseMapper extends Mapper<LongWritable, Text, Text, IntWritable> {

    private Text k = new Text();
    private IntWritable v = new IntWritable(1);

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString(); // dept:bigdata,job:programer,name:chensheng,nickname:shuaige,
        String[] fields = line.split(",");
        //需要先判断是否有部分
        for (String field : fields) {
            String[] depts = field.split(":");
            if (depts[0].equals("dept")) { // 说明该条记录有部门
                k.set(depts[1]);
                context.write(k, v);
            }else {
                k.set("other");
                context.write(k, v);
            }
        }
    }
}

class HDFS2HBaseReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable> {

    private IntWritable k = new IntWritable();

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        Iterator<IntWritable> iterator = values.iterator();
        int sum = 0;
        while (iterator.hasNext()) {
            int value = iterator.next().get();
            sum += value;
        }
        //1. 设计rowkey
        //1.1 最基本的一个原则就是不重复:UUID、时间戳
        String rk = key.toString() + "_" + new Date().getTime();
        Put put = new Put(Bytes.toBytes(rk));
        put.addColumn(Bytes.toBytes(HDFS2HBase.COLUMN_FAMILY), Bytes.toBytes("cnt"), Bytes.toBytes(sum));
        //1.2 提交
        context.write(new ImmutableBytesWritable(), put);
    }
}


2.3 执行测试
[root@qphone01 home]# hadoop jar /home/hdfs2hbase.jar cn.qphone.hbase.hdfs.HDFS2HBase /output/hbase

十 HBase整合Hive

1 HBase与Hive整合

1.1 当启动hbase之后,再启动hive报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z7r2f0Ym-1595216578203)(./image/010.png)]

原因:当我们整合hive和hbase的时候,hbase需要调度Hadoop底层的jline的jar包,因为hadoop没有所以报错
解决方案:
[root@qphone01 lib]# cp jline-2.12.jar /opt/apps/hadoop-2.8.1/share/hadoop/yarn/lib
1.2 创建hive表从而映射到hbase
create database if not exists hive2hbase;
use hive2hbase;

create table if not exists hive2hbase (
uid int,
uname string,
age int,
sex string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,base_info:name,base_info:age,base_info:sex"
)
tblproperties(
"hbase.table.name"="hive2hbase1"
);
1.3 出现了问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sHFiWXP0-1595216578204)(./image/011.png)]

原因:因为我们hive表映射到hbase需要从hive-hbase-handler-1.2.1.jar中调度一些依赖的类,但是这个jar保重没有,导致这个异常!
解决方案:
对这个hive-hbase-handler-1.2.1.jar进行解包,然后将其需要的资源都拷贝到这个jar中,重新打包,再重新导入到hive的lib中
1.4 处理过程
参考hbase文档第十三章

2 HBase与Hive整合

2.1 建立hbase的表
hbase(main):009:0> create 'dept', 'base_info'
0 row(s) in 2.2940 seconds


=> Hbase::Table - dept
hbase(main):010:0> put 'dept','1', 'base_info:name', 'bigdata'
0 row(s) in 0.0150 seconds

hbase(main):011:0> put 'dept','1', 'base_info:location', 'HZ'
0 row(s) in 0.0120 seconds

hbase(main):012:0> put 'dept','2', 'base_info:name', 'java'
0 row(s) in 0.0100 seconds

hbase(main):013:0> put 'dept','2', 'base_info:location', 'BJ'
0 row(s) in 0.0130 seconds

hbase(main):014:0> put 'dept','3', 'base_info:name', 'H5'
0 row(s) in 0.0100 seconds

hbase(main):016:0> put 'dept','3', 'base_info:location', 'HZ'
2.2 建立Hive表
create external table if not exists hbase2hive2(
uid string,
name string,
location string
)
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties(
"hbase.columns.mapping"=":key,base_info:name,base_info:location"
)
tblproperties(
"hbase.table.name"="dept"
);

tip:反向映射建表,hive必须是外部表

十一 HBase的协处理器

1 二级索引案例

1.1 在hbase中建表

create 'guanzhu', 'cf'
create 'fans', 'cf'

put 'guanzhu', 'wangbaoqiang', 'cf:name', 'ergouzi'
put 'fans', 'ergouzi', 'cf:star', 'wangbaoqiang'

1.2 协处理器完成拉链表操作

package cn.qphone.hbase.coprocessors;

import cn.qphone.hbase.utils.HBaseUtils;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;

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

/**
 * 自定义协处理器,用来实现拉链表操作
 */
public class MyCoprocessor extends BaseRegionObserver {

    /**
     * 在hbase中执行put命令的时候会触发此函数,这个函数会在put命令执行完毕之前被调用
     * put 对象就是put命令执行的时候插入的数据,这些数据被封装到了当前的put对象里面
     * put 'guanzhu', 'wangbaoqiang', 'cf:name', 'ergouzi'
     */
    @Override
    public void prePut(ObserverContext<RegionCoprocessorEnvironment> context, Put put, WALEdit edit, Durability durability) throws IOException {
        //1. 获取到fans表
        Table fans = HBaseUtils.getTable("fans");
        //2. 取出数据,结果是一个行键的一个列的cell,因为可能是多版本的数据,所以是一个list来存放的
        List<Cell> cellList = put.get(Bytes.toBytes("cf"), Bytes.toBytes("name"));
        Cell cell = cellList.get(0); // 最新版
        byte[] rk = CellUtil.cloneRow(cell); // wangbaoqiang
        byte[] cf = CellUtil.cloneFamily(cell); //cf
        byte[] v = CellUtil.cloneValue(cell); //ergouzi
        //3. 创建自己的对象
        //put 'fans', 'ergouzi', 'cf:star', 'wangbaoqiang'
        Put p = new Put(v);
        p.addColumn(cf, Bytes.toBytes("star"), rk);
        fans.put(p);
        //4. 释放资源
        HBaseUtils.close(fans);
    }
}

1.3 上传

1. 将程序打包上传到服务器并修改名称
[root@qphone01 home]# mv day08-hbase-1.0-SNAPSHOT.jar myCoprocessor.jar

2. 上传hdfs中
[root@qphone01 home]# hadoop fs -put myCoprocessor.jar /hbase

1.4 将自定义的协处理器应用到当前的hbase的表中

disable 'guanzhu'
alter 'guanzhu', METHOD => 'table_att', 'coprocessor' =>
'hdfs://qphone01:9000/hbase/myCoprocessor.jar|cn.qphone.hbase.coprocessors.MyCoprocessor|1001|'
enable 'guanzhu'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值