分布式存储学习——HBase表结构设计

news2025/3/16 0:20:56

目录

1.4.1  模式创建

1.4.2  Rowkey设计

1.4.3  列族定义

1.4.3.1  可配置的数据块大小

1.4.3.2  数据块缓存

1.4.3.3  布隆过滤器

1.4.3.4  数据压缩

1.4.3.5  单元时间版本

1.4.3.6  生存时间

1.4.4  模式设计实例

1.4.4.1  实例1:动物分类

1.4.4.2  实例2:店铺与商品

1.4.4.3  实例3:网上商城用户消费记录

1.4.4.4  实例4:微博用户与粉丝

1.4.4.5  小结


 本文参考于学校《HBase应用于开发》教材

前言

        本节将介绍如何设计HBase的模式(Schema),将对比HBase与RDBMS的模式设计的异同,重点介绍模式设计中的两个要点——Rowkey和Column Family,并结合4个实例介绍如何进行HBase的模式设计。

        数据库的模式设计并不是一个新概念,在关系型数据库之前,模式设计的范式已经存在。其实,只要是可以称为“数据库”的系统,都存在模式设计的问题。作为一种典型的列式存储数据库,HBase的模式设计同样非常重要。HBase的模式设计和传统数据库的模式设计存在什么样的差别,更需要关注的是哪些关键属性,如何设计这些属性,如何通过更直观、清晰地认识模式设计,这些都是本节讲解的要点。

1.4.1  模式创建

        要知道HBase的表如何创建,首先需要了解HBase的模式结构,包括表、Rowkey、列族、Timestamp(时间版本)。其实模式是一个三维有序结构,前面三个维度确定一行数据。

        HBase的模式不同于关系型数据库(RDBMS),HBase与RDBMS的区别在于:HBase的单元格(cell)所在的行是有序的,其列(Qualifier)在所属列族(Column Famliy)存在的情况下,可以通过客户端自由添加,如表 1.4.1所示。

表 1.4.1 HBase表设计模式与RDBMS对比

属性

HBase

RDBMS

数据类型

只有字符串

丰富的数据类型

数据操作

简单的增删改查,不支持Join

各种各样的函数与表连接

存储模式

基于列式存储

基于表格结构和列式存储

数据保护

更新后仍然保留旧版本

替换

可伸缩性

轻易地增加节点,兼容性高

需要中间层,牺牲功能

        通过HBase的模式与传统数据库系统对比,我们可以更清晰地了解HBase的结构:其实HBase和关系型数据库是不同的两种系统,它们拥有不同的设计特性。

在HBase模式设计过程中需要考虑不少因素,这些因素的列表如下:

1)这个表应该有多少个列族。

2)列族使用什么数据。

3)每个列族应该有多少列。

4)列名是什么,尽管列名不必在建表的时候定义,但是读写数据是需要知道的。

5)单元应该存放什么数据。

6)每个单元存储多少个时间版本。

7)行健(Rowkey)结构是什么,应该包含什么信息。

HBase模式的设计更需要注意两个关键点:

(1)  Join

        HBase中没有Join的概念,所以不支持Join操作,而在不少业务需求中,需要使用Join操作而大表结构可以解决这一问题,只需要一条行记录加上一个特定的行关键字,就可以实现把所有关于Join的数据合并在一起。

(2)  Rowkey

        Rowkey非常重要,在设计时需要慎重考虑。以存储用户观影记录数据为例,复合的Rowkey由用户ID作为前缀(方便把某用户的观影记录聚合在一起),倒置的时间串作为Rowkey的后缀可以使观影记录数据从新到旧排列。如果Rowkey是整型的,用二进制的方式应该比用string来存储一个数据更节约空间。

带着上面提到的若干问题,下面介绍如何设计HBase表结构。

1.4.2  Rowkey设计

        Rowkey是不可分割的字节数,按字典排序由低到高存储在表中。一个空的数组用来标识表空间的起始或结尾。

                在设计HBase表时,Rowkey设计是最重要的事情,应该基于预期的访问模式来为Rowkey建模。Rowkey决定了访问HBase表时可以得到的性能,原因有两个:Region基于Rowkey为一个区间的行提供服务,并且负责区间的每一行;HFile在硬盘上存储有序的行。这两个因素是相互关联的。当Region将内存中数据刷写为HFile时,这些行已经排过序,也会有序地写到硬盘上。Rowkey的有序特性和底层存储格式可以保证HBase表在设计Rowkey之后的良好性能。

