HBase的简单学习二

一 HBase shell

1.1 Region信息观察

1.1.1 创建表加命名空间

1.语法 create '命名空间:表名','列簇名'

2.示例:create 'bigdata29:t1','info'

1.1.2 查看命名空间的表

1.语法 list_namespace_tables '命名空间'

2.示例 list_namespace_tables 'bigdata29'

1.1.3 查看region中的某列簇数据

1.语法 hbase hfile -p -f 查看列簇在habse上的路径

2.实例:

hbase hfile -p -f /hbase/data/default/users/c186f7ae5e27dc820aee1959c269dcc6/detail/693737407e0e476bba4ce8e

c6b9367c6

注意 行键的设计在hbase中有三大设计原则:唯一性 长度不宜过长 散列性

刷新数据:flush 'tb'
合并数据:major_compact 'tb'

1.1.4 查看表的所有region list_regions

1.语法 list_regions '表名'

1.1.5 强制将表切分出来一个region split

1.语法 split '表名','行键'

2.会做负载均衡,如果切分过后在同一个节点上可能不均衡,系统自己会做负载均衡

1.2 预分region解决热点问题

  1. 设计良好的行键

    • 盐值(Salting):通过在行键前添加随机前缀(盐值),可以将数据分散到多个不同的区域。这样,即使原始行键存在热点问题,由于盐值的存在,数据也会被均匀地分散到多个区域中。
    • 反转或哈希行键:对于具有递增或递减趋势的行键,可以考虑反转或哈希行键,以打破这种趋势,使得数据更加均匀地分布在不同的区域中。
  2. 预分区

    • 在创建表时,可以预先设置更多的初始区域,以便在数据写入时,数据可以更加均匀地分布在这些区域中。这有助于减轻单个区域的负载压力。
  3. 使用负载均衡

    • HBase提供了负载均衡机制,可以自动地将负载过重的区域迁移到负载较轻的区域。确保启用了HBase的自动负载均衡功能,并根据需要调整相关参数。
  4. 优化扫描操作

    • 尽量避免全表扫描,因为这会导致大量的数据读取和传输,从而加重HBase的负担。如果需要扫描数据,尽量使用范围扫描或过滤器来减少扫描的数据量。
  5. 增加资源

    • 如果上述方法仍然无法解决热点问题,可以考虑增加HBase集群的资源,如增加更多的RegionServer节点或增加存储设备的容量和性能。
  6. 监控和诊断

    • 使用HBase提供的监控工具和日志来分析系统的运行状况,及时发现并定位热点问题。通过监控数据的读写速率、区域负载、资源利用率等指标,可以更好地了解系统的运行状况,并采取相应的措施来解决热点问题。
  7. 考虑其他存储方案

    • 如果HBase的热点问题无法解决或成本过高,可以考虑使用其他存储方案,如分布式文件系统(如HDFS)、NoSQL数据库或其他大数据存储解决方案,根据具体的应用场景和需求选择合适的存储方案。

1.3 split 建表使用

1.create 'tb_split','cf',SPLITS => ['e','h','l','r'] 这个建表语句是将表根据行名 划分为5个区域

2.添加数据

put 'tb_split','c001','cf:name','first'

put 'tb_split','f001','cf:name','second'

put 'tb_split','z001','cf:name','last'

3.然后去相对的hbase路径寻找

1.4 scan的进阶使用

1.5 查看几条数据

1.5.1 前几条

1.语法

scan '表名',{LIMIT=>数字}

1.5.2 后几条

1.语法

scan '表名',{LIMIT=>数字,REVERSED=>true}

1.5.3 查看指定列的行的几条数据

1.语法 scan '表名',LIMIT=>数字,COLUMNS=>['列簇信息']

scan 'teacher',LIMIT=>3,COLUMNS=>['cf:tid']

1.6 追加

1.语法 append 'teacher','tid00001','cf:name','123'

2.追加到之前的内容上

1.7 get进阶

1.8 incr和counter

1.9 获取region的分割点,清除数据,快照

二 JAVA API

2.1 链接数据库

1.获取hbase集群设置

Configuration conf = HBaseConfiguration.create();

2.设置zookeeper集群

conf.set("hbase.zookeeper.quorum", "master:2181,node1:2181,node2:2181");

3.获取数据库链接对象

conn = ConnectionFactory.createConnection(conf);

这里的参数是hbase集群设置的类

4.获取数据库操作对象

