实验平台
操作系统: Ubuntu 18.04.4LTS
Hadoop 版本: 2.7.7
HBase 版本:2.0.5
JDK 版本: 1.8.0_241
Java IDE: Eclipse
安装包:
HBase:https://archive.apache.org/dist/hbase/2.0.5/

实验内容
(一) 编程实现以下指定功能,并用 Hadoop 提供的 HBase Shell 命令完成相同任务:
(1) 列出 HBase 所有的表的相关信息,例如表名;
(2) 在终端打印出指定的表的所有记录数据;
(3) 向已经创建好的表添加和删除指定的列族或列;
(4) 清空指定的表的所有记录数据;
(5) 统计表的行数。

package shiyan4;

import java.io.IOException; 
import java.util.Scanner;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class shiyan4_1 {

	// 对配置信息管理的一个类
	public static Configuration configuration;
	// 对连接进行管理的一个类
    public static Connection connection; 
	// 对数据库进行管理的一个类,用于对表的增删改查
    public static Admin admin; 
    
  //建立连接
  	public static void init() {
  		configuration = HBaseConfiguration.create();
  		configuration.set("hbase.rootdir", "hdfs://localhost:9000/hbase");
  		try {
  			// 获取连接池
  			connection = ConnectionFactory.createConnection(configuration);
			// 使用连接对象获取Admin对象
  			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();
  		}
  	}
    
    //列出HBase所有的表
    public static void listTables() throws IOException 
    { 
        HTableDescriptor[] hTableDescriptors = admin.listTables(); 
        for (HTableDescriptor hTableDescriptor : hTableDescriptors) 
        { 
            System.out.println("表名:" + hTableDescriptor.getNameAsString()); 
        }
    }
    
    //在终端打印出指定的表的所有记录数据
    public static void getData(String tableName) throws IOException 
    {
    	Table table = connection.getTable(TableName.valueOf(tableName));
    	Scan scan = new Scan();
    	ResultScanner scanner = table.getScanner(scan);
    	for(Result result : scanner) //获取的result数据是结果集
    	{
    		printRecoder(result);
    	}
    }
    public static void printRecoder(Result result) throws IOException
    {
    	for (Cell cell : result.rawCells())
    	{
    		System.out.print("行键:" + new String(CellUtil.cloneRow(cell)) + " ");
    		System.out.print("列族: " + new String(CellUtil.cloneFamily(cell))+"  "); 
            System.out.print(" 列: " + new String(CellUtil.cloneQualifier(cell))+"  "); 
            System.out.print(" 值: " + new String(CellUtil.cloneValue(cell))+"  "); 
            System.out.println("时间戳: " + cell.getTimestamp());
    	}
    }

    //向已经创建好的表添加指定的的列族或列
    public static void insertRow(String tableName, String rowKey, String colFamily, String col, String val) throws IOException
    {
    	Table table = connection.getTable(TableName.valueOf(tableName));
    	Put put = new Put(rowKey.getBytes());
    	put.addColumn(colFamily.getBytes(), col.getBytes(), val.getBytes());
    	table.put(put);
    	table.close();
    }
    //向已经创建好的表删除指定的列族或列
    public static void deleteRow(String tableName, String rowKey, String colFamily, String col) throws IOException 
    { 
        
        Table table = connection.getTable(TableName.valueOf(tableName)); 
        Delete delete = new Delete(rowKey.getBytes()); 
        delete.addFamily(Bytes.toBytes(colFamily));
        delete.addColumn(Bytes.toBytes(colFamily), Bytes.toBytes(col)); 
        table.delete(delete); 
        table.close();
        
    }
    
    //清空指定的表的所有记录数据
    public static void clearRows(String tableName) throws IOException
    {
    	TableName tablename = TableName.valueOf(tableName);
    	admin.disableTable(tablename);
    	admin.truncateTable(tablename, false);
    }
    
    //统计表的行数
    public static void countTable(String tableName) throws IOException
    {
    	Table table = connection.getTable(TableName.valueOf(tableName));
    	Scan scan = new Scan();
    	ResultScanner scanner = table.getScanner(scan);
    	int cnt = 0;
    	for(Result result = scanner.next(); result != null; result = scanner.next())
    	{
    		cnt++;
    	}
    	System.out.println("行数:" + cnt);
    	scanner.close();
    }
    
    //主函数
    public static void main(String[] args) 
    {  
         try
         {
        	 int n = 0;
        	 init();
        	 Scanner in = new Scanner(System.in);
        	 while(n != 7)
        	 {
        		 System.out.println("1.列出 Hbase 所有的表的信息");
                 System.out.println("2.在终端打印出指定表的所有记录数据");
                 System.out.println("3.向已经创建好的表添加指定的的列族或列");
                 System.out.println("4.向已经创建好的表删除指定的的列族或列");
                 System.out.println("5.清空指定的表的所有记录数据");
                 System.out.println("6.统计表的行数");
                 System.out.println("7.退出");
                 System.out.println("请选择:");
                 if(in.hasNextInt())
                 {
                	 n = in.nextInt();
                 }
                 else
                 {
                	 System.out.println("输入的不是整数,请重新输入:");
                	 continue;
                 }
                 switch(n)
                 {
                 case 1:
                	 listTables();
                	 break;
                 case 2:
                	 getData("Student");
                	 break;
                 case 3:
                	 insertRow("tempTable", "r1", "f1", "c1", "hello,dblab"); 
                	 break;
                 case 4:
                	 deleteRow("tempTable", "r1", "f1", "c1");  
                	 break;
                 case 5:
                	 clearRows("tempTable"); 
                	 break;
                 case 6:
                	 countTable("tempTable"); 
                	 break;
                 case 7:
                	 break;
                 default:
                	 System.out.println("输入错误,请重新输入");
                 }
        	 }
        	 close();
         }
         catch (IOException e)
         {
        	 e.printStackTrace();
         }
    }

}