关系型数据库可以在多列上建立索引,但是HBase只能在Rowkey上建立索引。访问数据库的最主要方法就是使用Rowkey。非Rowkey访问,即在不清楚Rowkey前提下访问表,可以使用扫描全表。设计Rowkey有各种技巧,而且可以针对不同访问模式进行优化,我们接下来就研究一下。

        Rowkey是HBase的KeyValue存储中的Key,通常将用户要查询的字段作为Rowkey,查询结果作为Value下面介绍Rowkey设计需要的注意要点。在进行Rowkey设计时用户需要根据不同的需求有针对性地选择或优化这几点。

1.   Rowkey是以字典顺序从大到小排序

        原生HBase只支持从小到大的排序,但是现在有个需求想展现影片热度排行榜,这就要求实现从大到小排列,针对这种情况可以采用Rowkey=Integer.MAX_VALUE-Rowkey的方式将Rowkey进行转换,最大的变最小,最小的变最大,在应用层再转回来即可完成排序需求。

2.   RowKey尽量保证散列设计

        保证散列设计可以确保所有的数据都不是在一个Region上,从而避免读写的时候负载会集中在个别Region上。

        假设我们需要存储一个视频网站用户的所有观影记录(暂时不需要考虑时间倒排),这时候的Rowkey可设计为userid_videoid的拼接字符串,但是这样设计的话,userid的分布就很可能不均匀,因为Rowkey是按字符串排序的(默认字典顺序排序)。有三种办法来解决这个问题,具体如下:

  • Ø  反转userid,将userid字符串反转后存储;
  • Ø  散列userid,即对userid进行散列;
  • Ø  userid取模后进行MD5加密,取前6位作为前缀加入到userid前面。

        假设某视频网站的用户正在观看视顿,但此时,要开辟一个新栏目,所有的用户观影记录都按照时间倒排序展示在这个栏目中。这个时候,就需要为原来的userid_videoid建立一张索引表,并且这个表的Rowkey要和时间相关。

        Rowkey设计可以使用当前时间(观影时间)的Long值作为Rowkey的前缀、另外建议Rowkey最好都是String:一是方便线上使用shell查数据、排查错误;二是更容易让数据均匀分布;三是不必考虑存储成本。

3.   RowKey的长度尽量短

        如果Rowkey太长,第一存储开销会增加,影响存储效率;第二内存中Rowkey字段过长,会导致内存的利用率降低.进而降低索引命中率:

一般的做法是:

  • Ø  时间使用Long来表示。
  • Ø  尽量使用编码压缩。
1.4.3  列族定义

        列族(column Family)是一些列的集合。一个列族的所有列成员有着相同的前缀。比如,列courses:history和courses:math都是列族courses的成员:冒号(:)是列族的分隔符,来区分前缀和列名。列族前缀必须是可输出的字符,剩下的部分称为列(Qualifier),可以由任意字节数组组成一列族必须在表建立的时候声明:列则不需要特别声明,用户随时可以创建新列。

        在物理上,一个列族的成员在文件系统上都存储在一起,因为存储优化都是针对列族级别的,这就意味着,访问一个列族的所有成员的方式都是相同的。

        现在HBase并不能很好地处理两个或者三个以上的列族,所以应尽量减少列族数量。目前,flush和compaction操作是针对一个Region的,所以当一个列族操作大量数据的时候会引发一个flush那些不相关的列族也要进行nush操作,尽管它们没有操作多少数据。compaction操作现在是根据一个列族下全部文件的数量触发的,而不是根据文件大小触发的。当很多的列族在进行flush和compaction时,会造成很多没用的I/O负载,要解决这个问题,需要将flush和compaction操作只针对一个列族进行。

        尽量在应用中使用一个列族。如果所有查询操作只访问一个列族,可以引入第二个和第三个列族。基于flush性能的考虑,列族数量越少越好。

        如果一个表存在多个列族,当基数差距很大时,例如,A族有100万行,B族有10亿行,A族可能会被分散到很多Region,导致扫描A的效率降低多个列族在执行flush和compaction时,会造成很多I/O负载。

        下面是列族相关的配置属性,这此属性都有默认值,如果在创建表的时候不显式指定,则使用默认值。

 

