HBase微博实战案例

HBase微博实战案例

1 需求分析

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

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

  3. 拉取关注的人的微博内容
    HBase微博实战案例_第1张图片
    HBase微博实战案例_第2张图片
    HBase微博实战案例_第3张图片

2 代码实现

2.1 准备工作

  • 第一步:创建maven工程并导入jar包

    直接使用在版本确界当中创建的工程以及导入的jar包即可

  • 第二步:拷贝三个配置文件到maven工程的下

    将node01服务器的三个配置文件,分别是

    core-site.xml、hdfs-site.xml、hbase-site.xml三个配置文件,拷贝到maven工程的resources资源目录下

2.2 代码设计总览:

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

  2. 创建微博内容表

  3. 创建用户关系表

  4. 创建用户微博内容接收邮件表

  5. 发布微博内容

  6. 添加关注用户

  7. 移除(取关)用户

  8. 获取关注的人的微博内容

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

代码实现:

    //微博内容表
    private static final byte[] WEIBO_CONTENT = "weibo:content".getBytes();
    //用户关系表
    private static final byte[] WEIBO_RELATION = "weibo:relation".getBytes();
    //收件箱表
    private static final byte[] WEIBO_CRCEIVE_CONTENT_EMAIL = "weibo:receive_content_email".getBytes();
    //建命名空间
    public void createNameSpace() throws IOException {
        //获得连接
        Connection connection = getConnection();

        //生成Admin对象
        Admin admin = connection.getAdmin();

        //admin创建namespace
        NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create("weibo").addConfiguration("creator", "bruce").build();
        admin.createNamespace(namespaceDescriptor);

        //关闭连接
        admin.close();
        connection.close();
    }

    public Connection getConnection() throws IOException {
        Configuration configuration = HBaseConfiguration.create();
        configuration.set("hbase.zookeeper.quorum", "node01:2181,node02:2181,node03:2181");

        Connection connection = ConnectionFactory.createConnection(configuration);
        return connection;
    }

2.4 创建微博内容表

表结构:

方法名 creatTableeContent
Table Name weibo:content
RowKey 用户ID_时间戳
ColumnFamily info
ColumnLabel 标题,内容,图片
Version 1个版本

代码实现:

    public void createTableContent() throws IOException {
        //获得连接
        Connection connection = getConnection();

        //admin
        Admin admin = connection.getAdmin();

        //创建
        if(!admin.tableExists(TableName.valueOf(WEIBO_CONTENT))) {
            HTableDescriptor weibo_content = new HTableDescriptor(TableName.valueOf(WEIBO_CONTENT));

            HColumnDescriptor info = new HColumnDescriptor("info");
            //指定最小版本、最大版本
            info.setMinVersions(1);
            info.setMaxVersions(1);
            info.setBlockCacheEnabled(true);

            weibo_content.addFamily(info);

            admin.createTable(weibo_content);
        }

        //关闭连接
        admin.close();
        connection.close();
    }

2.5 创建用户关系表

表结构:

方法名 createTableRelations
Table Name weibo:relations
RowKey 用户ID
ColumnFamily attends、fans
ColumnLabel 关注用户ID,粉丝用户ID
ColumnValue 用户ID
Version 1个版本

代码实现:

    /**
     * 创建用户关系表
     *  * 方法名 createTableRelations
     *  Table Name    weibo:relations
     *  RowKey    用户ID
     *  ColumnFamily  attends、fans
     *  ColumnLabel   关注用户ID,粉丝用户ID
     *  ColumnValue   用户ID
     *  Version   1个版本
     */
    public void createTableRelation() throws IOException {
        Connection connection = getConnection();
        Admin admin = connection.getAdmin();

        if(!admin.tableExists(TableName.valueOf(WEIBO_RELATION))) {
            HTableDescriptor weibo_relation = new HTableDescriptor(TableName.valueOf(WEIBO_RELATION));
            //attends
            //minversion\max\...
            HColumnDescriptor attends = new HColumnDescriptor("attends");
            attends.setMinVersions(1);
            attends.setMaxVersions(1);
            attends.setBlockCacheEnabled(true);

            //fans
            //minversion\max\...
            HColumnDescriptor fans = new HColumnDescriptor("fans");
            fans.setMinVersions(1);
            fans.setMaxVersions(1);
            fans.setBlockCacheEnabled(true);

            weibo_relation.addFamily(attends);
            weibo_relation.addFamily(fans);
            admin.createTable(weibo_relation);

        }

        admin.close();
        connection.close();
    }

