头歌实践教学平台:大数据存储2023(六)

六、HBase 开发:批量操作

第1关:批量获取数据

任务描述

本关任务:编写Java程序批量获取HBase中指定表的所有数据。

相关知识

在上次实训中我们是这样获取数据的:

Get get = new Get(Bytes.toBytes("row1"));//定义get对象

Result result = table.get(get);//通过table对象获取数据

那么问题来了,我们想要获取多条数据,比如说查询1万条数据怎么办呢?

可能我们第一时间就会想到循环,例如:

String tableName = "test";

Table table = connection.getTable( TableName.valueOf(tableName));// 获取表

for (String rowkey : rowkeyList){

Get get = new Get(Bytes.toBytes(rowkey));

Result result = table.get(get);

for (Cell kv : result.rawCells()) {

String value = Bytes.toString(CellUtil.cloneValue(kv));

list.add(value);

}

}

这样做是非常低效的,如果有10000条数据那我们需要发送10000次请求,这样非常耗时,如果在自己本机上尝试,查询时间可能在5分钟左右。

这样肯定不行,我们在HBase的Table对象和子类的源码中找找看有没有解决办法,忽然眼前一亮:

public Result\[\] get(List<Get> gets) throws IOException {

if (gets.size() == 1) {

return new Result\[\]{get(gets.get(0))};

}

try {

Object\[\] r1 = new Objectgets.size();

batch((List<? extends Row>)gets, r1, readRpcTimeoutMs);

// Translate.

Result \[\] results = new Resultr1.length;

int i = 0;

for (Object obj: r1) {

// Batch ensures if there is a failure we get an exception instead

resultsi++ = (Result)obj;

}

return results;

} catch (InterruptedException e) {

throw (InterruptedIOException)new InterruptedIOException().initCause(e);

}

}

使用get函数批量获取数据

查看HBase的API,我们可以发现Table对象的get()函数不仅可以接收Get对象,也同样可以接收Get集合,现在我们试试get(List<Get> gets)函数的效果如何。

public List<String> getData(Table table, List<String> rows) throws Exception {

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

for (String str : rows) {

Get get = new Get(Bytes.toBytes(str));

gets.add(get);

}

List<String> values = new ArrayList<>();

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

for (Result result : results) {

System.out.println("Row:" + Bytes.toString(result.getRow()));

for (Cell kv : result.rawCells()) {

String family = Bytes.toString(CellUtil.cloneFamily(kv));

String qualifire = Bytes.toString(CellUtil.cloneQualifier(kv));

String value = Bytes.toString(CellUtil.cloneValue(kv));

values.add(value);

System.out.println(family + ":" + qualifire + "\t" + value);

}

}

return values;

}

根据这种批量的方法,10000个row进行查询,时间稳定在4s之内,

使用上述代码查询下表:

输出结果:

Row:20001

data:1 value1

data:2 value2

data:3 value3

data:4 value4

Row:20002

data:1 name1

data:2 name2

data:3 name3

data:4 name4

代码解释:

table.get(gets)会返回一个Result\[\]结果数组,里面存放了本次查询的所有数据,我们可以通过这个数组来遍历我们需要的数据;

result.rawCells(),result是单个结果,这里存放的是一行的所有数据,result的rowCells()方法会返回这一行所有的列(Cell)的集合;

Cell对象是单个的列,要获取列中的值可以通过CellUtil.cloneXXX()方法,如cloneValue(cell)就会返回该列的值。

编程要求

好了,到你啦,使用本关知识,在右侧编辑器begin-end处补充代码,现有表step1_student如下:

需要你编写程序获取表中行键为2018和2020的数据并输出。

测试说明

预期输出:

Row:2018

basic_info:birthday 1987-05-23

basic_info:gender male

basic_info:name 张飞

school_info:class class 1 grade 2

school_info:college ChengXing

school_info:object Software

Row:2020

basic_info:birthday 1985-05-23

basic_info:gender male

basic_info:name 黄忠

school_info:class class 2 grade 2

school_info:college Harvard

school_info:object Construction

注意:

你可以在Begin...End之外定义函数,但请不要改变原有的函数以及类。

点击测评之前,请先开启Hadoop(start-dfs.sh)和HBase(start-hbase.sh),并且需要等待HBase初始化完成(20秒左右),否则无法在 HBase中创建表。