1.4.3.1  可配置的数据块大小

        HFile数据块大小可以在列族层次设置。这个数据块不同于之前谈到的HDFS数据块,其默认位是65536字节,或64KB。数据块是索引存储的,每个HFile数据块的起始键数据块大小的设置影响数据块索引的大小。数据块越小,索引越大,从而占用更大内存空间。同时载进内存的数据块越小,随机查找性能更好。但是,如果需要更好的序列扫描性能,那么一次能够加载更多HFile数据进入内存更为合理,这意味着应该将数据块设置为更大的值。相应地,索引变小,将在随机读性能上付出更多的代价。

可以在表实例化时设置数据块大小,代码如下:

Hbase(main):002> create ‘mytable’

{NAME => ‘colfam1’, BLOCKSIZE => ‘65536’}

1.4.3.2  数据块缓存

        把数据放进读缓存,并不是一定能够提升性能。如果一个表或表的列族只被顺序化扫描访问或很少被访问,则Get或Scan操作花费时间长一点是可以接受的。在这种情况下,可以选择关闭列族的缓存。如果只是执行很多顺序化扫描,会多次使用缓存,并且可能会滥用缓存,从而把应该放进缓存获得性能提升的数据给排挤出去。如果关闭缓存,不仅可以避免上述情况发生,而且可以让出更多缓存给其他表和同一表的其他列族使用。

        数据块缓存默认是打开的。可以在新建表或更改表时关闭数据块缓存属性:

Hbase(main):002:0>create ‘mytable’, { NAME =>  ‘colfam1’, BLOCKCACHE => ‘false’ }

        IN_MEMORY参数的默认值是false,该值表示HBase除了在数据块缓存中保存这个列族,相比其他列族更激进之外,并不提供其他额外的保证。该参数在实际应用中设置为true。此时访问性能不会变化太大。下面代码展示如何设置lN_MEMORY属性:

Hbase(main):002:0>create ‘mytable’, { NAME =>  ‘colfam1’, IN_MEMORY => ‘true’ }

1.4.3.3  布隆过滤器

        数据块索引提供了一个有效的方法getDataBlocklndexReader(),在访问某个特定的行时用来查找应该读取的HFile的数据块。但是该方法的作用有限。HFile数据块的默认大小是64KB,一般情况下不能调整太多。

        如果要查找一个很短的行,只在整个数据块的起始行键上建立索引是无法给出更细粒度的索引信息的。例如,某行占用100字节存储空间,一个64KB的数据块包含(64*1024)/100=655.53,约700行,只能把起始行放在索引位上。要查找的行可能落在特定数据块上的行区问,但也不能肯定存放在那个数据块上,这就导致多种可能性:该行在表中不存在,或者存放在另一个HFile中,甚至在MemStore中。这些情况下,从硬盘读取数据块会带来I/O开销,也会滥用数据块缓存,这会影响性能,尤其是当面对一个巨大的数据集且有很多并发读用户时。

        布隆过滤器(Bloom Filter)允许对存储在每个数据块的数据做一个反向测验。当查询某行时,先检查布隆过滤器,看看该行是否存在这个数据块。布隆过滤器要么确定回答该行不在,要么回答不知道,因此称之为反向测验。布降过滤器也可以应用到行内的单元格上,当访问某列标识符时先使用同样的反向测验。

        使用布降过滤器也不是没有代价,相反,存储这个额外的索引层次占用额外的空间。布隆过滤器的占用空间大小随着它们的索引对象数据增长而增长,所以行级布隆过滤器比列标识符级布隆过滤器占用空间要少。当空间不是问题时,它们可以压榨整个系统的性能潜力。

可以在列族上打开布隆过滤器,代码如下:

