一、实验目的
(1)理解HBase在Hadoop体系结构中的角色;
(2)熟练使用HBase操作常用的Shell命令;
(3)熟悉HBase操作常用的Java API。
二、实验平台
(1)操作系统:Linux(建议Ubuntu16.04或Ubuntu18.04);
(2)Hadoop版本:3.1.3;
(3)HBase版本:2.2.2;
(4)JDK版本:1.8;
(5)Java IDE:Eclipse。
三、实验内容
(一)编程实现以下指定功能,并用Hadoop提供的HBase Shell命令完成相同任务:
(1) 列出HBase所有的表的相关信息,例如表名;
(2) 在终端打印出指定的表的所有记录数据;
(3) 向已经创建好的表添加和删除指定的列族或列;
(4) 清空指定的表的所有记录数据;
(5) 统计表的行数。
(二)HBase数据库操作
1. 现有以下关系型数据库中的表和数据(见表14-3到表14-5),要求将其转换为适合于HBase存储的表并插入数据:
表14-3 学生表(Student)
学号(S_No) 姓名(S_Name) 性别(S_Sex) 年龄(S_Age)
2015001 Zhangsan male 23
2015002 Mary female 22
2015003 Lisi male 24
表14-4 课程表(Course)
课程号(C_No) 课程名(C_Name) 学分(C_Credit)
123001 Math 2.0
123002 Computer Science 5.0
123003 English 3.0
表14-5 选课表(SC)
学号(SC_Sno) 课程号(SC_Cno) 成绩(SC_Score)
2015001 123001 86
2015001 123003 69
2015002 123002 77
2015002 123003 99
2015003 123001 98
2015003 123002 95
2. 请编程实现以下功能:
(1)createTable(String tableName, String[] fields)
创建表,参数tableName为表的名称,字符串数组fields为存储记录各个字段名称的数组。要求当HBase已经存在名为tableName的表的时候,先删除原有的表,然后再创建新的表。
(2)addRecord(String tableName, String row, String[] fields, String[] values)
向表tableName、行row(用S_Name表示)和字符串数组fields指定的单元格中添加对应的数据values。其中,fields中每个元素如果对应的列族下还有相应的列限定符的话,用“columnFamily:column”表示。例如,同时向“Math”、“Computer Science”、“English”三列添加成绩时,字符串数组fields为{“Score:Math”, ”Score:Computer Science”, ”Score:English”},数组values存储这三门课的成绩。
(3)scanColumn(String tableName, String column)
浏览表tableName某一列的数据,如果某一行记录中该列数据不存在,则返回null。要求当参数column为某一列族名称时,如果底下有若干个列限定符,则要列出每个列限定符代表的列的数据;当参数column为某一列具体名称(例如“Score:Math”)时,只需要列出该列的数据。
(4)modifyData(String tableName, String row, String column)
修改表tableName,行row(可以用学生姓名S_Name表示),列column指定的单元格的数据。
(5)deleteRow(String tableName, String row)
删除表tableName中row指定的行的记录。
四、实验过程、内容
(一)编程实现以下指定功能
用Hadoop提供的HBase Shell命令完成相同任务:
(1) 列出HBase所有的表的相关信息,例如表名;
(2)在终端打印出指定的表的所有记录数据;
(3)向已经创建好的表添加和删除指定的列族或列;
(4)清空指定的表的所有记录数据;
(5) 统计表的行数。
(二)HBase数据库操作
1.将关系型数据库中的表和数据转换为适合于HBase存储的表并插入数据
现有以下关系型数据库中的表和数据(见表14-3到表14-5),要求将其转换为适合于HBase存储的表并插入数据:
表14-3 学生表(Student)
学号(S_No) 姓名(S_Name) 性别(S_Sex) 年龄(S_Age)
2015001 Zhangsan male 23
2015002 Mary female 22
2015003 Lisi male 24
create 'Student','S_No','S_Name','S_Sex','S_Age'
put 'Student','1','S_No','2015001'
put 'Student','2','S_No','2015002'
put 'Student','3','S_No','2015003'
put 'Student','1','S_Name','Zhangsan'
put 'Student','2','S_Name','Mary'
put 'Student','3','S_Name','Lisi'
put 'Student','1','S_Sex','male'
put 'Student','2','S_Sex','felmale'
put 'Student','3','S_Sex','male'
put 'Student','1','S_Age','23'
put 'Student','2','S_Age','22'
put 'Student','3','S_Age','24'
表14-4 课程表(Course)
课程号(C_No) 课程名(C_Name) 学分(C_Credit)
123001 Math 2.0
123002 Computer Science 5.0
123003 English 3.0
create 'Course','C_No','C_Name','C_Credit'
put 'Course','1','C_No','123001'
put 'Course','2','C_No','123002'
put 'Course','3','C_No','123003'
put 'Course','1','C_Name','Math'
put 'Course','2','C_Name','Computer Science'
put 'Course','3','C_Name','English'
put 'Course','1','C_Credit','2.0'
put 'Course','2','C_Credit','5.0'
put 'Course','3','C_Credit','3.0'
表14-5 选课表(SC)
学号(SC_Sno) 课程号(SC_Cno) 成绩(SC_Score)
2015001 123001 86
2015001 123003 69
2015002 123002 77
2015002 123003 99
2015003 123001 98
2015003 123002 95
create 'SC','SC_Sno','SC_Cno','SC_Sorce'
put 'SC','1','SC_Sno','2015001'
put 'SC','2','SC_Sno','2015001'
put 'SC','3','SC_Sno','2015002'
put 'SC','4','SC_Sno','2015002'
put 'SC','5','SC_Sno','2015003'
put 'SC','6','SC_Sno','2015003'
put 'SC','1','SC_Cno',’123001’
put 'SC','2','SC_Cno','123003'
put 'SC','3','SC_Cno','123002'
put 'SC','4','SC_Cno','123003'
put 'SC','5','SC_Cno','123001'
put 'SC','6','SC_Cno','123002'
put 'SC','1','SC_Score’,’123001’
put 'SC','2','SC_Cno','123003'
put 'SC','3','SC_Cno','123002'
put 'SC','4','SC_Cno','123003'
put 'SC','5','SC_Cno','123001'
put 'SC','6','SC_Cno','123002'
2. 请编程实现以下功能:
(1)createTable(String tableName, String[] fields)
创建表,参数tableName为表的名称,字符串数组fields为存储记录各个字段名称的数组。要求当HBase已经存在名为tableName的表的时候,先删除原有的表,然后再创建新的表。
(2)addRecord(String tableName, String row, String[] fields, String[] values)
向表tableName、行row(用S_Name表示)和字符串数组fields指定的单元格中添加对应的数据values。其中,fields中每个元素如果对应的列族下还有相应的列限定符的话,用“columnFamily:column”表示。例如,同时向“Math”、“Computer Science”、“English”三列添加成绩时,字符串数组fields为{“Score:Math”, ”Score:Computer Science”, ”Score:English”},数组values存储这三门课的成绩。
(3)scanColumn(String tableName, String column)
浏览表tableName某一列的数据,如果某一行记录中该列数据不存在,则返回null。要求当参数column为某一列族名称时,如果底下有若干个列限定符,则要列出每个列限定符代表的列的数据;当参数column为某一列具体名称(例如“Score:Math”)时,只需要列出该列的数据。
(4)modifyData(String tableName, String row, String column)
修改表tableName,行row(可以用学生姓名S_Name表示),列column指定的单元格的数据。
(5)deleteRow(String tableName, String row)
删除表tableName中row指定的行的记录。
//HBaseStudentOperation.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
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.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Mutation;
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.TableDescriptorBuilder;
import org.apache.hadoop.hbase.util.Bytes;
import com.google.common.collect.Table.Cell;
public class HBaseStudentOperation {
public static Configuration configuration;
public static Connection connection;
public static Admin admin;
public static ArrayList<String> fields = new ArrayList<String>();
public static void init(){
configuration = HBaseConfiguration.create();
configuration.set("hbase.rootdir","hdfs://localhost:9000/hbase");
try{
connection = ConnectionFactory.createConnection(configuration);
admin = connection.getAdmin();
}catch (IOException e){
e.printStackTrace();
}
}
public static void close(){
try{
if(admin != null){
admin.close();
}
if(null != connection){
connection.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
public static void createTable(String tableName, String[] fields) throws IOException {
init(); //建立与hbase的链接
TableName tablename = TableName.valueOf(tableName);
if (admin.tableExists(tablename)) { //如果表已经存在
System.out.println("这个"+tablename+"表已经存在咯!"); //打印表存在
admin.disableTable(tablename); //禁用表
admin.deleteTable(tablename); //删除表
}
HTableDescriptor hTableDescriptor = new HTableDescriptor(tablename);
for (String str : fields) { //将存在fields的多个属性值去除添加进表
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(str);
hTableDescriptor.addFamily(hColumnDescriptor);
}
admin.createTable(hTableDescriptor);
System.out.println("创建了"+tablename+"表");
close();
}
//删表
public static void deleteTable(String tableName) throws IOException {
init();
TableName tn = TableName.valueOf(tableName);
if (admin.tableExists(tn)) {
admin.disableTable(tn);
admin.deleteTable(tn);
}
close();
}
public static void addRecord(String tableName, String row, String[] fields, String[] values) throws IOException {
init();
Table table = connection.getTable(TableName.valueOf(tableName));
for (int i = 0; i != fields.length; i++) {
Put put = new Put(row.getBytes());
String[] cols = fields[i].split(":");
put.addColumn(cols[0].getBytes(), cols[1].getBytes(), values[i].getBytes());
table.put(put);
}
table.close();
System.out.println("这个"+row+"列放入了列限定和值!"); //打印列删除
close();
}
public static void showCell(Result result) {
Cell[] cells = (Cell[]) result.rawCells();
for (Cell cell : cells) {
System.out.println("rowKey: " + new String(CellUtil.cloneRow((org.apache.hadoop.hbase.Cell) cell)));
System.out.println("colFamily: " + new String(CellUtil.cloneFamily((org.apache.hadoop.hbase.Cell) cell)));
System.out.println("clomn: " + new String(CellUtil.cloneQualifier((org.apache.hadoop.hbase.Cell) cell)));
System.out.println("timesTamp: " + ((Mutation) cell).getTimestamp());
System.out.println("value: " + new String(CellUtil.cloneValue((org.apache.hadoop.hbase.Cell) cell)));
}
}
public static void scanColumn(String tableName, String column) throws Exception {
init();
Table table = connection.getTable(TableName.valueOf(tableName));
Scan scan = new Scan();
String[] cols = column.split(":");
if (cols.length == 1) {
scan.addFamily(Bytes.toBytes(column));
} else {
scan.addColumn(Bytes.toBytes(cols[0]), Bytes.toBytes(cols[1]));
}
ResultScanner scanner = table.getScanner(scan);
for (Result result = scanner.next();result!=null;result=scanner.next()) {
showCell(result);
}
table.close();
close();
}
//修改表tableName
public static void modifyData(String tableName, String row, String column, String val) throws IOException {
long ts = 0;
init();
Table table = connection.getTable(TableName.valueOf(tableName));
Put put = new Put(row.getBytes());
Scan scan = new Scan();
ResultScanner resultScanner = table.getScanner(scan);
for (Result r : resultScanner) {
for (org.apache.hadoop.hbase.Cell cell : r.getColumnCells(row.getBytes(), column.getBytes())) {
ts = cell.getTimestamp();
}
}
put.addColumn(row.getBytes(), column.getBytes(), ts, val.getBytes());
table.put(put);
System.out.println(tableName+"表的"+row+"行的"+column+"列已经修改为:"+val); //打印列删除
table.close();
close();
}
//删除数据
public static void deleteRow(String tableName, String row) throws IOException {
init();
Table table = connection.getTable(TableName.valueOf(tableName));
Delete delete=new Delete(row.getBytes());
table.delete(delete);
System.out.println("这个"+delete+"行已经删除咯!"); //打印列删除
table.close();
close();
}
}
//HbaseModifyStudent.java
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;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
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.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.Delete;
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.TableDescriptorBuilder;
import org.apache.hadoop.hbase.util.Bytes;
import com.google.common.collect.Table.Cell;
public class HBaseModifyStudent {
public static void main(String[] args) throws Exception{
HBaseStudentOperation h1 = new HBaseStudentOperation();
@SuppressWarnings("resource")
Scanner in = new Scanner(System.in);
while(true) {
System.out.println("*******基于JAVA的HBase数据库表及表的基本操作******");
System.out.println("1. 创建学生表");
System.out.println("2. 添加学生信息");
System.out.println("3. 查看指定列数据");
System.out.println("4. 修改指定行数据");
System.out.println("5. 删除指定行数据");
System.out.println("0. 退出!");
System.out.print("请输入选项>>>");
int a=in.nextInt();
switch(a) {
case 1: h1.createTable("StudentScore",new String[]{"Student","Math","ComputerScience","English"}); break;
case 2: h1.addRecord("StudentScore","Zhangsan",new String[]{"Student:S_No","Student:S_Name","Student:S_Sex",
"Student:S_Age","Math:C_No","Math:C_Name","Math:C_Credit","English:SC_Score","English:C_No",
"English:C_Name","English:C_Credit","English:SC_Score"},
new String[] {"2020001","Zhangsan","male","23","123001","Math","2.0","86","123003","English",
"30","69"});break;
case 3: h1.scanColumn("StudentScore","Score:Math");break;
case 4: h1.modifyData("StudentScore","Zhangsan","Math:SC_Score","89");break;
case 5: h1.deleteRow("StudentScore","Zhangsan");break;
case 0: return;
}
}
}
}
四、实验结果(运行结果截图)
实验结果如上!
五、实验心得和总结
(列出遇到的问题和解决办法,列出没有解决的问题,可以是个人相关知识点总结,要求150字以上)
问题一:如何使用Java连接HBase。
解决方案:
Java连接HBase需要两个类:
- HBaseConfiguration
- ConnectionFactory
- Configuration config = HBaseConfiguration.create(); //使用create()静态方法就可以得到Configuration对象
- Connection connection = ConnectionFactory.createConnection(config); //config为前文的配置对象
使用这两个步骤就能完成连接HBase了。
问题二:如何防止获取指定行数据乱码。
解决方案:
- //获取数据
- Get get = new Get(Bytes.toBytes("row1")); //定义get对象
- Result result = table.get(get); //通过table对象获取数据
- System.out.println("Result: " + result);
- //很多时候我们只需要获取“值” 这里表示获取 data:1 列族的值
- byte[] valueBytes = result.getValue(Bytes.toBytes("data"), Bytes.toBytes("1")); //获取到的是字节数组
- //将字节转成字符串
- String valueStr = new String(valueBytes,"utf-8");
- System.out.println("value:" + valueStr);