怎么查看HBase初始化成功了呢?

输入hadoop fs -ls /hbase有如下结果即可:

如果启动过程中出现:

datanode running as process 214. Stop it first.说明Hadoop的进程还没有被杀死。

需要我们重新stop-dfs.sh 和stop-hbase.sh,然后在重启。

开始你的任务吧,祝你成功!

package step1;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.Cell;

import org.apache.hadoop.hbase.CellScanner;

import org.apache.hadoop.hbase.CellUtil;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.client.Admin;

import org.apache.hadoop.hbase.client.Connection;

import org.apache.hadoop.hbase.client.ConnectionFactory;

import org.apache.hadoop.hbase.client.Get;

import org.apache.hadoop.hbase.client.HTable;

import org.apache.hadoop.hbase.client.Result;

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.client.TableDescriptor;

import org.apache.hadoop.hbase.generated.rest.rest_jsp;

import org.apache.hadoop.hbase.util.Bytes;

public class Task {

public void batchGet() throws Exception {

/********* Begin *********/

Configuration config = HBaseConfiguration.create();

Connection Connection = ConnectionFactory.createConnection(config);

List<String> rows = new ArrayList<>();

rows.add("2018");

//rows.add("2019");

rows.add("2020");

TableName tableName = TableName.valueOf(Bytes.toBytes("step1_student"));

Table table = Connection.getTable(tableName);

getData(table,rows);

/********* End *********/

}

public List<String> getData(Table table, List<String> rows) throws Exception {

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

for (String str : rows) {

Get get = new Get(Bytes.toBytes(str));

gets.add(get);

}

List<String> values = new ArrayList<>();

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

for (Result result : results) {

System.out.println("Row:" + Bytes.toString(result.getRow()));

for (Cell kv : result.rawCells()) {

String family = Bytes.toString(CellUtil.cloneFamily(kv));

String qualifire = Bytes.toString(CellUtil.cloneQualifier(kv));

String value = Bytes.toString(CellUtil.cloneValue(kv));

values.add(value);

System.out.println(family + ":" + qualifire + "\t" + value);

}

}

return values;

}

}

第2关:批量删除数据

任务描述

本关任务:使用HJavaApi批量删除表中的数据。

相关知识

删除单行数据

删除一行数据很简单,我们来看个示例:

Table table = conn.getTable(tableName); //获取表

byte\[\] row = Bytes.toBytes("row1");//定义行

Delete delete = new Delete(row);//创建delete对象

table.delete(delete);//删除

这段代码就可以删除行键为row1的行。

删除多行数据

如何删除多行数据呢?

相信你已经猜到了,既然get()方法有重载方法,那应该delete()方法也有,确实:

Table table = conn.getTable(tableName);

List<Delete> deletes = new ArrayList<>();

for(int i = 1 ; i < 5;i++){

byte\[\] row = Bytes.toBytes("row" + i);

Delete delete = new Delete(row);

deletes.add(delete);

}

table.delete(deletes);

这样就可以删除多行数据啦。

编程要求

还等啥,亲自试一试吧,使用本关知识,在右侧编辑器begin-end处补充代码,现有表step2_table,请编写程序删除该表行键为row1至row5和row7至row10的数据。

测试说明

预期输出:

Row:null

Row:null

Row:null

Row:null

Row:null

Row:row6

data:0 value0

data:1 value1

data:2 value2

Row:null

Row:null

Row:null

Row:null

Row:row11

data:0 value0

data:1 value1

data:2 value2

Row:row12

data:0 value0

data:1 value1

data:2 value2

开始你的任务吧!

package step2;

import java.io.IOException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.HColumnDescriptor;

import org.apache.hadoop.hbase.HTableDescriptor;

import org.apache.hadoop.hbase.TableDescriptors;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.client.*;

import org.apache.hadoop.hbase.util.Bytes;