HBase(main):007:0>create ‘mytable’, { NAME =>  ‘colfam1’, BLOOMFILTER => ‘ROWCOL’ }

        注意,数据只在硬盘上是压缩的,在内存中(MemStore或BlockCache)或在网络传输时是没有压缩的,不能经常改变数据的压缩编码,但是如果的确需要改变某个列族的压缩编码,也可以直接更改表定义,设定新的压缩编码。此后Region合并时,生成的HFile全部会采用新编码压缩。这个过程不需要创建新表和复制数据。

1.4.3.4  数据压缩

        HFile可以被压缩并存放在HDFS上,这有助于节省硬盘I/O,但是读写数据时压缩和解压缩会提高CPU利用率。压缩是表定义的一部分,可以在建表或模式改变时设定。除非确定压缩不会提升系统的性能,否则推荐打开表的压缩。只有在数据不能被压缩,或者因为某些原因服务器的CPU利用率有限制要求的情况下,有可能需要关闭压缩特性。

        HBase可以使用多种压缩编码,包括LZO、SNAPPY和GZIP,LZO和SNAPPY是其中最流行的两种。SNAPPY由Google在2011年发布,发布不久Hadoop和HBase项目开始对其提供支持。在此之前,选择的是LZO编码。Hadoop使用的LZO原生库受GPLv2版权控制,不能放在Hadoop和HBase的任何发行版中,必须在它们中单独安装;另外,SNAPPY拥有BSD许可(BSD-licensed),所以它更容易和Hadoop及Haase发行版捆绑在一起。LZO和SNAPPY的压缩比例和压缩/解压缩速度差不多。

        当建表时可以在列族上打开压缩,代码如下:

  Hbase(main):002:0> create ‘mytable',{ NAME => ‘colfaml1’, COMPRESSION =>'SNAPPY’ }

        注意,数据只在硬盘上是压缩的,在内存中(MemStore或BlockCache)或在网络传输时是没有压缩的。

        不能经常改变数据的压缩编码,但是如果的确需要改变某个列族的压缩编码,也可以直接更改表定义,设定新的压缩编码。此后Region合并时,生成的HFile全部会采用新编码压缩。这个过程不需要创建新表和复制数据。

1.4.3.5  单元时间版本

        在默认情况下,HBase的每个单元格只维护三个时间版本。该属性也是可以设置的。如果只需要一个版本,在创建表时可以直接将VERSIONS参数设置为1,这样系统就不会保留更新单元的多个时间版本。时间版本也是在列族级设置的,代码如下:

Hbase(main):002:0> create ‘mytable’, { NAME => ‘colfam1’, VERSIONS => 1 }

可以在同一个建表语句里为列族指定多个属性,代码如下:

Hbase(main):002:0> create ‘mytable’, { NAME => ‘colfam1’, VERSIONS => 1, TTL => ‘18000’ }

也可以指定列族存储的最少时间版本数,代码如下:

Hbase(main):002:0> create ‘mytable’, { NAME => ‘colfam1’, VERSIONS => 5, MIN_VERSIONS => ‘1’ }

        在列族上同时设定TTL也是非常有用的。如果当前存储的所有时间版本都早于TTL,至少MIN_VERSION个最新版本会保留下来,这样可以确保在杳询以及数据早于TTL时有结果返回。

1.4.3.6  生存时间

        生存时间(Time To Live,TTL),用于设置单元格的生存周期。如果单元格过期,则会将其删除。应用系统经常需要从数据库中删除旧数据,因为数据库很难超过某种规模。传统数据库中内置了许多灵活的处理方法。例如,在一个视频网站用户的观影系统中,不想删除用户所有观影记录。这些都是用户生成的数据,将来某一天执行一些深度挖掘分析时可能有用,但是不需要保持所有观影记录都能实时访问,所以可以将早于某个时间的观影记录归档存放到平面文件中。

        早于指定TTL值的数据在下一次大合并时会被删除。如果在同一单元格中有多个时间版本,早于设定TTL值的版本会被删除。可以禁用TTL,或者通过设置其位为INT.MAX_VALUE(2147483647)让它永远启用,这也是默认值,单位是秒。可以在建表时设置TTL,代码如下:

