大数据HBase学习之旅第五篇

251 阅读6分钟

「这是我参与11月更文挑战的第36天,活动详情查看:2021最后一次更文挑战」。

一、HBase 实战

1.1、需求分析

  1. 微博内容的浏览,数据库表设计

  2. 用户社交体现:关注用户,取关用户

  3. 拉取关注的人的微博内容

1.2、代码实现

1.2.1、代码设计总览

  1. 创建命名空间以及表名的定义

  2. 创建微博内容表(发布微博)

  3. 创建用户关系表(关注用户)

  4. 取关用户

  5. 获取关注的人的微博内容(前几条:inbox version)

  6. 获取微博详情

  7. 测试

1.2.2、创建命名空间以及表名的定义

public class Constants {

    // HBase 配置信息
    public static final Configuration CONFIGURATION = HBaseConfiguration.create();

    // 命名空间
    public static final String NAMESPACE = "weibo";
    public static final String SYMBOL = ":";

    // 微博内容表
    public static final String CONTENT_TABLE = NAMESPACE + SYMBOL + "content";
    public static final String CONTENT_TABLE_CF = "info";
    public static final int CONTENT_TABLE_VERSIONS = 1;

    // 用关系表表
    public static final String RELATION_TABLE = NAMESPACE + SYMBOL + "relation";
    public static final String RELATION_TABLE_CF1 = "attends";
    public static final String RELATION_TABLE_CF2 = "fans ";
    public static final int RELATION_TABLE_VERSIONS = 1;

    // 收件箱表
    public static final String INBOX_TABLE = NAMESPACE + SYMBOL + "inbox";
    public static final String INBOX_TABLE_CF = "info";
    public static final int INBOX_TABLE_VERSIONS = 2;

}
// 创建命名空间
public static void createNamespace(String namespace) throws Exception {
    //1.获取Connection对象
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
    //2.获取Admin对象
    Admin admin = connection.getAdmin();
    //3.构建命名空间描述器
    NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(namespace).build();
    //4.创建命名空间
    admin.createNamespace(namespaceDescriptor);
    //5.关闭资源
    admin.close();
    connection.close();
}

1.2.3、发布微博

方法名publishWeiBo
Table Nameweibo:content
RowKey用户ID_时间戳
ColumnFamilyinfo
ColumnLabel内容
Version1个版本
  • 微博内容表中添加 1 条数据
  • 微博收件箱表对所有粉丝用户添加数据
// 发布微博
public static void publishWeiBo(String uid, String content) throws Exception {
    // 获取连接
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);

    // 第一部分:操作微博内容表
    // 1.获取微博表对象
    Table contentTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
    // 2.获取当前时间戳
    long ts = System.currentTimeMillis();
    // 3.获取RowKey
    String rowKey = uid + "_" + ts;
    // 4.创建Put对象
    Put contentPut = new Put(Bytes.toBytes(rowKey));
    // 5.给Put对象赋值
    contentPut.addColumn(Bytes.toBytes(Constants.CONTENT_TABLE_CF), Bytes.toBytes("content"), Bytes.toBytes(content));
    // 6.执行插入数据操作
    contentTable.put(contentPut);

    // 第二部分:操作收件箱表
    // 1.获取用户关系表对象
    Table relationTable = connection.getTable(TableName.valueOf(Constants.RELATION_TABLE));
    // 2.获取当前发布微博人的fans列族数据
    Get get = new Get(Bytes.toBytes(uid));
    get.addFamily(Bytes.toBytes(Constants.RELATION_TABLE_CF2));
    Result result = relationTable.get(get);
    // 3.创建一个集合,用于存放微博内容表的Put对象
    List<Put> inboxPutList = new ArrayList<>();
    // 4.遍历粉丝
    for (Cell cell : result.rawCells()) {
        // 5.构建微博收件箱表的Put对象
        Put inboxPut = new Put(CellUtil.cloneQualifier(cell));
        // 6.给收件箱表的Put对象赋值
        inboxPut.addColumn(Bytes.toBytes(Constants.INBOX_TABLE_CF), Bytes.toBytes(uid), Bytes.toBytes(rowKey));
        // 7.将收件箱表的Put对象存入集合
        inboxPutList.add(inboxPut);
    }
    // 8.判断是否有粉丝
    if (inboxPutList.size() > 0) {
        // 获取收件箱表对象
        Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
        // 执行收件箱表数据插入操作
        inboxTable.put(inboxPutList);
        // 关闭收件箱表
        inboxTable.close();
    }

    // 关闭资源
    relationTable.close();
    contentTable.close();
    connection.close();
}