2.6 创建微博收件箱表

表结构:

方法名 createTableReceiveContentEmails
Table Name weibo:receive_content_email
RowKey 用户ID
ColumnFamily info
ColumnLabel 用户ID
ColumnValue 取微博内容的RowKey
Version 1000

代码实现:

    /**
     * 表结构:
     *  方法名   createTableReceiveContentEmails
     *  Table Name    weibo:receive_content_email
     *  RowKey    用户ID
     *  ColumnFamily  info
     *  ColumnLabel   用户ID
     *  ColumnValue   取微博内容的RowKey
     *  Version   1000
     */
    public void createTableReceiveContentEmails() throws IOException {
        //获得连接
        Connection connection = getConnection();

        //admin
        Admin admin = connection.getAdmin();

        //创建
        if(!admin.tableExists(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL))) {
            HTableDescriptor weibo_receive_content_email = new HTableDescriptor(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL));

            HColumnDescriptor info = new HColumnDescriptor("info");
            //指定最小版本、最大版本
            info.setMinVersions(1000);
            info.setMaxVersions(1000);
            info.setBlockCacheEnabled(true);

            weibo_receive_content_email.addFamily(info);

            admin.createTable(weibo_receive_content_email);
        }

        //关闭连接
        admin.close();
        connection.close();
    }

2.7 发布微博内容

a、微博内容表中添加1条数据

b、微博收件箱表对所有粉丝用户添加数据

代码实现:

    //发送微博
    /**
     *  第一步:将uid微博内容添加到content表
     *  content
     *  第二步:从relation表中,获得uid的粉丝有哪些fan_uids
     *  ralation
     *  第三步:fan_uids中,每个fan_uid插入数据;uid发送微博时的rowkey
     *  email
     */
    public void publishWeibo(String uid, String content) throws IOException {
        //第一步:将uid微博内容添加到content表
        Connection connection = getConnection();
        Table weibo_content = connection.getTable(TableName.valueOf(WEIBO_CONTENT));
        long timeStamp = System.currentTimeMillis();
        //put -> rowkey -> uid+timestamp
        String rowkey = uid + "_" + timeStamp;
        //put
        Put put = new Put(rowkey.getBytes());
        put.addColumn("info".getBytes(), "content".getBytes(), timeStamp, content.getBytes());
        //完成内容的添加
        weibo_content.put(put);

        //第二步:从relation表中,获得uid的粉丝有哪些fan_uids
        Table weibo_relation = connection.getTable(TableName.valueOf(WEIBO_RELATION));
        //get
        Get get = new Get(uid.getBytes());
        get.addFamily("fans".getBytes());

        Result result = weibo_relation.get(get);
        if(result.isEmpty()) {
            weibo_content.close();
            weibo_relation.close();
            connection.close();
            return;
        }
        Cell[] cells = result.rawCells();

        List<byte[]> fan_uids = new ArrayList<>();
        for(Cell cell: cells) {
            byte[] fan_uid = CellUtil.cloneQualifier(cell);
            fan_uids.add(fan_uid);
        }

        //第三步:fan_uids中,每个fan_uid插入数据;uid发送微博时的rowkey
        Table weibo_email = connection.getTable(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL));

        List<Put> putList = new ArrayList<>();
        for(byte[] fan_uid: fan_uids) {
            //put
            Put put1 = new Put(fan_uid);
            put1.addColumn("info".getBytes(), uid.getBytes(), timeStamp, rowkey.getBytes());
            putList.add(put1);
        }

        weibo_email.put(putList);

        //释放资源
        weibo_content.close();
        weibo_relation.close();
        weibo_email.close();
        connection.close();
    }

