HBase应用之微博案例
一. 需求分析
1) 微博内容的浏览,数据库表设计
2) 用户社交体现:关注用户,取关用户
3) 拉取关注的人的微博内容
二. 代码实现
代码设计总览:
1.创建命名空间以及表名的定义
//获取配置 conf
private Configuration conf = HBaseConfiguration.create();
//微博内容表的表名
private static final byte[] TABLE_CONTENT = Bytes.toBytes("ns_weibo:content");
//用户关系表的表名
private static final byte[] TABLE_RELATION = Bytes.toBytes("ns_weibo:relation");
//微博收件箱表的表名
private static final byte[] TABLE_INBOX = Bytes.toBytes("ns_weibo:inbox");
/**
*初始化命名空间
*@param args
*/
public void initNamespace(){ HBaseAdmin admin = null; try {
Connection connection = ConnectionFactory.createConnection(conf); admin = (HBaseAdmin) connection.getAdmin();
//命名空间类似于关系型数据库中的 schema,可以想象成文件夹
NamespaceDescriptor weibo = NamespaceDescriptor
.create("ns_weibo")
.addConfiguration("creator", "Jinji")
.addConfiguration("create_time", System.currentTimeMillis() + "")
.build(); admin.createNamespace(weibo);
} catch (MasterNotRunningException e) {
e.printStackTrace();
} catch (ZooKeeperConnectionException e) { e.printStackTrace();
} catch (IOException e) { e.printStackTrace();
}finally{
if(null != admin){ try {
admin.close();
} catch (IOException e) { e.printStackTrace();
}
2. 创建微博内容表
表结构
|
方法名 |
creatTableeContent |
|
Table Name |
ns_weibo:content |
|
RowKey |
用户 ID_时间戳 |
|
ColumnFamily |
info |
|
ColumnLabel |
标题,内容,图片 |
|
Version |
1 个版本 |
代码
/**
*创建微博内容表
*Table Name:ns_weibo:content
*RowKey:用户 ID_时间戳
*ColumnFamily:info
*ColumnLabel:标题,内容,图片 URL
*Version:1 个版本
*/
public void createTableContent(){ HBaseAdmin admin = null;
Connection connection = null; try {
connection = ConnectionFactory.createConnection(conf); admin = (HBaseAdmin) connection.getAdmin();
//创建表表述
HTableDescriptor contentTableDescriptor = new
HTableDescriptor(TableName.valueOf(TABLE_CONTENT));
//创建列族描述
HColumnDescriptor infoColumnDescriptor = new HColumnDescriptor(Bytes.toBytes("info"));
//设置块缓存
infoColumnDescriptor.setBlockCacheEnabled(true);
//设置块缓存大小
infoColumnDescriptor.setBlocksize(2097152);
//设置压缩方式
// infoColumnDescriptor.setCompressionType(Algorithm.SNAPPY);
//设置版本确界
infoColumnDescriptor.setMaxVersions(1);
infoColumnDescriptor.setMinVersions(1); contentTableDescriptor.addFamily(infoColumnDescriptor);
admin.createTable(contentTableDescriptor);
} catch (IOException e) { e.printStackTrace();
} finally{
if(null != admin){ try {
admin.close(); connection.close();
} catch (IOException e) { e.printStackTrace();
}
}
}
}
3.创建用户关系表
表结构
|
方法名 |
createTableRelations |
|
Table Name |
ns_weibo:relation |
|
RowKey |
用户 ID |
|
ColumnFamily |
attends、fans |
|
ColumnLabel |
关注用户 ID,粉丝用户 ID |
|
ColumnValue |
用户 ID |
|
Version |
1 个版本 |
代码:
/**
*用户关系表
*Table Name:ns_weibo:relation
*RowKey:用户 ID
*ColumnFamily:attends,fans
*ColumnLabel:关注用户 ID,粉丝用户 ID
*ColumnValue:用户 ID
*Version:1 个版本
*/
public void createTableRelation(){
HBaseAdmin admin = null; try {
Connection connection = ConnectionFactory.createConnection(conf); admin = (HBaseAdmin) connection.getAdmin();
HTableDescriptor relationTableDescriptor = new HTableDescriptor(TableName.valueOf(TABLE_RELATION));
//关注的人的列族
HColumnDescriptor attendColumnDescriptor = new HColumnDescriptor(Bytes.toBytes("attends"));
//设置块缓存
attendColumnDescriptor.setBlockCacheEnabled(true);
//设置块缓存大小
attendColumnDescriptor.setBlocksize(2097152);
//设置压缩方式
//attendColumnDescriptor.setCompressionType(Algorithm.SNAPPY);
//设置版本确界
attendColumnDescriptor.setMaxVersions(1);
attendColumnDescriptor.setMinVersions(1);
//粉丝列族
HColumnDescriptor fansColumnDescriptor = new
HColumnDescriptor(Bytes.toBytes("fans"));
fansColumnDescriptor.setBlockCacheEnabled(true);
fansColumnDescriptor.setBlocksize(2097152);
fansColumnDescriptor.setMaxVersions(1);
fansColumnDescriptor.setMinVersions(1);
relationTableDescriptor.addFamily(attendColumnDescriptor);
relationTableDescriptor.addFamily(fansColumnDescriptor);
admin.createTable(relationTableDescriptor);
} catch (MasterNotRunningException e) { e.printStackTrace();
} catch (ZooKeeperConnectionException e) { e.printStackTrace();
} catch (IOException e) { e.printStackTrace();
}finally{
if(null != admin){ try {
admin.close();
} catch (IOException e)
{ e.printStackTrace();
}
}
4.创建用户微博内容接收邮件表
表结构:
|
方法名 |
createTableInbox |
|
Table Name |
ns_weibo:inbox |
|
RowKey |
用户 ID |
|
ColumnFamily |
info |
|
ColumnLabel |
用户 ID |
|
ColumnValue |
取微博内容的 RowKey |
|
Version |
1000 |
代码:
/**
*创建微博收件箱表
*Table Name: ns_weibo:inbox
*RowKey:用户 ID
*ColumnFamily:info
*ColumnLabel:用户 ID_发布微博的人的用户 ID
*ColumnValue:关注的人的微博的 RowKey
*Version:1000
*/
public void createTableInbox(){ HBaseAdmin admin = null; try {
Connection connection = ConnectionFactory.createConnection(conf); admin = (HBaseAdmin) connection.getAdmin();
HTableDescriptor inboxTableDescriptor = new HTableDescriptor(TableName.valueOf(TABLE_INBOX));
HColumnDescriptor infoColumnDescriptor = new
HColumnDescriptor(Bytes.toBytes("info"));
infoColumnDescriptor.setBlockCacheEnabled(true);
infoColumnDescriptor.setBlocksize(2097152);
infoColumnDescriptor.setMaxVersions(1000);
infoColumnDescriptor.setMinVersions(1000);
inboxTableDescriptor.addFamily(infoColumnDescriptor);
admin.createTable(inboxTableDescriptor);
} catch (MasterNotRunningException e) { e.printStackTrace();
} catch (ZooKeeperConnectionException e) { e.printStackTrace();
} catch (IOException e) { e.printStackTrace();
}finally{
if(null != admin){ try {
admin.close();
} catch (IOException e) { e.printStackTrace();
}
5.发布微博内容
a、微博内容表中添加 1 条数据
b、微博收件箱表对所有粉丝用户添加数据代码:Message.java
package com.z.hbase.weibo;
public class Message { private String uid;
private String timestamp; private String content;
public String getUid() {
return uid;
}
public void setUid(String uid) { this.uid = uid;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) { this.timestamp = timestamp;
}
public String getContent() {
return content;
}
public void setContent(String content) { this.content = content;
}
@Override
public String toString() {
return "Message [uid=" + uid + ", timestamp=" + timestamp + ", content=" + content +"]";
}
}
代码:public void publishContent(String uid, String content)
/**
*发布微博
*a、微博内容表中数据+1
*b、向微博收件箱表中加入微博的 Rowkey
*/
public void publishContent(String uid, String content){ Connection connection = null;
try {
connection = ConnectionFactory.createConnection(conf);
//a、微博内容表中添加 1 条数据,首先获取微博内容表描述
Table contentTable = connection.getTable(TableName.valueOf(TABLE_CONTENT));
//组装 Rowkey
long timestamp = System.currentTimeMillis(); String rowKey = uid + "_" + timestamp;
//添加微博内容
Put put = new Put(Bytes.toBytes(rowKey)); put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("content"), timestamp,
Bytes.toBytes(content));
contentTable.put(put);
//b、向微博收件箱表中加入发布的 Rowkey
//b.1、查询用户关系表,得到当前用户有哪些粉丝
Table relationTable = connection.getTable(TableName.valueOf(TABLE_RELATION));
//b.2、取出目标数据
Get get = new Get(Bytes.toBytes(uid)); get.addFamily(Bytes.toBytes("fans"));
Result result = relationTable.get(get);
List<byte[]> fans = new ArrayList<byte[]>();
//遍历取出当前发布微博的用户的所有粉丝数据for(Cell cell : result.rawCells()){
fans.add(CellUtil.cloneQualifier(cell));
}
//如果该用户没有粉丝,则直接 return
if(fans.size() <= 0) return;
//开始操作收件箱表
Table inboxTable = connection.getTable(TableName.valueOf(TABLE_INBOX));
//每一个粉丝,都要向收件箱中添加该微博的内容,所以每一个粉丝都是一个 Put
对象
List<Put> puts = new
ArrayList<Put>(); for(byte[] fan : fans){
Put fansPut = new Put(fan);
fansPut.addColumn(Bytes.toBytes("info"), Bytes.toBytes(uid), timestamp,
Bytes.toBytes(rowKey));
puts.add(fansPut);
}
inboxTable.put(puts);
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != connection){ try {
connection.close();
} catch (IOException e) { e.printStackTrace();
}
}
6.添加关注用户
a、在微博用户关系表中,对当前主动操作的用户添加新关注的好友
b、在微博用户关系表中,对被关注的用户添加新的粉丝
c、微博收件箱表中添加所关注的用户发布的微博
代码实现:public void addAttends(String uid, String... attends)
/**
*关注用户逻辑
*a、在微博用户关系表中,对当前主动操作的用户添加新的关注的好友
*b、在微博用户关系表中,对被关注的用户添加粉丝(当前操作的用户)
*c、当前操作用户的微博收件箱添加所关注的用户发布的微博 rowkey
*/
public void addAttends(String uid, String... attends){
//参数过滤
if(attends == null || attends.length <= 0 || uid == null || uid.length() <= 0){
return;
}
Connection connection = null; try {
connection = ConnectionFactory.createConnection(conf);
//用户关系表操作对象(连接到用户关系表)
Table relationTable = connection.getTable(TableName.valueOf(TABLE_RELATION));
List<Put> puts = new ArrayList<Put>();
//a、在微博用户关系表中,添加新关注的好友
Put attendPut = new Put(Bytes.toBytes(uid)); for(String attend : attends){
//为当前用户添加关注的人
attendPut.addColumn(Bytes.toBytes("attends"), Bytes.toBytes(attend),
Bytes.toBytes(attend));
//b、为被关注的人,添加粉丝
Put fansPut = new Put(Bytes.toBytes(attend)); fansPut.addColumn(Bytes.toBytes("fans"), Bytes.toBytes(uid),
Bytes.toBytes(uid));
//将所有关注的人一个一个的添加到 puts(List)集合中
puts.add(fansPut);
}
puts.add(attendPut); relationTable.put(puts);
//c.1、微博收件箱添加关注的用户发布的微博内容(content)的 rowkey
Table contentTable = connection.getTable(TableName.valueOf(TABLE_CONTENT)); Scan scan = new Scan();
//用于存放取出来的关注的人所发布的微博的 rowkey
List<byte[]> rowkeys = new ArrayList<byte[]>();
for(String attend : attends){
//过滤扫描 rowkey,即:前置位匹配被关注的人的 uid_
RowFilter filter = new RowFilter(CompareFilter.CompareOp.EQUAL, new
SubstringComparator(attend + "_"));
//为扫描对象指定过滤规则
scan.setFilter(filter);
//通过扫描对象得到 scanner
ResultScanner result = contentTable.getScanner(scan);
//迭代器遍历扫描出来的结果集
Iterator<Result> iterator = result.iterator(); while(iterator.hasNext()){
//取出每一个符合扫描结果的那一行数据
Result r = iterator.next();
for(Cell cell : r.rawCells()){
//将得到的 rowkey 放置于集合容器中
rowkeys.add(CellUtil.cloneRow(cell));
}
}
}
//c.2、将取出的微博 rowkey 放置于当前操作的用户的收件箱中
if(rowkeys.size() <= 0) return;
//得到微博收件箱表的操作对象
Table inboxTable = connection.getTable(TableName.valueOf(TABLE_INBOX));
/用于存放多个关注的用户的发布的多条微博 rowkey 信息
List<Put> inboxPutList = new ArrayList<Put>();
for(byte[] rk : rowkeys){
Put put = new Put(Bytes.toBytes(uid));
//uid_timestamp
String rowKey = Bytes.toString(rk);
//截取 uid
String attendUID = rowKey.substring(0, rowKey.indexOf("_"));
long timestamp = Long.parseLong(rowKey.substring(rowKey.indexOf("_") + 1));
//将微博 rowkey 添加到指定单元格中
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes(attendUID), timestamp, rk); inboxPutList.add(put);
}
inboxTable.put(inboxPutList);
} catch (IOException e) {
e.printStackTrace();
}finally{
if(null != connection){ try {
connection.close();
} catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
}
}
}
7.移除(取关)用户
a、在微博用户关系表中,对当前主动操作的用户移除取关的好友(attends)
b、在微博用户关系表中,对被取关的用户移除粉丝
c、微博收件箱中删除取关的用户发布的微博
代码:public void removeAttends(String uid, String... attends)
/**
*取消关注(remove)
*a、在微博用户关系表中,对当前主动操作的用户删除对应取关的好友
*b、在微博用户关系表中,对被取消关注的人删除粉丝(当前操作人)
*c、从收件箱中,删除取关的人的微博的 rowkey
*
*/
public void removeAttends(String uid, String... attends){
//过滤数据
if(uid == null || uid.length() <= 0 || attends == null || attends.length <= 0) return;
try {
Connection connection = ConnectionFactory.createConnection(conf);
//a、在微博用户关系表中,删除已关注的好友
Table relationTable = connection.getTable(TableName.valueOf(TABLE_RELATION));
//待删除的用户关系表中的所有数据 List<Delete> deleteList = new ArrayList<Delete>();
//当前取关操作者的 uid 对应的 Delete 对象
Delete attendDelete = new Delete(Bytes.toBytes(uid));
//遍历取关,同时每次取关都要将被取关的人的粉丝-1 for(String attend : attends){
attendDelete.addColumn(Bytes.toBytes("attends"), Bytes.toBytes(attend));
//b、在微博用户关系表中,对被取消关注的人删除粉丝(当前操作人) Delete fansDelete = new Delete(Bytes.toBytes(attend));
fansDelete.addColumn(Bytes.toBytes("fans"), Bytes.toBytes(uid)); deleteList.add(fansDelete);
}
deleteList.add(attendDelete); relationTable.delete(deleteList);
//c、删除取关的人的微博 rowkey 从 收件箱表中
Table inboxTable = connection.getTable(TableName.valueOf(TABLE_INBOX));
Delete inboxDelete = new Delete(Bytes.toBytes(uid)); for(String attend : attends){
inboxDelete.addColumn(Bytes.toBytes("info"), Bytes.toBytes(attend));
}
inboxTable.delete(inboxDelete)
} catch (IOException e) { e.printStackTrace();
}
}
8.获取关注的人的微博内容
a、从微博收件箱中获取所关注的用户的微博 RowKey
b、根据获取的 RowKey,得到微博内容
代码实现:public List<Message> getAttendsContent(String uid)
/**
* 获取微博实际内容
*a、从微博收件箱中获取所有关注的人的发布的微博的 rowkey
*b、根据得到的 rowkey 去微博内容表中得到数据
*c、将得到的数据封装到 Message 对象中
*/
public List<Message> getAttendsContent(String uid){ Connection connection = null;
try {
connection = ConnectionFactory.createConnection(conf)
Table inboxTable = connection.getTable(TableName.valueOf(TABLE_INBOX));
//a、从收件箱中取得微博 rowKey
Get get = new Get(Bytes.toBytes(uid));
//设置最大版本号
get.setMaxVersions(5);
List<byte[]> rowkeys = new ArrayList<byte[]>(); Result result = inboxTable.get(get);
for(Cell cell : result.rawCells()){ rowkeys.add(CellUtil.cloneValue(cell));
}
//b、根据取出的所有 rowkey 去微博内容表中检索数据
Table contentTable = connection.getTable(TableName.valueOf(TABLE_CONTENT)); List<Get> gets = new ArrayList<Get>();
//根据 rowkey 取出对应微博的具体内容
for(byte[] rk : rowkeys){
Get g = new Get(rk); gets.add(g);
}
//得到所有的微博内容的 result 对象
Result[] results = contentTable.get(gets);
//将每一条微博内容都封装为消息对象
List<Message> messages = new ArrayList<Message>(); for(Result res : results){
for(Cell cell : res.rawCells()){
Message message = new Message();
String rowKey = Bytes.toString(CellUtil.cloneRow(cell));
String userid = rowKey.substring(0, rowKey.indexOf("_")); String timestamp = rowKey.substring(rowKey.indexOf("_") + 1);
String content = Bytes.toString(CellUtil.cloneValue(cell));
message.setContent(content); message.setTimestamp(timestamp);
message.setUid(userid);
messages.add(message)
}
}
return messages;
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
9.测试
-- 测试发布微博内容
public void testPublishContent(WeiBo wb)
-- 测试添加关注
public void testAddAttend(WeiBo wb)
-- 测试取消关注
public void testRemoveAttend(WeiBo wb)
-- 测试展示内容
public void testShowMessage(WeiBo wb)
代码:
/**
*发布微博内容
*添加关注
*取消关注
*展示内容
*/
public void testPublishContent(WeiBo wb){
wb.publishContent("0001", "今天买了一包空气,送了点薯片,非常开心!!"); wb.publishContent("0001", "今天天气不错。");
}
public void testAddAttend(WeiBo wb){ wb.publishContent("0008", "准备下课!");
wb.publishContent("0009", "准备关机!"); wb.addAttends("0001", "0008", "0009");
}
public void testRemoveAttend(WeiBo wb){ wb.removeAttends("0001", "0008");
}
public void testShowMessage(WeiBo wb){
List<Message> messages = wb.getAttendsContent("0001"); for(Message message : messages){
System.out.println(message);
}
}
public static void main(String[] args) {
WeiBo weibo = new WeiBo();
weibo.initTable();
weibo.testPublishContent(weibo);
weibo.testAddAttend(weibo);
weibo.testShowMessage(weibo);
weibo.testRemoveAttend(weibo);
weibo.testShowMessage(weibo);
}
HBase应用之微博案例的更多相关文章
- hbase性能调优案例
hbase性能调优案例 1.人员-角色 人员有多个角色 角色优先级 角色有多个人员 人员 删除添加角色 角色 可以添加删除人员 人员 角色 删除添加 设计思路 person表 ...
- HBase与Sqoop集成案例
HBase与Sqoop集成 案例:将RDBMS中的数据抽取到HBase中 Step1.配置sqoop-env.sh如下: Step2.在Mysql中创建一张数据库library,一张表book CRE ...
- 吴裕雄--天生自然HADOOP操作实验学习笔记:hbase微博案例
实验目的 熟悉hbase表格设计的方法 熟悉hbase的javaAPI 通过API理解掌握hbase的数据的逻辑视图 了解MVC的服务端设计方式 实验原理 上次我们已经初步设计了学生选课案例的,具体功 ...
- iOS开发——UI进阶篇(三)自定义不等高cell,如何拿到cell的行高,自动计算cell高度,(有配图,无配图)微博案例
一.纯代码自定义不等高cell 废话不多说,直接来看下面这个例子先来看下微博的最终效果 首先创建一个继承UITableViewController的控制器@interface ViewControll ...
- 75.《nodejs开发指南》express4.x版-微博案例完整实现
转自:https://blog.csdn.net/cgwcgw_/article/details/39317587 完整代码下载 https://github.com/haishangfeie/wei ...
- jQuery 发布微博案例
.box { width: 500px; height: 500px; border: 1px solid #efefef; margin: 0 auto; text-align: center; } ...
- hbase性能调优_表设计案例
hbase性能调优案例 1.人员-角色 人员有多个角色 角色优先级 角色有多个人员 人员 删除添加角色 角色 可以添加删除人员 人员 角色 删除添加 设计思路 person表 ...
- 《OD学HBase》20160820
一.案例 微博: 微博内容: 关注用户和粉丝用户: 添加或移除关注用户 查看关注用户的微博内容 微博数据存储: 响应时间 秒级 无延迟 (1)mysql分布式 (2)hbase数据库 使用HBase数 ...
- 1.HBase In Action 第一章-HBase简介(后续翻译中)
This chapter covers ■ The origins of Hadoop, HBase, and NoSQL ■ Common use cases for HBase ■ A basic ...
随机推荐
- 给Java新手的一些建议——Java知识点归纳(Java基础部分)
原文出处:CSDN邓帅 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些Java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行 ...
- JVM小结--类文件结构
字节码是构成Java平台无关性的基石.实现语言无关性的基础是虚拟机和字节码存储格式. Java语言中的各种变量.关键字和运算符的语义最终是由多条字节码命令组成,因此字节码命令所能提供的语义描述能力肯定 ...
- C++函数不能为virtual的场景
1.类函数不能同时被static和virtual修饰. 2.类的模板函数不能被virtual修饰 未完待续
- 安装并使用 Wowza 发布你的 RTMP 直播流
转载自:http://blog.csdn.net/defonds/article/details/11979095 I. 下载 Wowza 官方下载地址 http://www.wowz ...
- HashMap源码分析-基于JDK1.8
hashMap数据结构 类注释 HashMap的几个重要的字段 hash和tableSizeFor方法 HashMap的数据结构 由上图可知,HashMap的基本数据结构是数组和单向链表或红黑树. 以 ...
- SourceTree免密克隆仓库及问题说明
前言说明: 公司陆陆续续进新员工,新员工都需要了解公司各类资料,而公司资料都存储于gitlab中,因此,新员工需要安装工具进行资料拉取. 公司采用SourceTree的是工具.相关下载地址如下: WI ...
- 【转】(总结)Nginx配置文件nginx.conf中文详解
本文转载自:http://www.ha97.com/5194.html 定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU总核心数 worker_pr ...
- python 远程执行命令、发布文件
最近有个需求,想获取部分服务器上运行了那些应用服务,一台台去看,太费劲了,参考牛人写了此脚本,后期再加上一个前端页面做一些简单的运维维护的工作,凑合着先用着,待完善, 注:此脚本依懒于安装fabric ...
- 让PHPCms内容页支持JavaScript_
在PHPCms内容页中,出于完全考虑,默认是禁止JavaScript脚本的,所以我们在添加文章时,虽然加入了js代码,但实际上并没有起作用,而是以文本形式显示.如果要让内容页支持JavaScript, ...
- Uva 11549 - Calculator Conundrum 找规律加map
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...