admin = conn.getAdmin(); //使用连接对象获取数据库操作对象

    //数据库连接对象
    private Connection conn;
    //数据库操作对象
    private Admin admin;
    @Before
    public void getConnection(){
       try {
           //获取hbase集群的配置文件对象
           //旧方法
//        HBaseConfiguration conn = new HBaseConfiguration();
           Configuration conf = HBaseConfiguration.create();

           //配置文件要设置你自己的zookeeper集群
           conf.set("hbase.zookeeper.quorum","master:2181,node1:2181,node2:2181");

           //3、获取数据库的连接对象
           Connection conn = ConnectionFactory.createConnection(conf);

           //4、获取数据库操作对象
           admin = conn.getAdmin(); //使用连接对象获取数据库操作对象
           System.out.println("数据库连接对象获取成功!!"+conn);
           System.out.println("数据库操作对象获取成功!!"+admin);
           System.out.println("==========================================");
       }catch (Exception e){
           e.printStackTrace();
       }
    }

2.2 在hbase中创建一张表

1.先将表名封装成一个TableName 的对象,使用ableName中的valueOf

TableName tn = TableName.valueOf("表名");

2.使用 TableDescriptorBuilder 类来创建并获取表描述器对象

TableDescriptorBuilder table = TableDescriptorBuilder.newBuilder(tn);

3.使用ColumnFamilyDescriptorBuilder中的of创建列簇描述器对象

ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");

4.使用表描述器对象中的setColumnFamily方法将列簇与表进行关联

table.setColumnFamily(info);

5.使用数据库操作对象admin中的createTable方法与表描述器对象中的build方法,创建表

admin.createTable(table.build());

    @Test
    public void createOneTable()  {

        try {
            //先将表名封装成一个TableName的对象
            TableName tn = TableName.valueOf("t_user");
            //TableDescriptorBuilder 类来创建并获取表描述器对象
            TableDescriptorBuilder table = TableDescriptorBuilder.newBuilder(tn);
            //创建列簇描述器对象
            ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");
            将列簇与表进行关联
            table.setColumnFamily(info);
            //调用方法,创建表
            admin.createTable(table.build());
            System.out.println(tn+"创建成功");
        }catch (Exception e){
            e.printStackTrace();
        }

    }

2.3 删除一张表

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("表名");

2.判断表是否存在 使用数据库操作对象中的tableExists方法

admin.tableExists(tn)

3.先禁用表 使用admin对象调用方法

admin.disableTable(tn);

4.使用admin对象调用方法删除表