1.2.4、关注用户

方法名addAttends
Table Nameweibo:relation
RowKey用户ID
ColumnFamilyattends、fans
ColumnLabel关注用户ID、粉丝用户ID
Version1个版本
  • 在微博用户关系表中,对当前主动操作的用户添加新关注的好友
  • 在微博用户关系表中,对被关注的用户添加新的粉丝
  • 微博收件箱表中添加所关注的用户发布的微博
// 关注用户
public static void addAttends(String uid, String... attends) throws Exception {
    if (attends.length <= 0) {
        System.out.println("请选择要关注的人!!!");
        return;
    }
    // 获取连接
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);

    // 第一部分:操作用户关系表
    // 1.获取用户关系表对象
    Table relationTable = connection.getTable(TableName.valueOf(Constants.RELATION_TABLE));
    // 2.创建一个集合,用于存放用户关系表的Put对象
    List<Put> relationPuts = new ArrayList<>();
    // 3.创建操作者的Put对象
    Put uidPut = new Put(Bytes.toBytes(uid));
    // 4.循环创建被关注者的Put对象
    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.将被关注者的Put对象放入集合
        relationPuts.add(attendPut);
    }
    // 9.将操作者的Put对象添加至集合
    relationPuts.add(uidPut);
    // 10.执行用户关系表的插入数据操作
    relationTable.put(relationPuts);

    // 第二部分:操作用户收件箱表
    // 1.获取微博内容表对象
    Table contentTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
    // 2.创建收件箱表的Put对象
    Put inboxPut = new Put(Bytes.toBytes(uid));
    // 3.循环attends,获取每个被关注者的近期发布的微博
    for (String attend : attends) {
        // 4.获取当前被关注者的近期发布的微博(scan)-> 集合ResultScan
        Scan scan = new Scan().withStartRow(Bytes.toBytes(attend + "_")).withStopRow(Bytes.toBytes(attend + "|"));
        ResultScanner resultScanner = contentTable.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();
    }

    // 关闭资源
    contentTable.close();
    relationTable.close();
    connection.close();
}

1.2.5、移除(取关)用户

方法名addAttends
Table Nameweibo:relation
RowKey用户ID
ColumnFamilyattends、fans
ColumnLabel关注用户ID、粉丝用户ID
Version1个版本
  • 在微博用户关系表中,对当前主动操作的用户移除取关的好友(attends)
  • 在微博用户关系表中,对被取关的用户移除粉丝
  • 微博收件箱中删除取关的用户发布的微博
// 取关用户
public static void deleteAttends(String uid, String... attends) throws Exception {
    if (attends.length <= 0) {
        System.out.println("请选择要取关的人!!!");
        return;
    }
    // 获取连接
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);

    // 第一部分:操作用户关系表
    Table relationTable = connection.getTable(TableName.valueOf(Constants.RELATION_TABLE));
    // 2.创建一个集合,用于存放用户关系表的Delete对象
    List<Delete> relDelList = new ArrayList<>();
    // 3.创建操作者的Delete对象
    Delete uidDel = new Delete(Bytes.toBytes(uid));
    // 4.循环创建被取关者的Delete对象
    for (String attend : attends) {
        // 5.给操作者的Delete对象赋值
        uidDel.addColumns(Bytes.toBytes(Constants.RELATION_TABLE_CF1), Bytes.toBytes(attend));
        // 6.创建被取关者的Delete对象
        Delete attDel = new Delete(Bytes.toBytes(attend));
        // 7.给被取关着的Delete对象赋值
        attDel.addColumns(Bytes.toBytes(Constants.RELATION_TABLE_CF2), Bytes.toBytes(uid));
        // 8.将被取关着的Delete对象添加至集合
        relDelList.add(attDel);
    }
    // 9.将操作者的Delete对象添加至集合
    relDelList.add(uidDel);
    // 10.执行用户关系表的删除操作
    relationTable.delete(relDelList);

    // 第二部分:操作用户收件箱表
    // 1.获取收件箱表对象
    Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
    // 2.创建操作者的Delete对象
    Delete inboxDel = new Delete(Bytes.toBytes(uid));
    // 3.给操作者的Delete对象赋值
    for (String attend : attends) {
        inboxDel.addColumns(Bytes.toBytes(Constants.INBOX_TABLE_CF), Bytes.toBytes(attend));
    }
    // 4.执行收件箱表的删除操作
    inboxTable.delete(inboxDel);

    // 关闭资源
    inboxTable.close();
    relationTable.close();
    connection.close();
}

