-
1.简述Hbase的特点及与传统关系数据库的区别
-
HBase与传统关系数据库的区别
-
(1)数据类型
-
关系数据库具有丰富的数据类型,如字符串型、数值型、日期型、二进制型等。HBase只有字符串数据类型,数据的实际类型都是交由用户自己编写程序对字符串进行解析的。
-
-
(2)数据操作
-
关系数据库中包含了丰富的操作,其中会涉及复杂的多表连接。HBase 操作则不存在复杂的表与表之间的关系,只有简单的插入、查询、删除、清空等,因为HBase在设计上就避免了复杂的表和表之间的关系
-
-
(3)存储模式
-
关系数据库是基于行存储的,在关系数据库中读取数据时,需要顺序扫描每个元组,然后从中筛选出所需要查询的属性。HBase是基于列存储的,HBase将列划分为若干个列族,每个列族都由几个文件保存,不同列族的文件时分离的,它的优点是:可以降低IO开销,支持大量并发用户查询,仅需要处理所要查询的列,不需要处理与查询无关的大量数据列。
-
-
(4)数据索引
-
关系数据库通常可以针对不同列构建复杂的多个索引,以提高数据访问性能。HBase只有一个索引一—行键,通过巧妙的设计,HBase 中的所有访问方法,或者箍过行键访简,或著通过行键扫描,从而使得整个系统不会慢下来
-
-
(5)数据维护
-
在关系数据库中,更新操作会用最新的当前值去替换元组中原来的旧值。而HBase执行的更新操作不会删除数据旧的版本,而是添加一个新的版本,旧的版本仍然保留。
-
-
(6)可伸缩性
-
关系数据库很难实现横向扩展,纵向扩展的空间也比较有限。相反,HBase和BigTable这些分布式数据库就是为了实现灵活的水平扩展而开发的,能够轻易施通过在集群中增加或著减少硬件数量来实现性能的伸缩
-
-
-
HBase的技术特点
-
容量大。
-
当关系数据库的单个表的记录在亿级时,则查询和写入的性能都会呈现指数级下降,而HBase对于单表存储百亿或更多的数据都没有性能问题。
-
-
表结构不固定。
-
可以根据需要动态的增加列,同一张表中不同的行可以有截然不同的列。
-
-
列式存储。
-
数据在表中是按列存储,可动态增加列,单独对列进行各种操作。
-
-
稀疏性。
-
空列不占用存储空间,表可以非常稀疏。
-
-
数据类型单一。
-
HBase中的数据都是字符串。
-
-
-
2.画出图4-1,简述Hbase与Hadoop中其他组件的关系。
-
HBase作为Hadoop生态系统的一部分,一方面它的运行依赖于Hadoop生态系统中的其他组件;另一方面,HBase又为Hadoop生态系统的其他组件提供了强大的数据存储和处理能力。
-
3.通过表4-3和图4-4,简述Hbase在4个维度上的多维映射关系。
-
-
行键
-
每个HBase 表都由若干行组成,每个行由行键(row key)来标识。
-
-
列族
-
一个HBase 表被分组成许多“列族”(Column Family)的集合,它是基本的访问控制单元
-
-
列限定符
-
列族里的数据通过列限定符(或列)来定位
-
-
单元格
-
在HBase 表中,通过行·列成健和列限定符确定一个 “单元格”(cell),单元格中存储的数据没有数据类型,总被视为字节数组byte[]
-
-
时间戳
-
每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引
-
-
HBase中需要根据行键、列族、列限定符和时间戳来确定一个单元格 因此,可以视为一个“四维坐标”,即[行键,列族,列限定符,时间戳]
-
-
4.简述HBase Shell命令的分类和作用。
-
基本命令
-
1.获取帮助help
-
2.查看服务器状态status
-
3.查看当前用户whoami
-
4.命名空间相关命令
-
(1)列出所有命名空间命令list_namespace
-
(2)创建命名空间命令create namespace
-
(3)查看命名空间命令describe_namespace
-
(4)创建表命令create
-
(5)列出指定命名空间下的所有表命令list_namespace_tables
-
(6)使表无效命令disable
-
(7)删除表命令drop
-
(8)删除命名空间命令drop namespace
-
-
-
创建表
-
create<表名称>,<列族名称1>[,'列族名称2'...]
-
HBase中的表至少要有一个列族,列族直接影响HBasc数据存储的物理特性。
-
-
插入与更新表中的数据
-
put<表名>,<行键>,<列族名:列名>,<值>[,时间戳]
-
-
查看表中的数据
-
1.查询某行数据get
-
2.浏览表中全部数据scan
-
-
删除表中的数据
-
delete命令用于删除一个单元格数据
-
deleteall命令用于删除一行数据
-
truncate命令用于删除表中的所有数据
-
-
表的启用/禁用
-
enable和disable可以启用/禁用表
-
is_enabled和is_disabled来检查表是否被禁用。
-
-
修改表结构
-
修改表结构必须先禁用表。
-
disable 'student'#禁用student表
-
-
1.添加列族alter '表名',列族名'
-
2删除列族 alter '表名',{NAME=>'列族名',METHOD => 'delete'}
-
alter 'student',{NAME=> 'teacherInfo',METHOD => 'delete"}
-
-
-
删除HBase表
-
第一步禁用表,第二步删除表。
-
disable 'student’#禁用student表
-
drop 'student'#删除student表
-
-
-
5.分析教材中P89-91中Java程序的功能,试改写程序为一个类实现。
-
教材P89-91内容如下:
//1.创建建表类 CreateHTable
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.client.HBaseAdmin;
import java.io.IOException;
public class CreateHTable{
public static void create (String tableName, String[] columnFamily) throws IOException {
Configuration cfg = HBaseConfiguration.create();//生成Configuration对象
//生成HBaseAdmin对象,用于管理 HBase数据库的表
HBaseAdmin admin = new HBaseAdmin(cfg);
//创建表,先判断表是否存在,若存在,先删除旧表再建表
if(admin.tableExists(tableName))(
admin.disableTable(tableName);//禁用表
admin.deleteTable(tableName);//删除表
)
//利用HBaseAdmin对象的createTable (HTableDescriptor desc)方法创建表
//通过tableName建立HTableDescriptor对象(包含HBase表的详细信息)
//通过HTableDescriptor对象的addFamily (HColumnDescriptor hcd)方法添加列族
//HColumnDescriptor对象是以列族名作为参数创建的
HTableDescriptor htd = new HTableDescriptor(tableName);
for(String column : columnFamily){
htd.addFamily(new HColumnDescriptor(column));
}
admin.createTable(htd);//创建表
}
}
//2.创建插入数据类InsertHData
//利用前面在HBaseExample项目中创建CreateHTable类的方法创建插入数据类InsertHData,在InsertHData.java的源代码文件中输入以下代码:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import java.io.IOException;
public class InsertHData {
public static void insertData (string tableName, String row, String columnFamily,String column , String data) throws IOException {
Configuration cfg = HBaseConfiguration.create();
// HTable对象用于与HBase进行通信
HTable table = new HTable (cfg, tableName);
//通过Put对象为已存在的表添加数据
Put put = new Put (row.getBytes());
if(column==null) //判断列限定符是否为空,如果为空,则直接添加列数据
put.add (columnFamily.getBytes(),null, data.getBytes());
else
put.add (columnFamily.getBytes (), column. getBytes () , data.getBytes());
//table对象的put()方法的输入参数 Put对象表示单元格数据
table.put (put);
}
}
//3.创建建表测试类TestCreateHTable
//利用前面在HBascExample项目中创建CreateHTable类的方法创建建表测试类TestCreateHTable,在TestCreatcHTable的源代码文件中输入以下代码:
import java.io.IOException;
public class TestCreateHTable{
public static void main(String[] args)throws IOException{
//先创建一个名为student的表,列族有baseinfo、scoreInfo
String[] columnFamily = {"baseInfo" , "scoreInfo"};
String tableName = "Student";
CreateHTable.create(tableName, columnFamily);
//插入数据
//插入Ding的信息和成绩
InsertHData.insertData ("student ", "Ding", "baseInfo", "Ssex" , "female");
InsertHData.insertData ("student", "Ding", "baseInfo", "Sno","10106");
InsertHData.insertData ( "student", "Ding" , "scoreInfo", "c","86");
InsertHData.insertData ("student" ,"Ding" , "scoreInfo", "Java" , "82");
InsertHData.insertData ( "Student" , "Ding", "scoreInfo" , "Python" , "87");
//插入Yan的信息和成绩
InsertHData.insertData ("student" , "Yan", "baseInfo" , "Ssex" , "female");
InsertHData.insertData ("student", "Yan", "baseInfo" , "Sno", "10108");
InsertHData.insertData ( "student" , "Yan", "scoreInfo", "c", "90");
InsertHData.insertData ("Student", "Yan", "scoreInfo" , "Java", "91");
InsertHData.insertData("student", "Yan" , "scoreInfo" , "python", "93");
//插入Feng的信息和成绩
InsertHData.insertData ("Student", "Feng" , "baseInfo" , "Ssex" ,"female");
InsertHData.insertData ("Student" , "Feng" , "baseInfo" , "Sno","10107");
InsertHData.insertData ("Student", "Feng", "scoreInfo", "c","89");
InsertHData.insertData ("student", "Feng", "scoreInfo" , "Java", "83");
InsertHData.insertData("Student", "Feng" , "scoreInfo" , "Python", "85");
}
}
-
(1)CreateHTable 类
-
创建一个 HBase 表。
-
首先检查表是否已经存在,如果存在则先删除旧表,然后创建一个新表。
-
通过 HTableDescriptor 对象定义表的名称和列族,然后使用 HBaseAdmin 对象创建表。
-
-
(2)InsertHData 类
-
向 HBase 表中插入数据。
-
使用 HTable 对象与 HBase 进行通信,并创建 Put 对象来表示要插入的单元格数据。
-
根据是否指定列限定符,使用不同的方法向表中添加数据。
-
-
(3)TestCreateHTable 类
-
测试类,用于测试前面两个类的功能。
-
首先创建了一个名为 "Student" 的表,列族为 "baseInfo" 和 "scoreInfo"。
-
然后使用 InsertHData 类向表中插入了三个学生的信息和成绩。
-
改写为一个类实现:
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.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import java.io.IOException;
/**
* HBaseManager 类提供了创建 HBase 表和向表中插入数据的功能。
*/
public class HBaseManager {
private Configuration configuration;
private HBaseAdmin admin;
/**
* 构造函数,初始化 HBase 配置和管理员对象。
*
* @throws IOException 如果初始化过程中出现 I/O 异常
*/
public HBaseManager() throws IOException {
this.configuration = HBaseConfiguration.create();
this.admin = new HBaseAdmin(configuration);
}
/**
* 创建 HBase 表。
*
* @param tableName 表名
* @param columnFamilies 列族名数组
* @throws IOException 如果创建表过程中出现 I/O 异常
*/
public void createTable(String tableName, String[] columnFamilies) throws IOException {
// 检查表是否已存在
if (admin.tableExists(tableName)) {
// 如果表存在,先禁用并删除旧表
admin.disableTable(tableName);
admin.deleteTable(tableName);
}
// 创建新表
HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
for (String columnFamily : columnFamilies) {
// 为表添加列族
tableDescriptor.addFamily(new HColumnDescriptor(columnFamily));
}
admin.createTable(tableDescriptor);
}
/**
* 向 HBase 表中插入数据。
*
* @param tableName 表名
* @param row 行键
* @param columnFamily 列族名
* @param column 列限定符(可为null)
* @param data 要插入的数据
* @throws IOException 如果插入数据过程中出现 I/O 异常
*/
public void insertData(String tableName, String row, String columnFamily, String column, String data) throws IOException {
// 获取表对象
HTable table = new HTable(configuration, tableName);
// 创建 Put 对象表示要插入的单元格数据
Put put = new Put(row.getBytes());
// 判断是否指定了列限定符
if (column == null) {
// 如果没有指定列限定符,直接添加列数据
put.add(columnFamily.getBytes(), null, data.getBytes());
} else {
// 如果指定了列限定符,使用列限定符添加列数据
put.add(columnFamily.getBytes(), column.getBytes(), data.getBytes());
}
// 将 Put 对象写入表
table.put(put);
}
}
public class HBaseManagerTest {
public static void main(String[] args) throws IOException {
HBaseManager manager = new HBaseManager();
// 创建表
String[] columnFamilies = {"baseInfo", "scoreInfo"};
String tableName = "Student";
manager.createTable(tableName, columnFamilies);
// 插入数据
// 插入 Ding 的信息和成绩
manager.insertData("Student", "Ding", "baseInfo", "Ssex", "female");
manager.insertData("Student", "Ding", "baseInfo", "Sno", "10106");
manager.insertData("Student", "Ding", "scoreInfo", "C", "86");
manager.insertData("Student", "Ding", "scoreInfo", "Java", "82");
manager.insertData("Student", "Ding", "scoreInfo", "Python", "87");
// 插入 Yan 的信息和成绩
manager.insertData("Student", "Yan", "baseInfo", "Ssex", "female");
manager.insertData("Student", "Yan", "baseInfo", "Sno", "10108");
manager.insertData("Student", "Yan", "scoreInfo", "C", "90");
manager.insertData("Student", "Yan", "scoreInfo", "Java", "91");
manager.insertData("Student", "Yan", "scoreInfo", "Python", "93");
// 插入 Feng 的信息和成绩
manager.insertData("Student", "Feng", "baseInfo", "Ssex", "female");
manager.insertData("Student", "Feng", "baseInfo", "Sno", "10107");
manager.insertData("Student", "Feng", "scoreInfo", "C", "89");
manager.insertData("Student", "Feng", "scoreInfo", "Java", "83");
manager.insertData("Student", "Feng", "scoreInfo", "Python", "85");
}
}