public class Task {

public void batchDelete()throws Exception{

/********* Begin *********/

Configuration conf = HBaseConfiguration.create();

Connection conn = ConnectionFactory.createConnection(conf);

TableName tableName = TableName.valueOf("step2_table");

Table table = conn.getTable(tableName);

List<String> rows1 = new ArrayList();

for(int i = 1; i<6;i++){

String row = "row" + i;

rows1.add(row);

}

delete(table,rows1);

List<String> rows2 = new ArrayList<>();

for(int i = 7;i<11;i++){

String row = "row" + i;

rows2.add(row);

}

delete(table,rows2);

/********* End *********/

}

public void delete(Table table,List<String> rows)throws IOException{

List<Delete> deletes = new ArrayList<>();

for(String str : rows){

byte\[\] row = Bytes.toBytes(str);

Delete delete = new Delete(row);

deletes.add(delete);

}

table.delete(deletes);

}

}

第3关:批量导入数据至HBase

任务描述

本关任务:使用Java程序向HBase中批量导入数据。

相关知识

每一次只添加一个数据显然不像是大数据开发,在开发项目的时候也肯定会涉及到大量的数据操作。

使用Java进行批量数据操作,其实就是循环的在Put对象中添加数据最后在通过Table对象提交。

如何进行批量操作呢,讲到批量操作,相信大家肯定第一时间会想到循环?

没错,使用循环确实就可以添加多个数据了,示例:

Table tableStep3 = connection.getTable(tableStep3Name);

// 循环添加数据

byte\[\] row = Bytes.toBytes("20001");

Put put = new Put(row);

for (int i = 1; i <= 4; i++) {

byte\[\] columnFamily = Bytes.toBytes("data");

byte\[\] qualifier = Bytes.toBytes(String.valueOf(i));

byte\[\] value = Bytes.toBytes("value" + i);

put.addColumn(columnFamily, qualifier, value);

}

tableStep3.put(put);

代码执行结果:

可以发现,这一段代码向同一个行中添加了四列数据。

我们要添加多行数据应该如何处理呢,我猜你肯定想到了:使用集合!

List<Put> puts = new ArrayList<>();

// 循环添加数据

for (int i = 1; i <= 4; i++) {

byte\[\] row = Bytes.toBytes("row" + i);

Put put = new Put(row);

byte\[\] columnFamily = Bytes.toBytes("data");

byte\[\] qualifier = Bytes.toBytes(String.valueOf(i));

byte\[\] value = Bytes.toBytes("value" + i);

put.addColumn(columnFamily, qualifier, value);

puts.add(put);

}

Table table = connection.getTable(tableName);

table.put(puts);

上述代码向HBase中添加了四行数据,结合上次实训,可以发现table对象的put()方法是一个重载方法既可以接收Put对象也可以接收Put集合。

添加完数据的表结构:

编程要求

好了,到你啦,在右侧编辑器begin-end中编写Java代码向HBase的stu表(表需要自己创建)中添加数据如下:

表名 行键 列族:列 值

stu 20181122 basic_info:name 阿克蒙德

stu 20181122 basic_info:gender male

stu 20181122 basic_info:birthday 1987-05-23

stu 20181122 basic_info:connect tel:13974036666

stu 20181122 basic_info:address HuNan-ChangSha

stu 20181122 school_info:college ChengXing

stu 20181122 school_info:class class 1 grade 2

stu 20181122 school_info:object Software

stu 20181123 basic_info:name 萨格拉斯

stu 20181123 basic_info:gender male

stu 20181123 basic_info:birthday 1986-05-23

stu 20181123 basic_info:connect tel:18774036666

stu 20181123 basic_info:address HuNan-ChangSha

stu 20181123 school_info:college ChengXing

stu 20181123 school_info:class class 2 grade 2

stu 20181123 school_info:object Software

可以发现这里有两个列族,如何添加多个列族呢?

在我们之前讲到的建表中setColumnFamily(family)方法,这个方法是可以调用多次的。

测试说明

平台会执行你的代码,并且会输出表的数据,如果批量导入的数据是符合的将会输出:

Row:20181122

basic_info:address HuNan-ChangSha

basic_info:birthday 1987-05-23

basic_info:connect tel:13974036666

basic_info:gender male

basic_info:name 阿克蒙德

school_info:class class 1 grade 2

school_info:college ChengXing

school_info:object Software

Row:20181123

basic_info:address HuNan-ChangSha

basic_info:birthday 1986-05-23

basic_info:connect tel:18774036666

basic_info:gender male

basic_info:name 萨格拉斯

school_info:class class 2 grade 2