Hbase(main):002:0> create ‘thetable’, {NAME => ‘cf1’, TTL => ‘18000’ }

该命令在列族cf1上设置TTL为18000s,即5小时。cf1中超过5小时的数据会在下一次大合并时被删除。

1.4.4  模式设计实例

        在设计教据库表的时候,考虑设计要满足功能需求是最基本的工作。下面将通过4个实例讲解如何进行HBase表结构设计。主要通过数据和功能需求两方面来对比传统关系型教据库与HBase表结构设计的异同。

1.4.4.1  实例1:动物分类

1.  数据需求

        如果一位生物科学家要存储一些动物相关信息,其中要包括动物的大类,以从一些大类动物下包括的小类,这样可以方便今后查询某种具体动物属于哪一类别,以及动物名字具体是什么。下面简单列举一些动物分类如下:

  • Ø  Animal
  • Ø  Pig
  • Ø  Cat
  • Ø  Monkey
  • Ø  Dog: Red dog和Black dog
  • Ø  Tiger: Tiger of northeast

        其中,Animal是顶级分类,Pig、Cat、Monkey、Dog和Tiger属于一级分类,而Dog中的Red dog和Black dog,以及Tiger中的Tiger of northesst属于二级分类。

2.  RDBMS表结构设计

        动物分类在关系型数据库的设计中只需要考虑主键的映射关系即可,需要一个分类表结构。每种动物都有几个关键字段:id、name、parent_id和child_id,如表 1.4.2所示。

表 1.4.2 RDBMS中的动物分类表结构

id PK

name

parent_id

child_id

1

animal

 

2,3,4,5

2

pig

1

 

3

cat

1

 

4

monkey

1

 

5

dog

1

7,8

6

red-dog

1.5

 

7

black-dog

1.5

 

8

tiger

1

9

9

tiger-of-northeast

1.8

 

        对于动物分类的HBase表结构设计,Rowkey对应RDBMS中的id,共有三个列族:name、parent、和child,详细设计如表 1.4.3所示。

表 1.4.3 HBase中的动物分类表结构

Rowkey

Column Famlily

<id>

name

parent

child

 

 

parent:<id>

child:<id>

1

animal

 

child:2=cat

child:3=monkey

child:4=dog

child:5=tiger

child:6=pig

 

 

 

 

4

dog

parent:1=animal

child:7=reddog

child:8=blackdog

7

reddog

perent:1=animal

parent:4=dog

 

        通过这个简单的例子可以行出,这两种表结构设计有本质的区别,一个是行式存储,一个是列式存储,所以刚刚接触HBase的读者需要转换思维设计表结构,这样才能够更好地掌握HBase的表模式设计。

1.4.4.2  实例2:店铺与商品

        电商行业中店铺和商品都是最基本的概念,本实例将描述这两者之间的关系。本实例是涉及多表关联关系的设计。

1.  数据需求

        某电商网站要存储在本网站的店铺属性信息,同时要知道这典店铺都卖了哪些商品,以及这些商品的详细信息。下面是店铺和商品之间关系的描述。

店铺表: Shop: Item=1:N

商品表:  Item:  Shop=1:N

其中,Shop是店铺,Item是商品。1:N表示一对多。

2.  RDBMS表结构设计

        关系型数据库中店铺表共包含三个字段:name、address和regdate,分别表示铺名称、所在地和注册日期,具体描述如表 1.4.4所示。

表 1.4.4 RDBMS中的店铺表结构

列名

列含义

id PK

主键

name

店铺名称

address

所在地

regdata

注册日期

        商品表共包含四个字段:name、price、details和title,分别表示商品名称、价格、商品详情和展示名称,具体描述如表 1.4.5所示。

表 1.4.5 RDBMS中的商品表结构

列名

列含义

id PK

主键

name

商品名称

price

价格

details

商品详情

title

展示名称

        店铺商品对应关系表是表示店铺和商品的映射关系表,共三个字段:shop_id、item_id和type,详细解释如表 1.4.6所示。

表 1.4.6 RDBMS中的店铺与商品对应关系表结构