(二) HBase 数据库操作
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 指定的行的记录。

package shiyan4;

import java.io.IOException; 
import java.util.Scanner;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class shiyan4_2_2 {
	
	// 对配置信息管理的一个类
	public static Configuration configuration;
	// 对连接进行管理的一个类
    public static Connection connection; 
	// 对数据库进行管理的一个类,用于对表的增删改查
    public static Admin admin; 
    
  //建立连接
  	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();
  		}
  	}
  	
  	//创建表,参数tableName为表的名称,字符串数组fields为存储记录各个域名称的数组。
	//要求当HBase已经存在名为tableName的表的时候,先删除原有的表,然后再创建新的表。
  	public static void createTable(String tableName, String[] fields) throws IOException 
  	{
  		init();
  		TableName tablename = TableName.valueOf(tableName);
  		if(admin.tableExists(tablename))
  		{
  			System.out.println("该表已存在,删除后重建。");
  			admin.disableTable(tablename);
  			admin.deleteTable(tablename);
  		}
  		
  		HTableDescriptor htd = new HTableDescriptor(tablename);
  		for(String str : fields)
  		{
  			HColumnDescriptor hcd = new HColumnDescriptor(str);
  			htd.addFamily(hcd);
  		}
  		admin.createTable(htd);
  		close();
  	}
  	
	//向表 tableName、行 row(用 S_Name 表示)和字符串数组 fields 指定的单元格中添加对应的数据 values。
	//其中, fields 中每个元素如果对应的列族下还有相应的列限定符的话,用“columnFamily:column”表示。
	//例如,同时向“Math”、 “Computer Science”、 “English”三列添加成绩时,
	//字符串数组 fields 为{“Score:Math”, ”Score:Computer Science”, ”Score:English”},
	//数组 values 存储这三门课的成绩。
  	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 p = new Put(row.getBytes());
  			String[] cols = fields[i].split(":");
  			if(cols.length == 1)
  			{
  				p.addColumn(cols[0].getBytes(), "".getBytes(), values[i].getBytes());
  			}
  			else
  			{
  				p.addColumn(cols[0].getBytes(), cols[1].getBytes(), values[i].getBytes());
  			}
  			table.put(p);
  		}
  		table.close();
  		close();
  	}
  	
	//浏览表 tableName 某一列的数据,如果某一行记录中该列数据不存在,则返回 null。
	//要求当参数 column 为某一列族名称时,如果底下有若干个列限定符,则要列出每个列限定符代表的列的数据;
	//当参数 column 为某一列具体名称(例如“Score:Math”)时,只需要列出该列的数据。
  	public static void scanColumn(String tableName, String column) throws IOException 
  	{
  		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)
  		{
  			Cell[] cells = result.rawCells();
  			for(Cell cell : cells)
  			{
  				System.out.println("行键:" + new String(CellUtil.cloneRow(cell)));
  				System.out.println("列族: " + new String(CellUtil.cloneFamily(cell)));
				System.out.println("列限定符: " + new String(CellUtil.cloneQualifier(cell)));
				System.out.println("时间戳: " + cell.getTimestamp());
				System.out.println("数据: " + new String(CellUtil.cloneValue(cell)));
  			}
  		}
  		table.close();
  		close();
  	}

  	//修改表 tableName,行 row(可以用学生姓名 S_Name 表示),列 column 指定的单元格的数据。
  	public static void modifyData(String tableName, String row, String column, String val) throws IOException
  	{
  		init();
  		Table table = connection.getTable(TableName.valueOf(tableName));
  		Put p = new Put(row.getBytes());
  		String[] cols = column.split(":");
  		if(cols.length == 1)
  		{
  			p.addColumn(column.getBytes(), "".getBytes(), val.getBytes());
  		}
  		else
  		{
  			p.addColumn(cols[0].getBytes(), cols[1].getBytes(), val.getBytes());
  		}
  		table.put(p);
  		table.close();
  		close();
  	}
  	
  	//删除表 tableName 中 row 指定的行的记录。
  	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);
  		table.close();
  		close();
  	}
  	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		shiyan4_2_2 shiyan = new shiyan4_2_2();
		
		try
		{
			//1
			System.out.println("执行1:");
			String[] fields1 = {"Score", "Sage"}; //存储记录各个字段名称的数组
			shiyan.createTable("S_Info", fields1);
			//2
			System.out.println("执行2:");
			String[] fields2 = {"Score:Math", "Score:Computer Science", "Score:English"};
			String[] values2 = {"90", "88.5", "59.5"};
			shiyan.addRecord("S_Info", "S_Name", fields2, values2);
			//3
			System.out.println("执行3:");
			shiyan.scanColumn("S_Info", "Score");
			shiyan.scanColumn("S_Info", "Score:Math");
			//4
			System.out.println("执行4:");
			shiyan.modifyData("S_Info", "S_Name", "Score:English", "60");
			shiyan.scanColumn("S_Info", "Score:English");
			//5
			System.out.println("执行5:");
			shiyan.deleteRow("S_Info", "S_Name");
			
		}
		catch (IOException e)
        {
       	 	e.printStackTrace();
        }
	}

}