admin.deleteTable(tn);

   @Test
    public void dropOneTable(){
        try {
            //先将表名封装成一个TableName的对象
            TableName tn = TableName.valueOf("ppp");
            //判断表是否存在
            if(admin.tableExists(tn)){
                //先禁用表
                admin.disableTable(tn);
                //使用admin对象调用方法删除表
                //void deleteTable(TableName tableName)
                admin.deleteTable(tn);
                System.out.println(tn+"表成功被删除");
            }else {
                System.out.println(tn+"表不存在!!");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

2.4 向表中添加一行数据

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("students");

2.判断表是否存在

admin.tableExists(tn)

3.获取表对象 使用数据库连接对象conn中的getTable获取表对象,参数是TableName的对象

Table students = conn.getTable(tn);

4.创建put对象,并创建行键

hbase自带的一个工具类Bytes,可以将字符串转字节数组

Put put = new Put(Bytes.toBytes("行键信息"));

5.对put对象进行设置,添加列簇,列名和列值

public Put add(Cell cell)

Cell 是一个接口,无法被实例化,使用实现类KeyValue来创建对象

KeyValue(final byte [] row, final byte [] family, final byte [] qualifier, final byte [] value)

所以:

put.add(new KeyValue(Bytes.toBytes("1001"),

Bytes.toBytes("info"),

Bytes.toBytes("age"),

Bytes.toBytes(18)));

6.需要先将我们添加的列数据封装成一个Put对象

使用的是表对象students 中的put方法 ,里面传入的是put的对象

students.put(put);

try {
            //先将表名封装成一个TableName的对象
            TableName tn = TableName.valueOf("students");
            //判断表是否存在
            if(admin.tableExists(tn)){
                //获取表对象
                Table students = conn.getTable(tn);
                //hbase自带的一个工具类Bytes,可以将字符串转字节数组
                Put put = new Put(Bytes.toBytes("1001"));
                // //KeyValue(final byte [] row, final byte [] family, final byte [] qualifier, final byte [] value)
                put.add(new KeyValue(Bytes.toBytes("1001"),
                        Bytes.toBytes("info"),
                        Bytes.toBytes("age"),
                        Bytes.toBytes(18)));
                students.put(put);
            }else {
                System.out.println(tn+"表不存在!!");
            }
        }catch (Exception e){
            e.printStackTrace();
        }

2.5 向表中添加多列数据

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("表名");

2.创建字符输入缓冲流

br = new BufferedReader(new FileReader("文件路径"));

3.判断表是否存在

admin.tableExists(tn)

4.循环读取数据

默认第一行为行键

String line = null;

while ((line = br.readLine()) != null) {

String[] info = line.split(",");

byte[] rowKey = Bytes.toBytes(info[0]);

//创建这一行的Put对象

Put put = new Put(rowKey);

//第一列作为行键唯一标识,从第二列开始,每一列都要被封装成Put对象

for (int i = 1; i < info.length; i++) {

byte[] colName = Bytes.toBytes(info[i]);

   /**
     * 需求:4、如何向一张表中同时添加一批数据
     */
    @Test
    public void putMoreDataToTable(){
        BufferedReader br = null;
        try {
            //先将表名封装成一个TableName的对象
            TableName tn = TableName.valueOf("students");
            //创建字符输入缓冲流
            br = new BufferedReader(new FileReader("data/students.csv"));

            String[] colNameArray = {"","name","age","gender","clazz"};

            //判断表是否存在
            if(admin.tableExists(tn)){
                //获取表对象
                Table students = conn.getTable(tn);
                //循环读取数据
                String line = null;
                while ((line= br.readLine())!=null){
                    String[] info = line.split(",");
                    byte[] rowKey = Bytes.toBytes(info[0]);
                    //创建这一行的Put对象
                    Put put = new Put(rowKey);
                    //第一列作为行键唯一标识,从第二列开始,每一列都要被封装成Put对象
                    for(int i=1;i<info.length;i++){
                        byte[] colName = Bytes.toBytes(info[i]);
                        put.addColumn(Bytes.toBytes("info"),Bytes.toBytes(colNameArray[i]),Bytes.toBytes(info[i]));
                        //添加该列数据
                        students.put(put);
                    }
                }

                System.out.println("学生表数据添加完毕!!!!");
            }else {
                System.out.println(tn+"表不存在!!");
            }


        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.6 获取一条数据

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("表名");

2.获取表对象 使用数据库连接对象conn中的getTable获取表对象,参数是TableName的对象

Table students = conn.getTable(tn);

3.传入行键的字节数组的形式 使用创建Get对象的构造方法

Get get = new Get(Bytes.toBytes("1500101000"));

4.得到结果对象 使用表对象中的get方法,传入的是Get的对象

Result result = table.get(get);

5.Result类中的常用方法:

* getRow() : 获取行键的字节数组形式

* getValue(byte [] family, byte [] qualifier): 根据列簇和列名,获取列值的字节数组形式

* List<Cell> listCells():获取所有单元格,单元格中存储了行键,列簇,列名,版本号(时间戳),列值

6.已知列名的情况下获取

   //获取行键
            String id = Bytes.toString(result.getRow());
            //获取列名
            String name = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")));
            String age = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")));
            String gender = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("gender")));
            String clazz = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("clazz")));
            System.out.println(id+name+age+gender+clazz);

7.不知道列名的情况下

使用的是CellUtil工具类

增强for循环

//创建单元格
            List<Cell> cells = result.listCells();
            //遍历集合得到每个单元格,获取每个列值
            //增强for循环遍历
            for (Cell cell : cells) {
                String id = Bytes.toString(CellUtil.cloneRow(cell));
                String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
                String colValue = Bytes.toString(CellUtil.cloneValue(cell));
                System.out.println(id+colName+colValue);
            }

forEach+lambda表达式

   cells.forEach(cell -> {
                String id = Bytes.toString(CellUtil.cloneRow(cell));
                String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
                String colValue = Bytes.toString(CellUtil.cloneValue(cell));
                System.out.println(id+colName+colValue);
            });

jdk1.8重新特性

//遍历方式4:jdk1.8新特性遍历,转流处理
            cells.stream().map(e->{
                String id = Bytes.toString(CellUtil.cloneRow(e));
                String colName = Bytes.toString(CellUtil.cloneQualifier(e));
                String colValue = Bytes.toString(CellUtil.cloneValue(e));

                return id+colName+colValue;
            }).forEach(System.out::println);

总体代码

    /**
     * 需求:5、如何获取一条数据
     * get 'students','1500101000'
     */
     @Test
     public void getOneData(){
        try {
            //将表封装成一个TableName对象
            TableName tn = TableName.valueOf("students");
            //获取表对象
            Table table = conn.getTable(tn);
            //传入行键
            Get get = new Get(Bytes.toBytes("1500100979"));

            //通过表对象获取结果
            Result result = table.get(get);
//            System.out.println(result);

            //获取行键
//            String id = Bytes.toString(result.getRow());
            //获取列名
//            String name = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")));
//            String age = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")));
//            String gender = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("gender")));
//            String clazz = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("clazz")));
//            System.out.println(id+name+age+gender+clazz);
            //创建单元格
            List<Cell> cells = result.listCells();
            //遍历集合得到每个单元格,获取每个列值
            //增强for循环遍历
//            for (Cell cell : cells) {
//                String id = Bytes.toString(CellUtil.cloneRow(cell));
//                String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
//                String colValue = Bytes.toString(CellUtil.cloneValue(cell));
//                System.out.println(id+colName+colValue);
//            }

            //遍历方式3:forEach + lambda表达式
//            cells.forEach(cell -> {
//                String id = Bytes.toString(CellUtil.cloneRow(cell));
//                String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
//                String colValue = Bytes.toString(CellUtil.cloneValue(cell));
//                System.out.println(id+colName+colValue);
//            });
            //遍历方式4:jdk1.8新特性遍历,转流处理
            cells.stream().map(e->{
                String id = Bytes.toString(CellUtil.cloneRow(e));
                String colName = Bytes.toString(CellUtil.cloneQualifier(e));
                String colValue = Bytes.toString(CellUtil.cloneValue(e));

                return id+colName+colValue;
            }).forEach(System.out::println);

2.7获取一批数据

2.7.1 get

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("表名");

2.获取表对象 使用数据库连接对象conn中的getTable获取表对象,参数是TableName的对象

Table students = conn.getTable(tn);

3.创建集合,存储行键,传入行键的字节数组的形式 使用创建Get对象的构造方法

ArrayList<Get> gets = new ArrayList<>();

for (int i = 1500100001; i <= 1500101000; i++) {

gets.add(new Get(Bytes.toBytes(String.valueOf(i))));

}

这里要转成字符串

4.得到结果对象集合 使用表对象中的get方法,传入的是Get的对象

Result[] results = table.get(get);

5.遍历results 获取每一个result

for (Result result : results) {

List<Cell> cells = result.listCells();

6.遍历每一个result 获取每一列

for (Result result : results) {
                List<Cell> cells = result.listCells();
                if (cells!=null){
                    cells.stream().map(cell -> {
                        String id = Bytes.toString(CellUtil.cloneRow(cell));
                        String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
                        String colValue = Bytes.toString(CellUtil.cloneValue(cell));
                        return id+colName+colValue;
                    }).forEach(System.out::println);
                    System.out.println("====================");
                }else {
                    System.out.println("kong");
                }
            }

    /**
     * 6、如果获取一批数据 第一种方式
     */
    @Test
    public void getMoreData(){
        try {
            //将表封装成一个TableName对象
            TableName tn = TableName.valueOf("students");
            //获取表对象
            Table table = conn.getTable(tn);
            //创建List集合,存储多个Get对象
            //1500100001 ~ 1500101000
            ArrayList<Get> gets = new ArrayList<>();
            for (int i = 1500100001; i <= 1500101000; i++) {
                gets.add(new Get(Bytes.toBytes(String.valueOf(i))));
            }
            //default Result[] get(List<Get> gets)
            Result[] results = table.get(gets);
            //1、先遍历results得到每一个result(每一行)
            //2、遍历每一个result中的每一列
            for (Result result : results) {
                List<Cell> cells = result.listCells();
                if (cells!=null){
                    cells.stream().map(cell -> {
                        String id = Bytes.toString(CellUtil.cloneRow(cell));
                        String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
                        String colValue = Bytes.toString(CellUtil.cloneValue(cell));
                        return id+colName+colValue;
                    }).forEach(System.out::println);
                    System.out.println("====================");
                }else {
                    System.out.println("kong");
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

2.7.2 scan

1.先将表名封装成一个TableName的对象

TableName tn = TableName.valueOf("表名");

2.获取表对象 使用数据库连接对象conn中的getTable获取表对象,参数是TableName的对象

Table students = conn.getTable(tn);

3.创建scan对象,并设置sacn

Scan scan = new Scan(); //查询表中的所有行

scan.withStartRow(Bytes.toBytes("1500100001"));//设置起始行

// scan.withStopRow(Bytes.toBytes("1500100004"), true);设置末尾行,有true表示包含这一行

//设置取前几行

scan.setLimit(10);

/**
     * 7、如果获取一批数据 第二种方式
     * scan 'students' 默认情况下获取表所有数据
     * scan 'students',LIMIT=>3
     */
    @Test
    public void ScanData(){
        try {
            //将表封装成一个TableName对象
            TableName tn = TableName.valueOf("students");
            //获取表对象
            Table table = conn.getTable(tn);
            //创建scan对象
            Scan scan = new Scan();//查询所有行
            //可以设置scan
            scan.withStartRow(Bytes.toBytes("1500100001"));
//            scan.withStopRow(Bytes.toBytes("1500100004"), true);
            //设置前几行
            scan.setLimit(10);
            //创建结果对象
            ResultScanner resultScanner = table.getScanner(scan);
            //获取迭代器对象
            for (Result result : resultScanner) {
                //不知道列名的情况下
                //                List<Cell> cells = result.listCells();
//                cells.stream().map(cell -> {
//                    String id = Bytes.toString(CellUtil.cloneRow(cell));
//                    String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
//                    String colValue = Bytes.toString(CellUtil.cloneValue(cell));
//                    return id+colName+colValue;
//                    }).forEach(System.out::println);
//                    System.out.println("====================");
                //知道列名
                // 获取行键
                String id = Bytes.toString(result.getRow());
                //获取列名
                String name = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")));
                String age = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("age")));
                String gender = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("gender")));
                String clazz = Bytes.toString(result.getValue(Bytes.toBytes("info"), Bytes.toBytes("clazz")));
                System.out.println(id + name + age + gender + clazz);

            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

2.8 创建预分表

1.先将表名封装成一个TableName 的对象,使用ableName中的valueOf

TableName tn = TableName.valueOf("表名");

2.使用 TableDescriptorBuilder 类来创建并获取表描述器对象

TableDescriptorBuilder table = TableDescriptorBuilder.newBuilder(tn);

3.使用ColumnFamilyDescriptorBuilder中的of创建列簇描述器对象

ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");

4.使用表描述器对象中的setColumnFamily方法将列簇与表进行关联

table.setColumnFamily(info);

5.创建预分二维数组

预分点是字节类型

6.调用另外一个方法,传入表描述器的同时,传入分割点,创建预分region表

    /**
     * 需求:7、如何创建预分region表
     * 将来对于某一个RegionServer而言,可能会接收大量的并发请求,超出了该RegionServer承受的压力,有可能会导致该子节点崩溃
     * 如果大量的并发请求查询的数据是多种多种多样的,只不过巧合的是都在一个RegionServer上管理
     * 解决的思路:分散查询的数据到不同的RegionServer上,这样请求也会随着被分散到不同的RegionServer上,就达到了减轻某一个RegionServer压力过大情况,解决了单点故障的问题
     */
    @Test
    public void createPreviewTable(){
        try {
            //先将表名封装成TableName对象
            TableName tn = TableName.valueOf("t_split");
            //创建表描述器对象
            TableDescriptorBuilder table = TableDescriptorBuilder.newBuilder(tn);
            //创建列簇描述器对象
            ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");
            将列簇与表进行关联
            table.setColumnFamily(info);
            //创建分割键的二维数组
            byte[][] splitKeys = {
                    Bytes.toBytes("f"),
                    Bytes.toBytes("k"),
                    Bytes.toBytes("p")
            };
            //调用方法,创建表
            admin.createTable(table.build(),splitKeys);
            System.out.println(tn+"创建成功");
            
        }catch (Exception e){
            e.printStackTrace();
        }
    }
相关推荐
HC1825808583212 分钟前
“倒时差”用英语怎么说?生活英语口语学习柯桥外语培训
学习·生活
学习路上_write16 分钟前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
喵叔哟17 分钟前
重构代码之移动字段
java·数据库·重构
念白44321 分钟前
智能病历xml提取
数据库·sql·oracle
非概念22 分钟前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
qingy_204625 分钟前
【JavaWeb】JavaWeb入门之XML详解
数据库·oracle
大数据面试宝典29 分钟前
用AI来写SQL:让ChatGPT成为你的数据库助手
数据库·人工智能·chatgpt
努力的小雨34 分钟前
快速上手 KSQL:轻松与数据库交互的利器
数据库·经验分享
Gentle58636 分钟前
labview中连接sql server数据库查询语句
数据库·labview
Gentle58637 分钟前
labview用sql server数据库存取数据到一个单元格
数据库·labview