列名

列含义

shop_id

店铺主键

item_id

商品主键

type

关联类型

3.  HBase表结构设计

        店铺表主键是RDBMS中的店铺表的id,共有两个列族:info和item,info表示店铺的静态属性,item表示店铺与商品的关联关系,如表 1.4.7所示。

表 1.4.7 HBase中的店铺表结构

Rowkey

Column Famlily

<shop_id>

info

item

info:name

info:address

info:regdate

item:<item_id>=type

        商品表主键是RDBMS中的商品表的id。共有两个列族:info和shop。info表示商品的静态属性,shop表示商品与店铺的关联关系,如表 1.4.8所示:

表 1.4.8 HBase中的商品表结构

Rowkey

Column Famlily

<shop_id>

info

shop

info:name

info:price

info:details

info:title

shop:<shop_id>=type

        通过对比我们可以看出,RDBMS表结构设计是通过三个表来实现的:一个表存储商品的详细信息,一个表存储店铺的详细信息,还有一个是店铺与商品的对应关系表。而HBase表结构设计是通过两个表实现的,每个表中都存储了店铺与商品的关联关系,并分别存储了商品与店铺的详细信息。如果想查询某个店铺所卖的商品的详细信息,RDBMS表要通过对商品详细信息和商品与店铺对应关系表进行Join来实现,而HBase表只需找到存储了商品的详细信息的表来查询即可。

1.4.4.3  实例3:网上商城用户消费记录

        现在网购已经成为潮流,用户在网上商城购买商品产生购买行为,网站一定会记录下用户的消费记录,本案例就是对网上商城的用户消费记录进行分析,提炼数据模型,并对比关系型数据库和HBase数据库的表结构设计的异同。

1.  数据需求

        某电商要存储用户购买商品的信息,并且想知道该用户最近一段时间都购买了哪些商品,从而分析该用户近期的消费状态,具体的查询需求如下:

用户购买的商品

查询用户最近购买的商品

2.  RDBMS表设计

        为了加速查询,需要对usr_id建立索引,但是建立索引的代价是索引的重建导致插入速度减慢。我们关系型数据库中用户消费记录表Sale,具体表述如表 1.4.9所示。

表 1.4.9 RDBMS中的Sale表结构

列名

列含义

Id PK

主键

user_id IDX

用户ID,创建索引

product

商品

time

购买时间

3.  HBase表结构设计

        在HBase中设计用户消费表Sale时,Rowkey的设计非常重要。本例使用<usr_id><Long.MAX_VALUE-System.currentTimeMillis()><product_id>作为Rowkey,该Rowkey共由三个部分组成:user_id,Long.MAX_VALUE-System.currentTimeMillis()和product_id,其中,Long.MAX_VALUE-System.currentTimeMillis()是为了使得用户的最近消费记录能够按照时间顺序排列。详细设计如表 1.4.10所示。

表 1.4.10 HBase中的Sale表结构

Rowkey

Column Family

<user_id> <Long.MAX_VALUE-System.currentTimeMillis()>

<product_id>

name

name:product

name:time

1.4.4.4  实例4:微博用户与粉丝

          很多人都在玩微博,相信大家都知道微博上用户和粉丝都是非常紧密的关系。本例将尝试提炼用户与粉丝关系的数据模型,并对比RDBMS和HBase设计表结构的异同。

1.  数据描述

        微博网站既要存储用户的详细信息,也要存储该用户所有的粉丝对应关系。用户粉丝的对应关系是一对多,即user:fans=1:N,user是用户,fans是粉丝,1:N表示一对多。基于这些数据关系,数据处理是可以查询用户的所有粉丝。

2.  RDBMS表结构设计

        RDBMS中的用户表共有5个字段:id、nickname、gender、dob和address,详细的字段说明如表 1.4.11所示。

表 1.4.11 RDBMS中的用户结构

列名

列含义

id

主键

nickname

用户昵称

gender

性别

dob

出生日期

address

所在地

用户对应表共有三个字段;user_id和fans_id和type,详细字段解释如表 1.4.12所示。

表 1.4.12 RDBMS中的用户粉丝对应表结构

