您现在的位置是:首页 >学无止境 >Hbase中表结构的设计网站首页学无止境

Hbase中表结构的设计

小刘同学要加油呀 2023-06-01 00:00:03
简介Hbase中表结构的设计

前言

在关系型数据库中,表与表之间的关系有多种,一对一,一对多以及多对多的关系,那在hbase中这种关系怎么设计呢?

  1. 一对一:一个订单对应一笔支付。
  2. 一对多:一笔订单对应多个多个商品。
  3. 多对多:一个用户对应多个角色,一个角色对应多个用户。
    关系型数据库中一般实现一对一,两个表之间之间关联,一对多一个主表和一个字表,多对多一般建立一个表来存两个表之间的关系。

1.Hbase表设计

1.1 RowKey的设计

Hbase中的row key是按照字母顺序排序的。这种设计方便Scan查询数据,进行相关行的读取与存储。 HBase中row key用来检索表中的记录,支持以下三种方式

  1. 通过单个row key访问:即按照某个row key键值进行get操作;

  2. 通过row key的range进行scan:即通过设置startRowKey和endRowKey,在这个范围内进行扫描;

  3. 全表扫描:即直接扫描整张表中所有行记录。

官方文档提供了三种设计方法

  1. 加盐
  2. hash
  3. 反转

1.2 列族

不要在一张表里定义太多的column family。目前Hbase并不能很好的处理超过2~3个column family的表。因为某个column family在flush的时候,它邻近的column family也会因关联效应被触发flush,最终导致系统产生更多的I/O。

1.3 时间差反转 Reverse Timestamps

在实际中经常需要找到最近的版本的值,使用时间戳反转技术(Long.MAX_VALUE - timestamp)能够很好的解决这个问题。[key][reverse_timestamp].

其他的设计根据需要在官网进行查阅。

2.表设计案例

需求:CSDN发博客表,关注列表和粉丝列表。

2.1 关注列表和粉丝列表

关注列表和粉丝列表是一个多对多的关系,博主可以有多个粉丝,也可以关注多个人。

博主关注列表粉丝列表
Blogger1Blogger3Blogger2,Blogger3
Blogger2Blogger3,Blogger4Blogger1
Blogger3Blogger1Blogger2,Blogger4
Blogger4Blogger5Blogger1,Blogger2,Blogger3

表设计
csdn为每一位博主分配一个ID

Rowkeycf1:关注列表cf2:粉丝列表
CSDN_1cf:CSDN_3=bobcf:CSDN_2=elite,cf:CSDN_3=bob
CSDN_2cf:CSDN_3=bobcf:CSDN_2=elite,cf:CSDN_3=bob
CSDN_3cf:CSDN_1=jaksoncf:CSDN_2=elite,cf:CSDN_4=Eric
CSDN_4cf:CSDN_5=tomcf:CSDN_1=jakson,cf:CSDN_2=elite,CSDN_3=bob

2.2 博客表

Hbase中Rowkey的是根据字母顺序进行排序的,需要倒序进行排序,需要用到时间戳反转来设计rowkey,最新发布的博客在前。

表设计

csdn为每一位博主分配一个ID,Rowkey的设计根据时间戳来设计。

Rowkeycf:博客信息
CSDNIID+Long.MAX_VALUE - timestamp1cf:title=‘大数据’,cf:content=‘大数据…’,cf:分栏=‘大数据.’
CSDNIID+Long.MAX_VALUE - timestamp2cf:title=‘Java’,cf:content=‘HashMap的原理…’,cf:分栏=‘java’
CSDNIID+Long.MAX_VALUE - timestamp3cf:title=‘python’,cf:content=‘大数据…’,cf:分栏=‘python’
CSDNIID+Long.MAX_VALUE - timestamp4cf:title=‘人工智能’,cf:content=‘AI应用…’,cf:分栏=‘AI’

在hbase shell中创建博客表

create 'blog','cf'

假设一年发表10000篇博客,使用hbase客户端插入。

 /**
     * 假设一个博主2022年发表10000篇博客
     * rowkey=博主ID_时间戳
     */
    @Test
    public void insertBlogData() throws Exception {
        List<Put> puts = new ArrayList<>();
        String bloggerId= "123";
        for(int j = 0 ;j<10000;j++){
            String title = "title_"+j;
            String content =  "content_"+j;
            String specaification = "bigdata_"+j;
            //rowkey
            String date = getDate("2022");
            String rowkey = bloggerId+"_"+(Long.MAX_VALUE-sdf.parse(date).getTime());
            Put put = new Put(Bytes.toBytes(rowkey));
            put.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("title"),Bytes.toBytes(title));
            put.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("content"),Bytes.toBytes(content));
            put.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("specaification"),Bytes.toBytes(specaification));
            puts.add(put);
        }
        table.put(puts);
    }

查询12月份发表的博客

 /**
     * 查询某近2022年12月发表的博客
     */
    @Test
    public void scanByCondition() throws Exception {
        Scan scan = new Scan();
        String startRow = "123_"+(Long.MAX_VALUE-sdf.parse("20221231235959").getTime());
        String stopRow = "123_"+(Long.MAX_VALUE-sdf.parse("20221201000000").getTime());
        scan.withStartRow(Bytes.toBytes(startRow));
        scan.withStopRow(Bytes.toBytes(stopRow));
        ResultScanner rss = table.getScanner(scan);
        for (Result rs:rss) {
            System.out.print(Bytes.toString(CellUtil.cloneValue(rs.getColumnLatestCell(Bytes.toBytes("cf"),Bytes.toBytes("title")))));
            System.out.print("--"+Bytes.toString(CellUtil.cloneValue(rs.getColumnLatestCell(Bytes.toBytes("cf"),Bytes.toBytes("content")))));
            System.out.println("--"+Bytes.toString(CellUtil.cloneValue(rs.getColumnLatestCell(Bytes.toBytes("cf"),Bytes.toBytes("specaification")))));
        }
    }
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。