在回答这个问题之前,我想指出关于 HBase 用例的一件事,它可以更容易地理解 HFile 布局。HBase(从读取工作负载的角度来看)针对非常长和宽的表(数万亿行和数百万列)中的随机键值查找进行了优化。它也适用于基于行键前缀的扫描,但它不是为大型单列扫描构建的。
也就是说,HBase 并不是一个真正的列式数据库,尤其是当也被视为一个宽列存储时。HBase 将同一行键和同一列族的所有列存储在一起。但是,不同的列族存储在不同的文件中,这使 HBase 具有列性质,因为您可以独立控制每个列族的配置,并且您可以扫描单个列族而不必担心由于其他族中的列而引入的读取成本. 这是单个HFile的样子(请注意,一列在 HBase中称为限定符。Type 也可以是Put或Delete):
RowKey1:Family1:Qualifier1:Timestamp1:Type:Value
RowKey1:Family1:Qualifier1:Timestamp2:Type:Value
RowKey1:Family1:Qualifier2:Timestamp0:Type:Value
RowKey1:Family1:Qualifier3:Timestamp2:Type:Value
RowKey2:Family1:Qualifier1:Timestamp0:Type:Value
RowKey2:Family1:Qualifier2:Timestamp2:Type:Value
请注意,Qualifier1与RowKey1和RowKey2不相邻。相反,同一行(即RowKey1键)的所有列都是相邻的。
如果您将每一列存储在其自己的列族中,HBase 将成为一个真正的列式存储,但由于其锁定提供的单行跨列 ACID 语义,它将无法为数百万列提供支持实施的策略。
编辑
给定上述 HFile 的结构,HFile 数据实际上是按照以下 key 排序的格式存储的(注意,一个文件只能有一个族,所以,将族名存储在数据本身中有些多余,但是有此问题范围之外的其他用途):
RowKey:Family:Qualifier:Timestamp:Type
这种排序顺序与 HFiles 上的块级索引和布隆过滤器相结合,使得 HBase 在定位任何随机RowKey或RowKey、Family:Qualifier元组或RowKey、Family:Qualifier、Timestamp元组方面非常迅速。