一、Hbase java API:
1、创建一张表
2、删除一张表
3、向一张表中添加一条数据
4、向一张表中同时添加一批数据
5、获取一条数据
6、获取一批数据
7、创建预分region表
代码实现:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
/*
java操作数据的步骤:
1、注册驱动
2、创建数据库连接对象
3、创建数据库操作对象
4、进行增删改查
5、如果时查询的话,可以对查询的结果进行分析
6、释放资源
hbase基础中要做的需求:
1、如何创建一张表
2、如何删除一张表
3、如何向一张表中添加一条数据
4、如何向一张表中同时添加一批数据
5、如何获取一条数据
6、如果获取一批数据
7、如何创建预分region表
*/
public class HBaseAPI {
private Connection conn;
private Admin admin;
/**
* 在所有Test方法执行之前执行
*/
@Before
public void getConnection() {
try {
//1、获取hbase集群的配置文件对象
//0.90.0之前旧版本的写法:
// HBaseConfiguration conf = new HBaseConfiguration();
//新版本的写法:调用静态方法public static Configuration create()
Configuration conf = HBaseConfiguration.create();
Properties prop = new Properties();
prop.load(new BufferedReader(new FileReader("src/main/resources/hbase.properties")));
String zk = (String)prop.get("hbase.zookeeper.quorum");
//2、因为hbase的数据都有一条元数据,而元数据也存储在一张表中,这张元数据表也有元数据,存储在zookeeper中
//配置文件要设置你自己的zookeeper集群
conf.set("hbase.zookeeper.quorum",zk); //前提时windows中配置了hosts映射
//3、获取数据库的连接对象
conn = ConnectionFactory.createConnection(conf);
//4、获取数据库操作对象
// HBaseAdmin hBaseAdmin = new HBaseAdmin(conn);
//新版本的做法
admin = conn.getAdmin(); //使用连接对象获取数据库操作对象
System.out.println("数据库连接对象获取成功!!" + conn);
System.out.println("数据库操作对象获取成功!!" + admin);
System.out.println("==========================================");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 需求1: 1、如何创建一张表
* create 'students','info' 必须要有表名和列簇的名
*/
@Test
public void createOneTable() {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf("students2");
//HTableDescriptor类已经在2.0.0版本之后就过时了,并且在3.0.0之后完全被删除
//新版本不能使用这个类
// HTableDescriptor students = new HTableDescriptor(tn);
//新版本使用 TableDescriptorBuilder 类来创建并获取表描述器对象
//public static TableDescriptorBuilder newBuilder(final TableName name)
TableDescriptorBuilder students = TableDescriptorBuilder.newBuilder(tn);
//旧版本创建列簇描述器对象
// HColumnDescriptor info = new HColumnDescriptor("info");
//新版本中ColumnFamilyDescriptorBuilder.of(String).
ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");
//将列簇与表进行关联
//旧版本中表描述器调用addColumnFamily方法将列簇描述器添加到表中
// students.addColumnFamily(info);
//新版本中使用setColumnFamily
students.setColumnFamily(info);
//调用方法,创建表
// createTable(TableDescriptor desc)
// TableDescriptorBuilder
admin.createTable(students.build());
System.out.println(tn + "表创建成功!!!");
} catch (Exception e) {
System.out.println("表创建失败!!");
e.printStackTrace();
}
}
/**
* 需求:2、如何删除一张表
* disable 'students'
* drop 'students'
*/
@Test
public void dropOneTable() {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf("tb_split2");
//判断表是否存在
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();
}
}
/**
* 需求:3、如何向一张表中添加一条数据
* put 'students','1001','info:name','小虎'
*/
@Test
public void putOneDataToTable() {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf("students");
//判断表是否存在
if (admin.tableExists(tn)) {
//获取表对象
Table students = conn.getTable(tn);
//创建Put对象
// Put put = new Put("1001".getBytes());//行键的字节数组形式
// //对put对象进行设置,添加列簇,列名和列值
// put.addColumn("info".getBytes(),"name".getBytes(),"小虎".getBytes());
//hbase自带的一个工具类Bytes,可以将字符串转字节数组
Put put = new Put(Bytes.toBytes("1001"));//行键的字节数组形式
//对put对象进行设置,添加列簇,列名和列值 以前的写法
// put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("小虎"));
//public Put add(Cell cell) 新版本另外一种设置put对象的方式
//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)));
//void put(Put put)
//需要先将我们添加的列数据封装成一个Put对象
students.put(put);
} else {
System.out.println(tn + "表不存在!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 需求:4、如何向一张表中同时添加一批数据
*/
@Test
public void putMoreDataToTable() {
BufferedReader br = null;
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf("students2");
//创建字符输入缓冲流
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();
}
}
}
}
/**
* 需求:5、如何获取一条数据
* get 'students','1500101000'
*/
@Test
public void getOneData() {
try {
//将表名封装TableName对象
TableName sd = TableName.valueOf("students");
//获取表的对象
Table students = conn.getTable(sd);
//传入行键的字节数组的形式
Get get = new Get(Bytes.toBytes("1500101000"));
//default Result get(Get get)
Result result = students.get(get);
// System.out.println(result);
/**
* Result类中的常用方法:
* getRow() : 获取行键的字节数组形式
* getValue(byte [] family, byte [] qualifier): 根据列簇和列名,获取列值的字节数组形式
* List<Cell> listCells():获取所有单元格,单元格中存储了行键,列簇,列名,版本号(时间戳),列值
*/
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(); //获取的结果值的顺序是hbase中存储排序后的顺序
//遍历集合得到每个单元格,获取每个列值
/**
* hbase中除了提供一个Bytes工具类给我们使用以外,还提供了另外的一个工具类:CellUtil
* 该工具类主要的操作对象是Cell类的对象
*/
//遍历方式1:普通for循环遍历
//遍历方式2:增强for循环遍历
// for (Cell cell : cells) {
// String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
// String colValue = Bytes.toString(CellUtil.cloneValue(cell));
// System.out.println(colName + ":" + colValue);
// }
//遍历方式3:forEach + lambda表达式
// cells.forEach(e -> {
// String colName = Bytes.toString(CellUtil.cloneQualifier(e));
// String colValue = Bytes.toString(CellUtil.cloneValue(e));
// System.out.println(colName + ":" + colValue);
// });
//遍历方式4:jdk1.8新特性遍历,转流处理
cells.stream().map(e -> {
String colName = Bytes.toString(CellUtil.cloneQualifier(e));
String colValue = Bytes.toString(CellUtil.cloneValue(e));
// System.out.println(colName + ":" + colValue);
return colName + ":" + colValue;
}).forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 6、如果获取一批数据 第一种方式
*/
@Test
public void getMoreData() {
try {
//将表名封装TableName对象
TableName sd = TableName.valueOf("students");
//获取表的对象
Table students = conn.getTable(sd);
//创建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 = students.get(gets);
//1、先遍历results得到每一个result(每一行)
//2、遍历每一个result中的每一列
for (Result result : results) {
List<Cell> cells = result.listCells();
if (cells != null) {
cells.stream().map(cell -> {
String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
String colValue = Bytes.toString(CellUtil.cloneValue(cell));
// System.out.println(colName + ":" + colValue);
return colName + ":" + colValue;
}).forEach(System.out::println);
System.out.println("-----------------");
} else {
System.out.println("是空");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 7、如果获取一批数据 第二种方式
* scan 'students' 默认情况下获取表所有数据
* scan 'students',LIMIT=>3
*/
@Test
public void ScanData() {
try {
TableName sd = TableName.valueOf("students");
Table students = conn.getTable(sd);
//创建Scan对象
Scan scan = new Scan(); //查询表中的所有行
//设置开始行和结束行
//旧版本写法
// scan.setStartRow(Bytes.toBytes("1500100001"));
// scan.setStopRow(Bytes.toBytes("1500100004"));
//新版本写法
// scan.withStartRow(Bytes.toBytes("1500100001"));
// scan.withStopRow(Bytes.toBytes("1500100004"), true);
//设置取前几行
scan.setLimit(10);
//default ResultScanner getScanner(Scan scan)
ResultScanner resultScanner = students.getScanner(scan);
//通过观察源码发现,可以先获取迭代器对象
Iterator<Result> iterator = resultScanner.iterator();
while (iterator.hasNext()) {
Result result = iterator.next();
//不知道列名的时候遍历
// List<Cell> cells = result.listCells();
// cells.stream().map(cell->{
// String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
// String colValue = Bytes.toString(CellUtil.cloneValue(cell));
// return colName + ":" + colValue;
// }).forEach(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);
printResult(result);
System.out.println("-----------------");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 需求:7、如何创建预分region表
* 将来对于某一个RegionServer而言,可能会接收大量的并发请求,超出了该RegionServer承受的压力,有可能会导致该子节点崩溃
* 如果大量的并发请求查询的数据是多种多种多样的,只不过巧合的是都在一个RegionServer上管理
* 解决的思路:分散查询的数据到不同的RegionServer上,这样请求也会随着被分散到不同的RegionServer上,就达到了减轻某一个RegionServer压力过大情况,解决了单点故障的问题
*/
@Test
public void createPreviewTable(){
try {
//先将表名封装成TableName对象
TableName tb = TableName.valueOf("tb_split2");
//创建表描述器对象
TableDescriptorBuilder tbSplit2 = TableDescriptorBuilder.newBuilder(tb);
//创建列簇描述器对象
ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of("info");
//将列簇添加到表中
tbSplit2.setColumnFamily(info);
//创建分割键的二维数组
byte[][] splitKeys = {
Bytes.toBytes("f"),
Bytes.toBytes("k"),
Bytes.toBytes("p")
};
//调用方法创建表
// admin.createTable(tbSplit2.build());
//调用另外一个方法,传入表描述器的同时,传入分割点,创建预分region表
//void createTable(TableDescriptor desc, byte[][] splitKeys)
admin.createTable(tbSplit2.build(),splitKeys);
System.out.println("预分region表创建成功!!!");
}catch (Exception e){
e.printStackTrace();
}
}
public void printResult(Result 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);
// System.out.println("-----------------");
}
/**
* 释放Before创建的资源,在每个Test之后执行
*/
@After
public void closeSource() {
try {
if (admin != null) {
admin.close();
}
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们可以将上述的API实现方式封装为一个工具类HBaseUtil,方便我们后续使用:
import com.shujia.bean.MyCell;
import com.shujia.bean.NotFoundFilterNameException;
import com.shujia.bean.NotFountComparatorException;
import jdk.nashorn.internal.codegen.types.BooleanType;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class HBaseUtil {
public static Connection CONNECTION;
public static Admin ADMIN;
private HBaseUtil() {
}
/**
* 获取数据库连接对象和数据库操作对象
*/
static {
try {
//1、获取hbase集群的配置文件对象
//0.90.0之前旧版本的写法:
// HBaseConfiguration conf = new HBaseConfiguration();
//新版本的写法:调用静态方法public static Configuration create()
Configuration conf = HBaseConfiguration.create();
//2、因为hbase的数据都有一条元数据,而元数据也存储在一张表中,这张元数据表也有元数据,存储在zookeeper中
//配置文件要设置你自己的zookeeper集群
// conf.set("hbase.zookeeper.quorum", "master:2181,node1:2181,node2:2181"); //前提时windows中配置了hosts映射
Properties prop = new Properties();
prop.load(new BufferedReader(new FileReader("E:\\projects\\IDEAProjects\\bigdata29\\hbase\\src\\main\\resources\\hbase.properties")));
String zk = (String) prop.get("hbase.zookeeper.quorum");
//2、因为hbase的数据都有一条元数据,而元数据也存储在一张表中,这张元数据表也有元数据,存储在zookeeper中
//配置文件要设置你自己的zookeeper集群
conf.set("hbase.zookeeper.quorum", zk); //前提时windows中配置了hosts映射
//3、获取数据库的连接对象
CONNECTION = ConnectionFactory.createConnection(conf);
//4、获取数据库操作对象
// HBaseAdmin hBaseAdmin = new HBaseAdmin(conn);
//新版本的做法
ADMIN = CONNECTION.getAdmin(); //使用连接对象获取数据库操作对象
} catch (Exception e) {
e.printStackTrace();
}
}
public static void createOneTable(String tableName, String columnFamily) {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf(tableName);
if (!ADMIN.tableExists(tn)) {
TableDescriptorBuilder students = TableDescriptorBuilder.newBuilder(tn);
// ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of(columnFamily);
//使用另外一种方式创建列簇并设置布隆过滤器
ColumnFamilyDescriptor columnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily))
.setBloomFilterType(BloomType.ROW).build();
students.setColumnFamily(columnFamilyDescriptor);
ADMIN.createTable(students.build());
System.out.println(tn + "表创建成功!!!");
} else {
System.out.println(tn + "表已经存在!");
}
} catch (Exception e) {
System.out.println("表创建失败!!");
e.printStackTrace();
}
}
/**
* 需求:2、如何删除一张表
* disable 'students'
* drop 'students'
*/
public static void dropOneTable(String tableName) {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf(tableName);
//判断表是否存在
if (ADMIN.tableExists(tn)) {
//先禁用表
ADMIN.disableTable(tn);
ADMIN.deleteTable(tn);
System.out.println(tn + "表成功被删除");
} else {
System.out.println(tn + "表不存在!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 需求:3、如何向一张表中添加一条数据
* put 'students','1001','info:name','小虎'
*/
public static void putOneDataToTable(String tableName, String rowKey, String columnFamily, String colName, String colValue) {
try {
//先将表名封装成一个TableName的对象
TableName tn = TableName.valueOf(tableName);
//判断表是否存在
if (ADMIN.tableExists(tn)) {
//获取表对象
Table students = CONNECTION.getTable(tn);
//hbase自带的一个工具类Bytes,可以将字符串转字节数组
Put put = new Put(Bytes.toBytes(rowKey));//行键的字节数组形式
put.add(new KeyValue(Bytes.toBytes(rowKey),
Bytes.toBytes(columnFamily),
Bytes.toBytes(colName),
Bytes.toBytes(colValue)));
//void put(Put put)
//需要先将我们添加的列数据封装成一个Put对象
students.put(put);
} else {
System.out.println(tn + "表不存在!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 需求:5、如何获取一条数据
* get 'students','1500101000'
*/
public static List<MyCell> getOneData(String tableName, String rowKey) throws Exception {
//将表名封装TableName对象
TableName sd = TableName.valueOf(tableName);
//获取表的对象
Table students = CONNECTION.getTable(sd);
//传入行键的字节数组的形式
Get get = new Get(Bytes.toBytes(rowKey));
Result result = students.get(get);
//创建List集合List<MyCell> MyCell:行键,列簇,列名,列值,
ArrayList<MyCell> myCells = new ArrayList<>();
byte[] rk = result.getRow();
//当不清楚列名的时候该如何获取呢?
//获取一行中的所有单元格组合的集合
List<Cell> cells = result.listCells(); //获取的结果值的顺序是hbase中存储排序后的顺序
//遍历集合得到每个单元格,获取每个列值
for (Cell cell : cells) {
byte[] family = CellUtil.cloneFamily(cell);
byte[] qualifier = CellUtil.cloneQualifier(cell);
byte[] value = CellUtil.cloneValue(cell);
myCells.add(new MyCell(rk, family, qualifier, value));
}
return myCells;
}
/**
* 7、如果获取一批数据 第二种方式
* scan 'students' 默认情况下获取表所有数据
* scan 'students',LIMIT=>3
*/
public static void scanData(String tableName) {
try {
TableName sd = TableName.valueOf(tableName);
Table students = CONNECTION.getTable(sd);
//创建Scan对象
Scan scan = new Scan(); //查询表中的所有行
//default ResultScanner getScanner(Scan scan)
ResultScanner resultScanner = students.getScanner(scan);
//通过观察源码发现,可以先获取迭代器对象
for (Result result : resultScanner) {
printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void scanData(String tableName, String startRow, String endRow, boolean include) {
try {
TableName sd = TableName.valueOf(tableName);
Table students = CONNECTION.getTable(sd);
//创建Scan对象
Scan scan = new Scan(); //查询表中的所有行
//设置开始行和结束行
if (include) {
scan.withStartRow(Bytes.toBytes(startRow));
scan.withStopRow(Bytes.toBytes(endRow), true);
} else {
scan.withStartRow(Bytes.toBytes(startRow));
scan.withStopRow(Bytes.toBytes(endRow));
}
//default ResultScanner getScanner(Scan scan)
ResultScanner resultScanner = students.getScanner(scan);
//通过观察源码发现,可以先获取迭代器对象
for (Result result : resultScanner) {
printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void scanData(String tableName, int limit) {
try {
TableName sd = TableName.valueOf(tableName);
Table students = CONNECTION.getTable(sd);
//创建Scan对象
Scan scan = new Scan(); //查询表中的所有行
scan.setLimit(limit);
//default ResultScanner getScanner(Scan scan)
ResultScanner resultScanner = students.getScanner(scan);
//通过观察源码发现,可以先获取迭代器对象
for (Result result : resultScanner) {
printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static ResultScanner scanDataReturn(String tableName, int limit) throws Exception{
TableName sd = TableName.valueOf(tableName);
Table students = CONNECTION.getTable(sd);
//创建Scan对象
Scan scan = new Scan(); //查询表中的所有行
scan.setLimit(limit);
//default ResultScanner getScanner(Scan scan)
return students.getScanner(scan);
}
/**
* 需求:7、如何创建预分region表
* 将来对于某一个RegionServer而言,可能会接收大量的并发请求,超出了该RegionServer承受的压力,有可能会导致该子节点崩溃
* 如果大量的并发请求查询的数据是多种多种多样的,只不过巧合的是都在一个RegionServer上管理
* 解决的思路:分散查询的数据到不同的RegionServer上,这样请求也会随着被分散到不同的RegionServer上,就达到了减轻某一个RegionServer压力过大情况,解决了单点故障的问题
*/
public static void createPreviewTable(String tableName, String columnFamily, byte[][] splitKeys) {
try {
//先将表名封装成TableName对象
TableName tb = TableName.valueOf(tableName);
//创建表描述器对象
TableDescriptorBuilder tbSplit2 = TableDescriptorBuilder.newBuilder(tb);
//创建列簇描述器对象
ColumnFamilyDescriptor info = ColumnFamilyDescriptorBuilder.of(columnFamily);
//将列簇添加到表中
tbSplit2.setColumnFamily(info);
//调用方法创建表
// admin.createTable(tbSplit2.build());
//调用另外一个方法,传入表描述器的同时,传入分割点,创建预分region表
//void createTable(TableDescriptor desc, byte[][] splitKeys)
ADMIN.createTable(tbSplit2.build(), splitKeys);
System.out.println(tableName + "预分region表创建成功!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 编写一个方法专门做比较过滤器的
* <p>
* 需要考虑的参数:表名 过滤器 操作符 比较器 值
*/
public static void scanDataWithCompareFilter(String tableName, String filterType, CompareOperator compareOperator,
String comparatorType, String value) {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf(tableName);
Table students = CONNECTION.getTable(st);
Scan scan = new Scan();
ByteArrayComparable byteArrayComparable = null;
switch (comparatorType) {
case "BinaryComparator":
byteArrayComparable = new BinaryComparator(Bytes.toBytes(value));
break;
case "BinaryPrefixComparator":
byteArrayComparable = new BinaryPrefixComparator(Bytes.toBytes(value));
break;
case "SubstringComparator":
byteArrayComparable = new SubstringComparator(value);
break;
default:
throw new NotFountComparatorException("没有匹配的比较器!使用ComparableName获取");
}
//--------------------------------------------------------------------------------
CompareFilter compareFilter = null;
switch (filterType) {
case "RowFilter":
compareFilter = new RowFilter(compareOperator, byteArrayComparable);
break;
case "FamilyFilter":
compareFilter = new FamilyFilter(compareOperator, byteArrayComparable);
break;
case "QualifierFilter":
compareFilter = new QualifierFilter(compareOperator, byteArrayComparable);
break;
case "ValueFilter":
compareFilter = new ValueFilter(compareOperator, byteArrayComparable);
break;
default:
throw new NotFoundFilterNameException("没有匹配的比较过滤器!使用FilterName获取");
}
//--------------------------------------------------------------------------------
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(compareFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void printResult(Result result) {
List<Cell> cells = result.listCells();
StringBuffer sb = new StringBuffer();
String rk = Bytes.toString(result.getRow());
sb.append(rk).append(",");
for (int i = 0; i < cells.size(); i++) {
String fa = Bytes.toString(CellUtil.cloneFamily(cells.get(i)));
String qName = Bytes.toString(CellUtil.cloneQualifier(cells.get(i)));
String colName = Bytes.toString(CellUtil.cloneValue(cells.get(i)));
if (i == cells.size() - 1) {
sb.append(fa).append(":").append(qName).append("-").append(colName); // 1001,info:name-xiaohu,info:age-18
} else {
sb.append(fa).append(":").append(qName).append("-").append(colName).append(",");
}
}
System.out.println(sb);
}
/**
* 释放Before创建的资源,在每个Test之后执行
*/
public static void closeSource() {
try {
if (ADMIN != null) {
ADMIN.close();
}
if (CONNECTION != null) {
CONNECTION.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
二、过滤器
比较过滤器:
1、行键过滤器:RowFilter
2、列簇过滤器:FamilyFilter
3、列名过滤器:QualifierFilter
4、列值过滤器:ValueFilter
专用过滤器:
5、单列值过滤器:SingleColumnValueFilter
SingleColumnValueFilter会返回满足条件的cell所在行的所有cell的值(即会返回一行数据)
6、列值排除过滤器:SingleColumnValueExcludeFilter
与SingleColumnValueFilter相反,会排除掉指定的列,其他的列全部返回
7、rowkey前缀过滤器:PrefixFilter
8、分页过滤器PageFilter
9、包装过滤器:
(1)SkipFilter过滤器:SkipFilter包装一个过滤器,当被包装的过滤器遇到一个需要过滤的 KeyValue 实例时,则拓展过滤整行数据。
(2)WhileMatchFilter过滤器:WhileMatchFilter 包装一个过滤器,当被包装的过滤器遇到一个需要过滤的 KeyValue 实例时,WhileMatchFilter 则结束本次扫描,返回已经扫描到的结果。
10、多过滤器综合查询:
以上都是讲解单个过滤器的作用,当需要多个过滤器共同作用于一次查询的时候,就需要使用 FilterList
。FilterList
支持通过构造器或者 addFilter
方法传入多个过滤器。
代码实现:
import com.shujia.bean.ComparableName;
import com.shujia.bean.FilterName;
import com.shujia.utils.HBaseUtil;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;
public class HBaseFilter {
private Connection conn;
private Admin admin;
/**
* 在所有Test方法执行之前执行
*/
@Before
public void getConnection() {
conn = HBaseUtil.CONNECTION;
admin = HBaseUtil.ADMIN;
}
/**
*行键过滤器RowFilter:
*需求:通过RowFilter与BinaryComparator(二进制内容比较器)过滤比rowKey 1500100010小的所有值出来
* 配合等值比较器BinaryComparator
*/
@Test
public void scanDataWithRowFilterAndBinaryComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建一个BinaryComparator比较器对象
BinaryComparator binaryComparator = new BinaryComparator(Bytes.toBytes("1500100010"));
//创建一个行键过滤器对象
//旧版本创建方式:public RowFilter(final CompareOp rowCompareOp,final ByteArrayComparable rowComparator)
// RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.LESS, binaryComparator);
//新版本创建方式:public RowFilter(final CompareOperator op,final ByteArrayComparable rowComparator)
RowFilter rowFilter = new RowFilter(CompareOperator.LESS, binaryComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(rowFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 列簇过滤器:FamilyFilter
* 需求:过滤出列簇名中包含“a”的列簇中所有数据配合包含比较器SubstringComparator
*/
@Test
public void scanDataWithFamilyFilterAndSubstringComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("users");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建一个包含比较器
SubstringComparator substringComparator = new SubstringComparator("f");
//创建列簇过滤器
//public FamilyFilter(final CompareOperator op, final ByteArrayComparable familyComparator)
FamilyFilter familyFilter = new FamilyFilter(CompareOperator.EQUAL, substringComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(familyFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 列名过滤器:QualifierFilter
* 通过QualifierFilter与SubstringComparator(包含比较器)查询列名包含 m 的列的值
*/
@Test
public void scanDataWithQualifierFilterAndSubstringComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("users");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建一个包含比较器
SubstringComparator substringComparator = new SubstringComparator("m");
//创建列名过滤器
//public QualifierFilter(final CompareOperator op, final ByteArrayComparable qualifierComparator)
QualifierFilter qualifierFilter = new QualifierFilter(CompareOperator.EQUAL, substringComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(qualifierFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 列值过滤器(属于比较过滤器)
* 通过ValueFilter与BinaryPrefixComparator(二进制前缀比较器)过滤出所有的cell中值以 "从" 开头的学生
* 注意:列值过滤器只能过滤出当前符合条件的列,至于与该列属于同一行的其他列并不会返回
*/
@Test
public void scanDataWithValueFilterAndBinaryPrefixComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建二进制前缀比较器
BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator(Bytes.toBytes("从"));
//创建列值过滤器对象
//public ValueFilter(final CompareOperator valueCompareOp, final ByteArrayComparable valueComparator)
ValueFilter valueFilter = new ValueFilter(CompareOperator.EQUAL, binaryPrefixComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(valueFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 单列值过滤器(专用过滤器)
* 需求:通过SingleColumnValueFilter与BinaryPrefixComparator过滤出所有的cell中值以 "从" 开头的学生
*/
@Test
public void scanDataWithSingleColumnValueFilterAndBinaryPrefixComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建二进制前缀比较器
BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator(Bytes.toBytes("从"));
//创建单列值过滤器
//public SingleColumnValueFilter(final byte [] family, final byte [] qualifier,
// final CompareOperator op,
// final org.apache.hadoop.hbase.filter.ByteArrayComparable comparator)
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info"), Bytes.toBytes("name"),
CompareOperator.EQUAL, binaryPrefixComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(singleColumnValueFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 列值排除过滤器
* SingleColumnValueExcludeFilter
* 通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
*/
@Test
public void scanDataWithSingleColumnValueExcludeFilterAndBinaryComparator() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建二进制内容比较器
BinaryComparator binaryComparator = new BinaryComparator(Bytes.toBytes("文科一班"));
//创建列值排除过滤器
//public SingleColumnValueExcludeFilter(byte[] family, byte[] qualifier,
// CompareOperator op, ByteArrayComparable comparator)
SingleColumnValueExcludeFilter singleColumnValueExcludeFilter = new SingleColumnValueExcludeFilter(Bytes.toBytes("info"), Bytes.toBytes("clazz"),
CompareOperator.EQUAL, binaryComparator);
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(singleColumnValueExcludeFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 行键前缀过滤器 PrefixFilter
* 通过PrefixFilter查询以15001001开头的所有前缀的rowkey
*/
@Test
public void scanDataWithPrefixFilter() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//PrefixFilter(final byte [] prefix)
PrefixFilter prefixFilter = new PrefixFilter(Bytes.toBytes("150010093"));
//设置过滤器
//public Scan setFilter(Filter filter)
scan.setFilter(prefixFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 分页过滤器
* PageFilter
* 通过PageFilter查询三页的数据,每页10条
*/
@Test
public void scanDataWithPageFilter() {
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
//设置几个变量
//设置要查询的页数
int pageNum = 5;
//设置每一页要查询的条数
int pageNumData = 10;
//设置开始行
String startRowKey = "";
//创建分页过滤器对象
PageFilter pageFilter = new PageFilter(pageNumData);
//创建Scan的对象
Scan scan = new Scan();
scan.setFilter(pageFilter);
for (int i = 1; i <= pageNum; i++) {
System.out.println("====================当前是第 " + i + " 页=========================");
//查询10条数据
ResultScanner resultScanner = students.getScanner(scan);
//获取该页的最后一行的行键
for (Result result : resultScanner) {
startRowKey = Bytes.toString(result.getRow()) + 0;
//设置下一行的开始
scan.withStartRow(Bytes.toBytes(startRowKey));
HBaseUtil.printResult(result);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 包装过滤器之SkipFilter过滤器
*
* 1500100071,祖昌勋,22,男,理科四班
*/
@Test
public void scanDataWithSkipFilter(){
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
ValueFilter valueFilter = new ValueFilter(CompareOperator.NOT_EQUAL, new SubstringComparator("理科"));
//创建跳过过滤器
//SkipFilter(Filter filter)
SkipFilter skipFilter = new SkipFilter(valueFilter);
scan.setFilter(skipFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 包装过滤器之WhileMatchFilter过滤器
*
* 1500100071,祖昌勋,22,男,理科四班
*/
@Test
public void scanDataWithWhileMatchFilter(){
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
ValueFilter valueFilter = new ValueFilter(CompareOperator.NOT_EQUAL, new SubstringComparator("祖昌勋"));
//创建跳过过滤器
//SkipFilter(Filter filter)
WhileMatchFilter whileMatchFilter = new WhileMatchFilter(valueFilter);
scan.setFilter(whileMatchFilter);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 组合过滤器
* 需求:通过运用4种比较器过滤出姓于,年纪大于22岁,性别为女,且是理科的学生。
*/
@Test
public void scanDataWithGroupFilter(){
try {
/**
* CompareFilter 是一个抽象类,无法被实例化
* 但是,我们通过观察源码,可以得到一些信息,创建比较过滤器对象的时候,至少需要传入两种参数:操作符,比较器
*/
//获取表对象
TableName st = TableName.valueOf("students");
Table students = conn.getTable(st);
Scan scan = new Scan();
//创建单列值过滤器
//过滤出姓于的
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info"), Bytes.toBytes("name"),
CompareOperator.EQUAL, new BinaryPrefixComparator(Bytes.toBytes("于")));
//年纪大于22岁
SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter(Bytes.toBytes("info"), Bytes.toBytes("age"),
CompareOperator.GREATER, new BinaryComparator(Bytes.toBytes("22")));
//性别为女
SingleColumnValueFilter singleColumnValueFilter2 = new SingleColumnValueFilter(Bytes.toBytes("info"), Bytes.toBytes("gender"),
CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("女")));
//理科
SingleColumnValueFilter singleColumnValueFilter3 = new SingleColumnValueFilter(Bytes.toBytes("info"), Bytes.toBytes("clazz"),
CompareOperator.EQUAL, new SubstringComparator("理科"));
//如何以每次添加一个过滤器作为条件的话,后一次添加的过滤器逻辑会将前一次覆盖
// scan.setFilter(singleColumnValueFilter);
// scan.setFilter(singleColumnValueFilter1);
// scan.setFilter(singleColumnValueFilter2);
// scan.setFilter(singleColumnValueFilter3);
//通过观察源码发现,虽然setFilter这个方法只能传Filter的子类对象
//但是我们发现了该抽象类的一个子类FilterList表示多个过滤器集合的意思
//所以我们可以先创建FilterList对象,将多个过滤器封装成List集合添加到FilterList对象中,最终将FilterList对象再添加到scan中
//先将上面4个过滤器添加到List集合中
ArrayList<Filter> filters = new ArrayList<>();
filters.add(singleColumnValueFilter);
filters.add(singleColumnValueFilter1);
filters.add(singleColumnValueFilter2);
filters.add(singleColumnValueFilter3);
//创建FilterList对象
FilterList filterList = new FilterList();
//public void addFilter(List<Filter> filters)
filterList.addFilter(filters);
scan.setFilter(filterList);
ResultScanner resultScanner = students.getScanner(scan);
for (Result result : resultScanner) {
HBaseUtil.printResult(result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testHBaseUtil() {
//需求:通过RowFilter与BinaryComparator过滤比rowKey 1500100010小的所有值出来
// HBaseUtil.scanDataWithCompareFilter("students", FilterName.ROWKEY,
// CompareOperator.LESS,ComparableName.BINARY,"1500100010");
//需求:过滤出列簇名中包含“a”的列簇中所有数据配合包含比较器SubstringComparator
// HBaseUtil.scanDataWithCompareFilter("users",FilterName.FAMILY,
// CompareOperator.EQUAL,ComparableName.SUBSTRING,"a");
//需求:通过QualifierFilter与SubstringComparator查询列名包含 m 的列的值
// HBaseUtil.scanDataWithCompareFilter("users",FilterName.QUALIFIER,
// CompareOperator.EQUAL,ComparableName.SUBSTRING,"m");
//需求:通过ValueFilter与BinaryPrefixComparator过滤出所有的cell中值以 "从" 开头的学生
HBaseUtil.scanDataWithCompareFilter("students", FilterName.VALUE,
CompareOperator.EQUAL, ComparableName.BINARY_PREFIX, "从");
}
/**
* 释放Before创建的资源,在每个Test之后执行
*/
@After
public void closeSource() {
HBaseUtil.closeSource();
}
}