1.2.6、获取关注的人的微博内容(前几条:inbox version)

  • 从微博收件箱中获取所关注的用户的微博 RowKey
  • 根据获取的 RowKey,得到微博内容
// 获取用户的初始化页面(用户登录进入主页面,显示所关注的人的微博内容)
public static void getInit(String uid) throws Exception {
    // 1.获取连接
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
    // 2.获取收件箱表对象
    Table inboxTable = connection.getTable(TableName.valueOf(Constants.INBOX_TABLE));
    // 3.获取微博内容表对象
    Table contentTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
    // 4.创建收件箱表Get对象,并获取数据(设置最大版本)
    Get inboxGet = new Get(Bytes.toBytes(uid));
    inboxGet.readAllVersions();
    Result result = inboxTable.get(inboxGet);
    // 5.遍历获取的数据
    for (Cell cell : result.rawCells()) {
        // 6.构建微博内容表Get对象
        Get contentGet = new Get(CellUtil.cloneValue(cell));
        // 7.获取该Get对象的数据内容
        Result contentResult = contentTable.get(contentGet);
        // 8.解析内容并打印
        for (Cell contentCell : contentResult.rawCells()) {
            System.out.printf("RK:{%s}\tCF:{%s}\tCN:{%s}\tCV:{%s}",
                    Bytes.toString(CellUtil.cloneRow(contentCell)),
                    Bytes.toString(CellUtil.cloneFamily(contentCell)),
                    Bytes.toString(CellUtil.cloneQualifier(contentCell)),
                    Bytes.toString(CellUtil.cloneValue(contentCell)));
            System.out.println();
        }
    }
    // 9.关闭资源
    contentTable.close();
    inboxTable.close();
    connection.close();
}

1.2.7、获取微博详情

// 获取用户微博详情(点击进入某个人的微博详情)
public static void getWeiBoDetail(String uid) throws Exception {
    // 1.获取连接
    Connection connection = ConnectionFactory.createConnection(Constants.CONFIGURATION);
    // 2.获取微博内容表对象
    Table contentTable = connection.getTable(TableName.valueOf(Constants.CONTENT_TABLE));
    // 3.构建Scan对象
    Scan scan = new Scan();
    // 3.1构建过滤器
    RowFilter rowFilter = new RowFilter(CompareOperator.EQUAL, new SubstringComparator(uid + "_"));
    scan.setFilter(rowFilter);
    // 4.获取数据
    ResultScanner resultScanner = contentTable.getScanner(scan);
    // 5.解析数据并打印
    for (Result result : resultScanner) {
        for (Cell cell : result.rawCells()) {
            System.out.printf("RK:{%s}\tCF:{%s}\tCN:{%s}\tCV:{%s}",
                    Bytes.toString(CellUtil.cloneRow(cell)),
                    Bytes.toString(CellUtil.cloneFamily(cell)),
                    Bytes.toString(CellUtil.cloneQualifier(cell)),
                    Bytes.toString(CellUtil.cloneValue(cell)));
            System.out.println();
        }
    }
    // 6.关闭资源
    contentTable.close();
    connection.close();
}

1.2.8、测试

public static void test() throws Exception {
    // 1001发布微博
    HBaseDao.publishWeiBo("1001", "赶紧下课吧!!!");
    // 1002关注1001和1003
    HBaseDao.addAttends("1002", "1001", "1003");
    // 获取1002初始化页面
    HBaseDao.getInit("1002");

    System.out.println("===================111===================");

    // 1003发布3条微博,同时1001发布2条微博
    HBaseDao.publishWeiBo("1003", "谁说的赶紧下课!!!");
    Thread.sleep(10);
    HBaseDao.publishWeiBo("1001", "我没说话!!!");
    Thread.sleep(10);
    HBaseDao.publishWeiBo("1003", "那谁说的!!!");
    Thread.sleep(10);
    HBaseDao.publishWeiBo("1001", "反正飞机是下线了!!!");
    Thread.sleep(10);
    HBaseDao.publishWeiBo("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.getWeiBoDetail("1001");
}

image.png

二、友情链接

大数据HBase学习之旅第四篇

大数据HBase学习之旅第三篇

大数据HBase学习之旅第二篇

大数据HBase学习之旅第一篇