school_info:college ChengXing

school_info:object Software

在测评完之后我会将你创建的stu表删除,以免影响下一次测评。

开始你的任务吧,祝你成功!

package step3;

import java.io.IOException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.HColumnDescriptor;

import org.apache.hadoop.hbase.HTableDescriptor;

import org.apache.hadoop.hbase.TableDescriptors;

import org.apache.hadoop.hbase.TableName;

import org.apache.hadoop.hbase.client.Admin;

import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;

import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;

import org.apache.hadoop.hbase.client.Connection;

import org.apache.hadoop.hbase.client.ConnectionFactory;

import org.apache.hadoop.hbase.client.Get;

import org.apache.hadoop.hbase.client.Put;

import org.apache.hadoop.hbase.client.Result;

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.client.TableDescriptor;

import org.apache.hadoop.hbase.client.TableDescriptorBuilder;

import org.apache.hadoop.hbase.util.Bytes;

public class Task {

public void batchPut()throws Exception{

/********* Begin *********/

Configuration config = new Configuration();

Connection conn = ConnectionFactory.createConnection(config);

Admin admin = conn.getAdmin();

// 建表

TableName tableName = TableName.valueOf(Bytes.toBytes("stu"));

TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName);

ColumnFamilyDescriptor family = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("basic_info")).build();

ColumnFamilyDescriptor family2 = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("school_info")).build();

builder.setColumnFamily(family);

builder.setColumnFamily(family2);

admin.createTable(builder.build());

List<Put> puts = new ArrayList<>();

String\[\] rows = {"20181122","20181123"};

String\[\]\[\] basic_infos = {{"阿克蒙德","male","1987-05-23","tel:139********","HUNan-ChangSha"},{"萨格拉斯","male","1986-05-23","tel:187********","HUNan-ChangSha"}};

String\[\] basic_colums = {"name","gender","birthday","connect","address"};

String\[\]\[\] school_infos = {{"ChengXing","class 1 grade 2","Software"},{"ChengXing","class 2 grade 2","Software"}};

String\[\] school_colums = {"college","class","object"};

for (int x = 0; x < rows.length; x++) {

// 循环添加数据

Put put = new Put(Bytes.toBytes(rowsx));

for (int i = 0; i < basic_infos.length; i++) {

byte\[\] columFamily = Bytes.toBytes("basic_info");

byte\[\] qualifier = Bytes.toBytes(basic_columsi);

byte\[\] value = Bytes.toBytes(basic_infosxi);

put.addColumn(columFamily, qualifier, value);

}

for (int i = 0; i < school_infos.length; i++) {

byte\[\] columFamily = Bytes.toBytes("school_info");

byte\[\] qualifier = Bytes.toBytes(school_columsi);

byte\[\] value = Bytes.toBytes(school_infosxi);

put.addColumn(columFamily, qualifier, value);

}

puts.add(put);

}

Table table = conn.getTable(tableName);

table.put(puts);

/********* End *********/

}

}

有任何问题都可以随时关注私信!

相关推荐
世岩清上1 小时前
新能源宣传片怎么拍?如何用画面讲好你的绿色能源故事
大数据·人工智能·能源·宣传片·宣传片拍摄
for_ever_love__1 小时前
python基础语法学习: 闭包
开发语言·python·学习·闭包
ly76891 小时前
Python 全面入门:从核心语法到工程实践
开发语言·python
Elastic 中国社区官方博客2 小时前
让大模型思考,让小模型执行:在 Elastic Workflows 中拆分 LLM 成本
大数据·运维·数据库·人工智能·elasticsearch·ai
Faith_xzc2 小时前
一条 SQL 顶一条 Flink 链路?Doris Streaming Job 持续导入全景解析
大数据·数据库·sql·flink
SXkehuirongsheng3 小时前
APP开发定制和模板开发哪个更实用?
大数据·运维·人工智能
Niuguangshuo3 小时前
DeepFilterNet 3:端侧实时全带降噪的开源标杆
python
第一程序员3 小时前
AI 辅助编程的 7 个误区:把模型当高级搜索引擎是对它的最大浪费
python·rust·github
醉颜凉4 小时前
Elasticsearch底层原理:文档更新与删除完整执行流程深度剖析
大数据·elasticsearch·jenkins