列名

列含义

user_id

用户主键

fans_id

粉丝用户主键

type

互粉类型

3.  HBase表结构设计

        表 1.4.13是用户与粉丝关系表的HBase结构。其中,主键是RDBMS中的用户主键。列族有两个:info和fans。info表示用户的静态属性信息,fans表示该用户的粉丝关系的。因为粉丝也是微博用户,所以粉丝的id也是user_id,在fans列族中的粉丝id也使用user_id。

 

表 1.4.13 HBase中的用户与粉丝表结构

Rowkey

Column Family

<user_id>

info

fans

info:nickname

info:gender

info:dob

info:address

fans:<user_id>=type

        通过对比可以看出,RDBMS是使用两个表来设计实现的,一个表存储用户的详细信息,一个表存储用户与粉丝的对应关系。而HBase通过一个表存储用户的详细信息和粉丝对应关系。

1.4.4.5  小结

        我们带着一些问题开始了本章的学习,现在我们知道,HBase表如何设计是与需求直接相关的,如果想设计优秀的表结构,关键是先清理业务场景需求。当然HBase表结构设计有一些硬性指标,遵循这些指标对HBase性能的的提升有很大帮助。例如,Rowkey本身是按字典升序排列,每个表最好不超过三个列族等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2315715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue项目如何实现条件查询?

目录 1.前端 2.后端 3.mybatis的sql语句 结语 1.前端 说白了就是&#xff0c;无论该参数是否是空字符串&#xff0c;都会传递到后端。&#xff08;反正不是null就行&#xff09;。 2.后端 在controller层中&#xff0c;使用RequestParam注解接收名为registerName的参数&…

在Linux中安装Nginx

上传nginx安装包 Nginx的安装包&#xff0c;从官方下载下来的是c语言的源码包&#xff0c;我们需要自己编译安装。具体操作步骤如下&#xff1a; 安装nginx 安装nginx运行时需要的依赖 yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel 解压源码包到当…

【每日学点HarmonyOS Next知识】状态栏字体、生命周期、自定义对话框屏幕中间、透明度、tab居中

1、HarmonyOS 单页面如何控制状态栏字体颜色&#xff1f; 状态栏字体颜色可通过设置statusBarContentColor修改&#xff0c;参考文档如下&#xff1a; https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-window-V5 参考代码&#xff1a; import…

外贸企业可以申请网络专线吗?

在对外业务不断扩大的情况下&#xff0c;外贸企业对网络的需求愈发迫切。稳定、快速的网络连接不仅是企业开展国际业务的基础&#xff0c;更是提升竞争力的关键。外贸企业是否可以申请网络专线&#xff1f;如何选择适合的外贸网络专线服务&#xff1f;本文将为您详细解答。 网络…

阿里巴巴发布 R1-Omni:首个基于 RLVR 的全模态大语言模型,用于情感识别

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

QuickAPI 和 DBAPI 谁更香?SQL生成API工具的硬核对比(一)

最近低代码开发火得不行&#xff0c;尤其是能把数据库秒变API的工具&#xff0c;简直是开发者的救星。今天咱就聊聊两款国内玩家&#xff1a;QuickAPI&#xff08;麦聪软件搞出来的低代码神器&#xff09;和 DBAPI&#xff08;开源社区的硬核作品&#xff09;。这两货都能靠SQL…

Git使用(一)--如何在 Windows 上安装 Git:详细步骤指南

如果你想在 Windows 机器上安装 Git&#xff0c;可以按照以下详细指南进行操作。 第一步&#xff1a;下载 Git 可通过官网下载 适用于 Windows 的 Git 最新版本。 如果下载速度较慢&#xff0c;可以通过下面提供的百度网盘 链接下载安装包&#xff0c; https://git-scm.com/d…

C#-使用VisualStudio编译C#工程

一.创建csproj文件 二.创建源cs文件 三.生成解决方案 四.运行解决方案 五.VisualStudio功能列表 <1.代码格式化: CtrlKD完成代码整体格式化 <2.窗口布局 窗口->重置窗口布局 <3.引用查找&关联 <4.包管理 <5.日志输出级别 工具->选项->项目解决方案…

