hbase-api
HBase-api
1 依赖
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
2 log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
3 配置文件
配置文件中有域名映射的话,Windows也需要配
4 java-api操作
封装一个util
public class HBaseUtil {
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
private static HBaseUtil hBaseUtil = new HBaseUtil();
private HBaseUtil() {
}
public static HBaseUtil getInstance() throws IOException {
makeConnection();
return hBaseUtil;
}
//生成连接
private static void makeConnection() throws IOException {
Connection conn = threadLocal.get();
if (conn == null) {
conn = ConnectionFactory.createConnection(HBaseConfiguration.create());
threadLocal.set(conn);
}
}
public Connection getConnection(){
return threadLocal.get();
}
//创建表
public void createTable(String tableName, String... columnFamilys) throws IOException {
if (columnFamilys.length <= 0) {
throw new RuntimeException("没有设置列族信息~~~");
}
TableName name = TableName.valueOf(tableName);
Admin admin = threadLocal.get().getAdmin();
if (admin.tableExists(name)) {
throw new RuntimeException("表已经存在~~~");
}
HTableDescriptor hTableDescriptor = new HTableDescriptor(name);
for (String columnFamily : columnFamilys) {
hTableDescriptor.addFamily(new HColumnDescriptor(columnFamily));
}
admin.createTable(hTableDescriptor);
admin.close();
}
//创建指定版本个数的表
public void createTable(String tableName,int version,String... columnFamilys) throws IOException {
if (columnFamilys.length <= 0) {
throw new RuntimeException("没有设置列族信息~~~");
}
TableName name = TableName.valueOf(tableName);
Admin admin = threadLocal.get().getAdmin();
if (admin.tableExists(name)) {
throw new RuntimeException("表已经存在~~~");
}
HTableDescriptor hTableDescriptor = new HTableDescriptor(name);
for (String columnFamily : columnFamilys) {
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(columnFamily);
hColumnDescriptor.setMaxVersions(version);
hTableDescriptor.addFamily(hColumnDescriptor);
}
admin.createTable(hTableDescriptor);
admin.close();
}
//删除表
public void deleteTable(String tableName) throws IOException {
TableName name = TableName.valueOf(tableName);
Admin admin = threadLocal.get().getAdmin();
if (!admin.tableExists(name)) {
throw new RuntimeException("没有这张表~~~");
}
admin.disableTable(name);
admin.deleteTable(name);
admin.close();
}
//判断表是否存在
public boolean tableExist(String tableName) throws IOException {
Admin admin = threadLocal.get().getAdmin();
boolean b = admin.tableExists(TableName.valueOf(tableName));
admin.close();
return b;
}
//创建命名空间
public void createNameSpace(String nameSpace) throws IOException {
try {
Admin admin = threadLocal.get().getAdmin();
admin.createNamespace(NamespaceDescriptor.create(nameSpace).build());
admin.close();
} catch (NamespaceExistException e) {
throw new RuntimeException("命名空间已存在~~~");
}
}
//插入数据
public void insertData(String tableName, String rowkey, String family, String column, String value) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Put put = new Put(Bytes.toBytes(rowkey));
put.addColumn(Bytes.toBytes(family), Bytes.toBytes(column), Bytes.toBytes(value));
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
table.put(put);
table.close();
}
//获取数据
public void getData(String tableName,String rowkey) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Get get = new Get(Bytes.toBytes(rowkey));
Result result = table.get(get);
printData(result);
table.close();
}
//指定获取的列族
public void getData(String tableName,String rowkey,String family) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Get get = new Get(Bytes.toBytes(rowkey));
get.addFamily(Bytes.toBytes(family));
Result result = table.get(get);
printData(result);
table.close();
}
//指定获取的列
public void getData(String tableName,String rowkey,String family,String column) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Get get = new Get(Bytes.toBytes(rowkey));
get.addColumn(Bytes.toBytes(family), Bytes.toBytes(column));
Result result = table.get(get);
printData(result);
table.close();
}
//扫描数据
public void scanTable(String tableName) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Scan scan = new Scan();
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) {
printData(result);
}
table.close();
}
//区间扫描
public void scanTable(String tableName,String startRowKey,String stopRowKey) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Scan scan = new Scan(Bytes.toBytes(startRowKey),Bytes.toBytes(stopRowKey));
ResultScanner resultScanner = table.getScanner(scan);
for (Result result : resultScanner) {
printData(result);
}
table.close();
}
//删除数据(rowkey级别,相当于命令行deleteall)
public void deleteData(String tableName,String rowKey) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Delete delete = new Delete(Bytes.toBytes(rowKey));
table.delete(delete);
table.close();
}
//删除数据(列族级别)
public void deleteData(String tableName,String rowKey,String family) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Delete delete = new Delete(Bytes.toBytes(rowKey));
delete.addFamily(Bytes.toBytes(family));
table.delete(delete);
table.close();
}
//删除数据(column级别)
//addColumns: 会删除所有的版本,如果传入时间戳参数,则删除小于等于这个时间戳的所有版本
//addColumn: 仅删除最后一个版本,后面的版本会显示出来(当然如果flush了,那就找不到了,除非设置多个版本持久化,生产环境慎用)
public void deleteData(String tableName,String rowKey,String family,String column) throws IOException {
if (!tableExist(tableName)) {
throw new RuntimeException("没有这张表~~~");
}
Table table = threadLocal.get().getTable(TableName.valueOf(tableName));
Delete delete = new Delete(Bytes.toBytes(rowKey));
delete.addColumns(Bytes.toBytes(family), Bytes.toBytes(column));
table.delete(delete);
table.close();
}
//关闭连接
public void close() throws IOException {
Connection conn = threadLocal.get();
if (conn != null) {
conn.close();
threadLocal.remove();
}
}
//打印数据
public void printData(Result result){
for (Cell cell : result.rawCells()) {
System.out.println("***************分隔符***************");
System.out.println("rowkey = "+Bytes.toString(CellUtil.cloneRow(cell)));
System.out.println("family = "+Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println("column = "+Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println("value = "+Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
HBase 实战之谷粒微博
微博内容表
键 | 值 |
---|---|
rowkey | 当前用户id + “_” + ts(时间戳) |
family | info |
column | content |
value | “微博内容” |
关系表
键 | 值 |
---|---|
rowkey | 当前用户id |
family | attends(关注的人) , fans(粉丝) |
column | 关注人的id,fens的id |
value | 关注人的id,fens的id |
收件箱表
键 | 值 |
---|---|
rowkey | 当前用户id |
family | info |
column | 关注人的uid(消息推送) |
value | 微博内容表的rowkey |
1 需求分析
- 微博内容的浏览,数据库表设计
- 用户社交体现:关注用户,取关用户
- 拉取关注的人的微博内容
2 代码设计总览:
- 创建命名空间以及表名的定义
- 创建微博内容表
- 创建用户关系表
- 创建用户微博内容接收邮件表
- 发布微博内容
- 添加关注用户
- 移除(取关)用户
- 获取关注的人的微博内容
- 测试
3 代码实现
定义常量
public class Constants {
public static final Configuration CONFIGURATION= HBaseConfiguration.create();
//命名空间
public static final String NAMESPACE="blog";
//微博内容表
public static final String CONTENT_TABLE="blog:content";
public static final String CONTENT_TABLE_CF="info";
public static final int CONTENT_TABLE_VERSION=1;
//用户关系表
public static final String RELATION_TABLE="blog:relation";
public static final String RELATION_TABLE_CF1="attends";
public static final String RELATION_TABLE_CF2="fans";
public static final int RELATION_TABLE_VERSION=1;
//收件箱表
public static final String INBOX_TABLE="blog:inbox";
public static final String INBOX_TABLE_CF="info";
public static final int INBOX_TABLE_VERSION=2;
}
编写操作层
public class HBaseDao {
//[发布微博]
public static void publishBlog(String uid,String content) throws IOException {
//第一部分:操作微博内容表
Connection conn = ConnectionFactory.createConnection(Constants.CONFIGURATION);
//1.获取微博内容表对象
Table contTable = conn.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
//2.拼接rowkey
//获取当前时间戳
long ts = System.currentTimeMillis();
String rowkey=uid+"_"+ts;
//3.获取put对象
Put contPut=new Put(Bytes.toBytes(rowkey));
//4.给put对象赋值
contPut.addColumn(Bytes.toBytes(Constants.CONTENT_TABLE_CF), Bytes.toBytes("content"), Bytes.toBytes(content));
contTable.put(contPut);
//第二部分:操作微博收件箱表
//1.获取用户关系表对象
Table relaTable = conn.getTable(TableName.valueOf(Constants.RELATION_TABLE));
//2.获取当前发布微博人的fans列族数据
Get get = new Get(Bytes.toBytes(uid));
get.addFamily(Bytes.toBytes(Constants.RELATION_TABLE_CF2));
Result relaResult = relaTable.get(get);
//3.创建一个集合,用于存放微博内容表的put对象
List<Put> inboxPuts = new ArrayList<>();
for (Cell cell : relaResult.rawCells()) {
//4.构建微博收件箱表的put对象
Put inboxPut=new Put(CellUtil.cloneQualifier(cell));
//5.给收件箱表的put对象赋值
inboxPut.addColumn(Bytes.toBytes(Constants.INBOX_TABLE_CF), Bytes.toBytes(uid), Bytes.toBytes(rowkey));
//6.将收件箱表的put对象存入集合
inboxPuts.add(inboxPut);
}
//7.判断是否有粉丝
if (inboxPuts.size()>0) {
//获取收件箱表对象
Table inboxTable = conn.getTable(TableName.valueOf(Constants.INBOX_TABLE));
//执行收件箱表插入操作
inboxTable.put(inboxPuts);
//关闭收件箱表
inboxTable.close();
}
relaTable.close();
contTable.close();
conn.close();
}
//[关注用户]
public static void addAttends(String uid,String... attends) throws IOException {
//校验是否添加了待关注的人
if (attends.length<=0) {
System.out.println("请选择待关注的人");
return;
}
//获取连接
Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
//第一步:操作用户关系表
//1.获取用户关系表对象
Table relaTable = connection.getTable(TableName.valueOf(Constants.RELATION_TABLE));
//2.创建一个集合,用于存放关系表的put对象
List<Put> relaPuts=new ArrayList<>();
//3.创建操作者的put对象
Put uidPut=new Put(Bytes.toBytes(uid));
//4.循环待关注者id
for (String attend : attends) {
//5.给操作者的put对象赋值
uidPut.addColumn(Bytes.toBytes(Constants.RELATION_TABLE_CF1), Bytes.toBytes(attend), Bytes.toBytes(attend));
//6.创建被关注者的put对象
Put attendPut = new Put(Bytes.toBytes(attend));
//7.给被关注者的put对象赋值
attendPut.addColumn(Bytes.toBytes(Constants.RELATION_TABLE_CF2), Bytes.toBytes(uid), Bytes.toBytes(uid));
//8.将被关注者的对象放入集合
relaPuts.add(attendPut);
}
//9.将操作者的put对象添加至集合
relaPuts.add(uidPut);
//10.用户关系表的插入数据操作
relaTable.put(relaPuts);
//第二步:操作收件箱表
//1.获取微博内容表对象
Table contTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
//2.创建收件箱表的put对象
Put inboxPut = new Put(Bytes.toBytes(uid));
//3.循环attends,获取每个被关注者的近期发布的微博
for (String attend:attends) {
//4.获取当前被关注者的近期发布的微博(scan)->集合ResultScanner
Scan scan = new Scan(Bytes.toBytes(attend+"_"),Bytes.toBytes(attend+"|"));
ResultScanner resultScanner = contTable.getScanner(scan);
//定义一个时间戳(如果没有时间戳,批量添加的时间戳相同,那么数据会被覆盖)
long ts = System.currentTimeMillis();
//5.对获取的值进行遍历
for (Result result : resultScanner) {
//6.给收件箱表的put对象赋值
inboxPut.addColumn(Bytes.toBytes(Constants.INBOX_TABLE_CF), Bytes.toBytes(attend),ts++,result.getRow());
}
}
//7.判断当前的put对象是否为空
if(!inboxPut.isEmpty()){
//获取收件箱表对象
Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
//插入数据
inboxTable.put(inboxPut);
//关闭收件箱表对象
inboxTable.close();
}
//关闭资源
relaTable.close();
contTable.close();
connection.close();
}
//[取关]
public static void deleteAttends(String uid,String... deletes) throws IOException {
//校验是否添加了待关注的人
if (deletes.length<=0) {
System.out.println("请选择待关注的人");
return;
}
//获取connection对象
Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
//第一部分:操作用户关系表
//1.获取用户关系表对象
Table relaTable = connection.getTable(TableName.valueOf(Constants.RELATION_TABLE));
//2.创建一个集合,用于存放用户关系表的delete对象
List<Delete> delList=new ArrayList<>();
//3.创建操作者的delete对象
Delete uidDel=new Delete(Bytes.toBytes(uid));
//4.循环创建被取关者的delete对象
for (String delete:deletes) {
//5.给操作者的delete对象赋值
uidDel.addColumns(Bytes.toBytes(Constants.RELATION_TABLE_CF1), Bytes.toBytes(delete));
//6.创建被取关者的delete对象
Delete delDelete = new Delete(Bytes.toBytes(delete));
//7.给被取关者的delete对象赋值
delDelete.addColumns(Bytes.toBytes(Constants.RELATION_TABLE_CF2), Bytes.toBytes(uid));
//8.将被取关者的delete对象添加至集合
delList.add(delDelete);
}
//9.将操作者的delete对象添加至集合
delList.add(uidDel);
//10.执行yoghurt关系表的删除操作
relaTable.delete(delList);
//第二部分:操作收件箱表
//1.获取收件箱表对象
Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
//2.创建操作者的delete对象
Delete inboxDelete = new Delete(Bytes.toBytes(uid));
//3.给操作者的delete对象赋值
for (String delete:deletes) {
inboxDelete.addColumns(Bytes.toBytes(Constants.INBOX_TABLE_CF), Bytes.toBytes(delete));
}
//4.执行收件箱表删除操作
inboxTable.delete(inboxDelete);
//关闭资源
relaTable.close();
inboxTable.close();
connection.close();
}
//[获取用户初始化数据]
public static void getInit(String uid) throws IOException {
//1.获取connection对象
Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
//2.获取收件箱表对象
Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
//3.获取微博内容表对象
Table contTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
//4.创建收件箱表get对象,并获取数据(设置最大版本)
Get inboxGet=new Get(Bytes.toBytes(uid));
inboxGet.setMaxVersions();
Result inboxResult = inboxTable.get(inboxGet);
//5.遍历获取的数据
for (Cell inboxCell:inboxResult.rawCells()) {
//6.构建微博内容表get对象
Get contGet = new Get(CellUtil.cloneValue(inboxCell));
//7.获取该get对象的数据内容
Result contResult = contTable.get(contGet);
//8.解析内容并打印
for (Cell contCell : contResult.rawCells()) {
System.out.println("rowkey: "+Bytes.toString(CellUtil.cloneRow(contCell)));
System.out.println("family: "+Bytes.toString(CellUtil.cloneFamily(contCell)));
System.out.println("column: "+Bytes.toString(CellUtil.cloneQualifier(contCell)));
System.out.println("value: "+Bytes.toString(CellUtil.cloneValue(contCell)));
}
}
//9.关闭资源
inboxTable.close();
contTable.close();
connection.close();
}
//[获取某个人的所有微博详情]
public static void getBlog(String uid) throws IOException {
//1.获取connection对象
Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
//2.获取微博内容表对象
Table contTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
//3.构建scan对象
Scan scan = new Scan();
RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL,new SubstringComparator(uid+"_")) ;
scan.setFilter(filter);
//4.获取数据
ResultScanner scanner = contTable.getScanner(scan);
//5.解析数据并打印
for (Result result : scanner) {
for (Cell cell : result.rawCells()) {
System.out.println("rowkey: "+Bytes.toString(CellUtil.cloneRow(cell)));
System.out.println("family: "+Bytes.toString(CellUtil.cloneFamily(cell)));
System.out.println("column: "+Bytes.toString(CellUtil.cloneQualifier(cell)));
System.out.println("value: "+Bytes.toString(CellUtil.cloneValue(cell)));
}
}
//6.关闭资源
contTable.close();
connection.close();
}
}
编写测试类
util就用上面的
public class TestBlog {
public static void init() throws IOException {
HBaseUtil instance = HBaseUtil.getInstance();
//创建命名空间
instance.createNameSpace(Constants.NAMESPACE);
//创建微博内容表
instance.createTable(Constants.CONTENT_TABLE,Constants.CONTENT_TABLE_VERSION,Constants.CONTENT_TABLE_CF);
//创建用户关系表
instance.createTable(Constants.RELATION_TABLE,Constants.RELATION_TABLE_VERSION,Constants.RELATION_TABLE_CF1,Constants.RELATION_TABLE_CF2 );
//创建收件箱表
instance.createTable(Constants.INBOX_TABLE, Constants.INBOX_TABLE_VERSION,Constants.INBOX_TABLE_CF);
}
public static void main(String[] args) throws IOException, InterruptedException {
//初始化
init();
//1001发布微博
HBaseDao.publishBlog("1001", "赶紧下课吧!!!");
//1002关注1001和1003
HBaseDao.addAttends("1002","1001","1003");
//获取1002初始化页面
HBaseDao.getInit("1002");
System.out.println("*****************111*****************");
//1003发布3条微博,同时1001发布2条
HBaseDao.publishBlog("1003", "谁说的赶紧下课!!!");
Thread.sleep(10);
HBaseDao.publishBlog("1001", "我没说话!!!");
Thread.sleep(10);
HBaseDao.publishBlog("1003", "那谁说的!!!");
Thread.sleep(10);
HBaseDao.publishBlog("1001", "反正飞机是下线了!!!");
Thread.sleep(10);
HBaseDao.publishBlog("1003", "你们爱咋咋地!!!");
//获取1002的初始化页面
HBaseDao.getInit("1002");
System.out.println("*****************222*****************");
//1002取关1003
HBaseDao.deleteAttends("1002", "1003");
//获取1002初始化页面
HBaseDao.getInit("1002");
System.out.println("*****************333*****************");
//1002再次关注1003
HBaseDao.addAttends("1002", "1003");
//获取1002初始化页面
HBaseDao.getInit("1002");
System.out.println("*****************444*****************");
//获取1001微博详情
HBaseDao.getBlog("1001");
}
}
总结
文章内容主要来自尚硅谷