2.8 添加关注用户

a、在微博用户关系表中,对当前主动操作的用户添加新关注的好友

b、在微博用户关系表中,对被关注的用户添加新的粉丝

c、微博收件箱表中添加所关注的用户发布的微博

代码实现:

    /**
     * 添加关注用户,一次可能添加多个关注用户
     * A 关注一批用户 B,C ,D
     * 第一步:A是B,C,D的关注者   在weibo:relations 当中attend列族当中以A作为rowkey,B,C,D作为列名,B,C,D作为列值,保存起来
     * 第二步:B,C,D都会多一个粉丝A  在weibo:relations 当中fans列族当中分别以B,C,D作为rowkey,A作为列名,A作为列值,保存起来
     * 第三步:A需要获取B,C,D 的微博内容存放到 receive_content_email 表当中去,以A作为rowkey,B,C,D作为列名,获取B,C,D发布的微博rowkey,放到对应的列值里面去
     * @param uid 当前用户
     * @param attends 当前用户所关注的一些其他用户
     */
    public void addAttends(String uid, String... attends) throws IOException {
        //第一:把uid关注别人的逻辑,写到relation表的attend列族下
        Connection connection = getConnection();
        Table weibo_relation = connection.getTable(TableName.valueOf(WEIBO_RELATION));

        Put put = new Put(uid.getBytes());
        for(String attend: attends) {
            put.addColumn("attends".getBytes(),attend.getBytes(), attend.getBytes());
        }
        weibo_relation.put(put);

        //第二:要将attends有一个粉丝uid的逻辑,添加到relation表的fans列族下
        for(String attend: attends) {
            Put put1 = new Put(attend.getBytes());
            put1.addColumn("fans".getBytes(), uid.getBytes(), uid.getBytes());
            weibo_relation.put(put1);
        }

        //第三:去content表查询attends中,每个人发布微博时的rowkey
        Table weibo_content = connection.getTable(TableName.valueOf(WEIBO_CONTENT));
        Scan scan = new Scan();

        ArrayList<byte[]> rowkeyBytes = new ArrayList<>();

        for(String attend: attends) {
            //attend -> 被关注人的uid -> 2 ->
            PrefixFilter prefixFilter = new PrefixFilter((attend + "_").getBytes());
            scan.setFilter(prefixFilter);

            ResultScanner scanner = weibo_content.getScanner(scan);
            //如果当前被关注人没有发送过微博的话,跳过此次循环
            if(null == scanner) {
                continue;
            }

            for(Result result: scanner) {
                byte[] rowkeyWeiboContent = result.getRow();
                rowkeyBytes.add(rowkeyWeiboContent);
            }
        }

        Table weibo_email = connection.getTable(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL));
        if(rowkeyBytes.size() > 0) {
            //第四:要将uid关注的人attends发布的微博时的rowkey写入到email表

            Put put1 = new Put(uid.getBytes());

            for(byte[] rowkeyWeiboContent: rowkeyBytes) {
                //rowkeyWeiboContent -> 1_1758420156 uid_timestamp
                String rowkey = Bytes.toString(rowkeyWeiboContent);
                String[] split = rowkey.split("_");
                put1.addColumn("info".getBytes(),split[0].getBytes(),Long.parseLong(split[1]), rowkeyWeiboContent);
            }
            weibo_email.put(put1);

        }

        //释放资源
        weibo_content.close();
        weibo_relation.close();
        weibo_email.close();
        connection.close();
    }

2.9 移除(取关)用户

a、在微博用户关系表中,对当前主动操作的用户移除取关的好友(attends)

b、在微博用户关系表中,对被取关的用户移除粉丝

c、微博收件箱中删除取关的用户发布的微博