Qt常见面试题合集

零、基本概念 什么是信号槽? 信号槽类似于软件设计模式中的观察者模式&#xff0c;&#xff08;观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。&#xf…

vscode编译器的一些使用问题

目录 解决pip不可用问题 检查VSCode的终端配置 解决pip不可用问题 eg&#xff1a; C:\Users\student>pip pip 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 先找到系统环境变量 高级->环境变量 系统属性->Path 变量名随意&#xff0c;自己后续知道…

Docker 》》Docker Compose 》》network 网络 compose

docker 默认的网络 三种模式 # 列出所有当前主机上或Swarm集群上的网络 docker network ls#查看网络详情 docker network inspect network名称# 清除未使用的docker网络 docker network prune -f# 创建网络 ocker network create -d bridge 网络名称 docker network create –s…

【SpringMVC】深入解析使用 Postman 和浏览器模拟将单个与多个参数传递到后端的原理和后端接收参数的过程

SpringMVC—请求(Request) 访问不同的路径&#xff0c;就是发送不同的请求&#xff1b;在发送请求时&#xff0c;可能会带一些参数&#xff0c;所以学习Spring的请求&#xff0c;主要是学习如何传递参数到后端以及后端如何接收&#xff1b; 我们主要是使用 浏览器 和 Postman …

VSTO(C#)Excel开发10:启动和卸载顺序 事件处理 监视变化

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

vue 仿deepseek前端开发一个对话界面

后端&#xff1a;调用deepseek的api&#xff0c;所以返回数据格式和deepseek相同 {"model": "DeepSeek-R1-Distill-Qwen-1.5B", "choices": [{"index": 0, "delta": {"role": "assistant", "cont…

UE5以插件的形式加载第三方库

之前在UE中加载第三方库的形式是以静态或者动态链接的形式加载但是不太容易复用。就想着能不能以插件的形式加载第三方库&#xff0c;这样直接把插件打包发行就可以复用了&#xff0c;之前也找过相应的教程但是很难找到比较简单易懂的教程&#xff0c;要么是比较复杂&#xff0…

Vue3全局化配置(ConfigProvider)

效果如下图&#xff1a; 在线预览 APIs ConfigProvider 参数说明类型默认值theme主题对象Theme{}abstractboolean是否不存在 DOM 包裹元素truetagstringConfigProvider 被渲染成的元素&#xff0c;abstract 为 true 时有效‘div’ Theme Type 名称说明类型默认值common?全…

Centos7系统基于docker下载ollama部署Deepseek-r1(GPU版不踩坑)

目录 一、Docker下载安装 二、Ollama安装 三、部署Deepseek-R1 一、Docker下载安装 1、更新源 sudo yum update -y 2、下载依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 3、添加docker远程仓库地址 yum-config-manager --add-repo http://down…

【工具】C#游戏防沉迷小工具

背景介绍 嘿&#xff0c;各位小伙伴&#xff01;今天想跟大家唠唠我为啥要搞这么个防沉迷小工具。 咱都清楚&#xff0c;现在这游戏啊&#xff0c;玩起来那叫一个带劲&#xff0c;但时间一长&#xff0c;不仅眼睛累&#xff0c;心也跟着累。有些游戏&#xff0c;规则定得挺有意…

深圳南柯电子|净水器EMC测试整改:水质安全与电磁兼容性的双赢

在当今注重健康生活的时代&#xff0c;净水器作为家庭用水安全的第一道防线&#xff0c;其性能与安全性备受关注。其中&#xff0c;电磁兼容性&#xff08;EMC&#xff09;测试是净水器产品上市前不可或缺的一环&#xff0c;它直接关系到产品在复杂电磁环境中的稳定运行及不对其…

SpeechCraf论文学习

Abstract 核心问题 挑战 语音风格包含细微的多样化信息&#xff08;如情感、语调、节奏&#xff09;&#xff0c;传统基于标签/模板的标注方法难以充分捕捉&#xff0c;制约了语音-语言多模态模型的性能。 数据瓶颈&#xff1a; 大规模数据收集与高质量标注之间存在矛盾&…