代码实现:

    /**
     * 取消关注 A取消关注 B,C,D这三个用户
     * 其实逻辑与关注B,C,D相反即可
     * 第一步:在weibo:relation关系表当中,在attends列族当中删除B,C,D这三个列
     * 第二步:在weibo:relation关系表当中,在fans列族当中,以B,C,D为rowkey,查找fans列族当中A这个粉丝,给删除掉
     * 第三步:A取消关注B,C,D,在收件箱中,删除取关的人的微博的rowkey
     */
    public void cancelAttends(String uid, String... attends) throws IOException {
        //relation:删除关注的人
        Connection connection = getConnection();
        Table weibo_relation = connection.getTable(TableName.valueOf(WEIBO_RELATION));

        Delete delete = new Delete(uid.getBytes());
        for(String cancelAttend: attends) {
            delete.addColumn("attends".getBytes(), cancelAttend.getBytes());
        }
        weibo_relation.delete(delete);

        //relation:删除attends的粉丝uid
        for(String cancelAttend: attends) {
            Delete delete1 = new Delete(cancelAttend.getBytes());
            delete1.addColumn("fans".getBytes(), uid.getBytes());
            weibo_relation.delete(delete1);
        }

        //email:删除uid中,attends相关的列
        Table weibo_email = connection.getTable(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL));
        Delete delete1 = new Delete(uid.getBytes());
        for(String attend: attends) {
            delete1.addColumns("info".getBytes(), attend.getBytes());
        }
        weibo_email.delete(delete1);

        //释放资源
        weibo_relation.close();
        weibo_email.close();
        connection.close();

    }

2.10 获取关注的人的微博内容

a、从微博收件箱中获取所关注的用户的微博RowKey

b、根据获取的RowKey,得到微博内容

代码实现:

    /**
     * 某个用户获取收件箱表内容
     * 例如A用户刷新微博,拉取他所有关注人的微博内容
     * A 从 weibo:receive_content_email  表当中获取所有关注人的rowkey
     * 通过rowkey从weibo:content表当中获取微博内容
     */
    public void getContent(String uid) throws IOException {
        //从email表获得uid行的所有的值-> 发送微博时的rowkey
        Connection connection = getConnection();
        Table weibo_email = connection.getTable(TableName.valueOf(WEIBO_CRCEIVE_CONTENT_EMAIL));

        Get get = new Get(uid.getBytes());
        get.setMaxVersions(5);

        Result result = weibo_email.get(get);
        Cell[] cells = result.rawCells();

        ArrayList<Get> gets = new ArrayList<>();

        for(Cell cell: cells) {
            byte[] bytes = CellUtil.cloneValue(cell);
            Get get1 = new Get(bytes);
            gets.add(get1);
        }

        //根据这些rowkey去content表获得微博内容
        Table weibo_content = connection.getTable(TableName.valueOf(WEIBO_CONTENT));
        Result[] results = weibo_content.get(gets);
        for(Result result1: results) {
            byte[] weiboContent = result1.getValue("info".getBytes(), "content".getBytes());
            System.out.println(Bytes.toString(weiboContent));
        }
    }

2.11 main入口

    public static void main(String[] args) throws IOException {
        HBaseWeibo hBaseWeibo = new HBaseWeibo();
        //建命名空间
//        hBaseWeibo.createNameSpace();
        //微博内容表
//        hBaseWeibo.createTableContent();
        //用户关系表
//        hBaseWeibo.createTableRelation();
        //收件箱表
//        hBaseWeibo.createTableReceiveContentEmails();
        //发送微博
//        hBaseWeibo.publishWeibo("2", "今天是HBase案例课的第二天");
        //关注别人
//        hBaseWeibo.addAttends("1", "2", "3", "M");
        //取消关注
//        hBaseWeibo.cancelAttends("1", "M");
        //获得所关注人发表的微博
        hBaseWeibo.getContent("1");
    }

你可能感兴趣的:(实战案例)