HBase 模式定义 (Schema Definition)

在 HBase 中创建一个表包括表模式(table schema)的定义, 以及所包含的列族的模式(schemas for all contained column families). 它们定义了如何,
以及何时存储表和列的数据。在更高级别上,每个表是一个名称空间(namespace)的一部分。


1.1 名称空间 (Namespaces)
-----------------------------------------------------------------------------------------------------------------------------------------
名称空间在 HBase 0.96 版本引入,它的引入是为了解决 HBase 中组织多个表的问题。在这个特性引入之前,所有表构成一个扁平的列表,包括系统目录表
(system catalog tables). 这在扩展,特别是当有几百个表时非常难于管理。利用名称空间可以将多个表按组组织,使相关的表可以一起处理。除此之外,
名称空间可以更进一步抽象类属概念,例如安全性。可以在 namespace 级别定义访问控制,以在所有包含的表上快速应用规则。

HBase 在启动时创建两个 namespace: default 和 hbase. hbase 是为系统目录表使用的,用户不能在此名称空间内创建用户表。

使用 shell 可以列出 namespace 及其包含的内容:

    hbase(main):001:0> list_namespace
    NAMESPACE
    default
    hbase
    2 row(s) in 0.0090 seconds

    hbase(main):002:0> list_namespace_tables 'hbase'
    TABLE
    foobar
    meta
    namespace
    3 row(s) in 0.0120 seconds

所有未指定名称空间的表都放到 default 名称空间内。因此在创建表时不必一定指定一个名称空间,它会被加入到 default 名称空间内。

通过下面的 shell 操作看看发生的变化:

    hbase(main):001:0> list_namespace_tables 'default'
    TABLE
    0 row(s) in 0.0170 seconds

    hbase(main):002:0> create 'testtable', 'colfam1'
    0 row(s) in 0.1650 seconds
    => Hbase::Table - testtable

    hbase(main):003:0> list_namespace_tables 'default'
    TABLE
    testtable
    1 row(s) in 0.0130 seconds

新表(testtable) 被创建并加入到了 default 名称空间中。

因为 namespace 将表分组管理, namespace 名称成为一个表定义固定的一部分,因此可以在不同的 namespace 中可以随意创建具有相同名称的表。

    hbase(main):001:0> create_namespace 'booktest'
    0 row(s) in 0.0970 seconds
    
    hbase(main):002:0> create 'booktest:testtable', 'colfam1'
    0 row(s) in 0.1560 seconds
    => Hbase::Table - booktest:testtable
    
    hbase(main):003:0> create_namespace 'devtest'
    0 row(s) in 0.0140 seconds
    
    hbase(main):004:0> create 'devtest:testtable', 'colfam1'
    0 row(s) in 0.1490 seconds
    => Hbase::Table - devtest:testtable

在代码中处理名称空间,围绕着 NamespaceDescriptor 类,使用下面方法构建 Builder:

    static Builder create(String name)
    static Builder create(NamespaceDescriptor ns)

可以为新实例手动输入一个名称字符串,或者传入一个已存在的 NamespaceDescriptor 实例,方法会从该实例中复制配置信息创建新实例。返回的 Builder
实例可以更进一步添加配置信息到这个新名称空间,构成最终的实例。

示例: Example how to create a NamespaceDescriptor in code

    NamespaceDescriptor.Builder builder = NamespaceDescriptor.create("testspace");
    builder.addConfiguration("key1", "value1");
    NamespaceDescriptor desc = builder.build();
    System.out.println("Namespace: " + desc);

输出结果:

    Namespace: {NAME => 'testspace', key1 => 'value1'}

NamespaceDescriptor 类还有几个方法:

    String getName()
    String getConfigurationValue(String key)
    Map<String, String> getConfiguration()
    void setConfiguration(String key, String value)
    void removeConfiguration(final String key)
    String toString()

详细信息查阅 API 文档


1.2 表 (Tables)
-----------------------------------------------------------------------------------------------------------------------------------------
在 HBase 中的数据最终会存储到一个或多个表中,使用表的主要原因是控制表中的所有列共享表内某些特性。定义一个表最典型的工作是为其定义列族(
column families)。表描述符在 Java 中的构造器如下:

    HTableDescriptor(final TableName name)
    HTableDescriptor(HTableDescriptor desc)

使用一个名称或一个已存在的描述符创建表描述符实例。必须使用 TableName 类实例指定表名称,这允许指定表的名称,以及可选的 namespace 作为表名。
在使用已存在的描述符作为参数构造时,构造器从该实例中复制所有的设置和状态创建一个新的实例。

创建表名的字符有一定的限制。表名用于实际存储文件路径的一部分,因此它必须遵循文件名规则。TableName 类强制这些规则。

示例: Example how to create a TableName in code

private static void print(String tablename) {
    print(null, tablename);
}

private static void print(String namespace, String tablename) {
    
    System.out.print("Given Namespace: " + namespace + ", Tablename: " + tablename + " -> ");
    
    try {
        System.out.println(namespace != null ?     TableName.valueOf(namespace, tablename) : TableName.valueOf(tablename));
    } catch (Exception e) {
        System.out.println(e.getClass().getSimpleName() +     ": " + e.getMessage());
    }
}

public static void main(String[] args) throws IOException, InterruptedException
{
    print("testtable");
    print("testspace:testtable");
    print("testspace", "testtable");
    print("testspace", "te_st-ta.ble");
    print("", "TestTable-100");
    print("tEsTsPaCe", "te_st-table");
    print("");
    // VALID_NAMESPACE_REGEX = "(?:[a-zA-Z_0-9]+)";
    // VALID_TABLE_QUALIFIER_REGEX = "(?:[a-zA-Z_0-9][a-zAZ_
    0-9-.]*)";
    print(".testtable");
    print("te_st-space", "te_st-table");
    print("tEsTsPaCe", "te_st-table@dev");
}

输出结果:
    Given Namespace: null, Tablename: testtable -> testtable
    Given Namespace: null, Tablename: testspace:testtable -> testspace:    testtable
    Given Namespace: testspace, Tablename: testtable -> testspace:testtable
    Given Namespace: testspace, Tablename: te_st-ta.ble ->    testspace:te_st-ta.ble
    Given Namespace: , Tablename: TestTable-100 -> TestTable-100
    Given Namespace: tEsTsPaCe, Tablename: te_st-table ->tEsTsPaCe:te_st-table
    Given Namespace: null, Tablename: -> IllegalArgumentException:Table qualifier must not be empty
    Given Namespace: null, Tablename: .testtable ->    IllegalArgumentException: Illegal first character at 0.
    User-space table qualifiers can only start with 'alphanumeric
    characters':
    i.e. [a-zA-Z_0-9]: .testtable
    Given Namespace: te_st-space, Tablename: te_st-table -> IllegalArgumentException: Illegal character at 5. Namespaces can
    only contain 'alphanumeric characters': i.e. [a-zA-Z_0-9]: te_stspace
    Given Namespace: tEsTsPaCe, Tablename: te_st-table@dev ->
    IllegalArgumentException: Illegal character code:64, <@> at 11. User-space
    table qualifiers can only contain 'alphanumeric characters':
    i.e. [a-zA-Z_0-9-.]: te_st-table@dev

虽然,在概念上,HBase 中的一个表是行与列的集合,但在物理上,它们被存储在不同的分区上,称为 region. 每个 region 只在一个 region server
上提供服务,因而 region 会将存储的值直接提供给客户端。

 

1.2.1 序列化 (Serialization)
-----------------------------------------------------------------------------------------------------------------------------------------
很多客户端 API 类都有如下方法:

    byte[] toByteArray()
    static HTableDescriptor parseFrom(final byte[] bytes)
    TableSchema convert()
    static HTableDescriptor convert(final TableSchema ts)

每个远程系统间的通信都是使用 RPC framework 完成的。它利用 Google 的 Protocol Buffer (或简写 Protobuf) 库实现序列化和反序列化对象。
以上方法由 framework 调用以将数据写入到 output stream, 然后由接收系统读回。为此,framework 在发送端调用 toByteArray() 序列化对象的字段,
framework 精心维护类名和其它细节信息。返回值为 HTableDescriptor 的 convert() 方法用于将整个实例转换为 Protobuf 类。

在接收端,framework 读取 metadata, 并通过静态方法 parseFrom() 使用匹配的类创建类实例,这会读回字段数据并初始化发送对象的副本。使用匹配的
convert() 调用实现,得到一个 Protobuf 对象而不是底层的字节数组。

 
1.2.2 The RegionLocator Class
-----------------------------------------------------------------------------------------------------------------------------------------
RegionLocator 类提供了一些方法,这些方法总是运行在特定表的上下文中(always runs in a context of a specific table):

    public HRegionLocation getRegionLocation(final byte[] row) throws IOException
    public HRegionLocation getRegionLocation(final byte[] row, boolean reload) throws IOException
    public List<HRegionLocation> getAllRegionLocations() throws IOException

    public byte[][] getStartKeys() throws IOException
    public byte[][] getEndKeys() throws IOException
    public Pair<byte[][], byte[][]> getStartEndKeys() throws IOException

    TableName getName()

基本构建块与 Table 用法相同,从共享的连接接收一个实例,该连接指定了要处理的表,并且一旦工作完成,可以通过调用 close() 方法释放资源:

    Configuration conf = HBaseConfiguration.create();
    Connection connection = ConnectionFactory.createConnection(conf);
    TableName tn = TableName.valueOf(tableName);
    RegionLocator locator = connection.getRegionLocator(tn);
    Pair<byte[][], byte[][]> pair = locator.getStartEndKeys();
    ...
    locator.close();

region 由包含的起始键(start key inclusive),但不包含的结束键(end key exclusive)设定。

RegionLocator 可用于访问 region 细节信息,例如存储该 region 的服务器,或者与之相关联的 HRegionInfo 对象:

    HRegionInfo getRegionInfo()
    String getHostname()
    int getPort()
    String getHostnamePort()
    ServerName getServerName()
    long getSeqNum()
    String toString()

    
1.2.3 服务器和 region 名称 (Server Names and Region Names)
-----------------------------------------------------------------------------------------------------------------------------------------
有两个基本信息需要准确介绍:服务器和 region 名称(the server name and region name). 它们出现在很多地方,如 HBase shell, web-based UI, 以及
系统管理和客户端 API. 有时候它们表现为人类可读的形式,包括编码不可打印字符为代码点。有时它们通过方法返回,如 HRegionInfo 的getServerName()
或 getRegionNameAsString(), 或者作为系统管理 API 方法要求的输入参数。

下面示例创建了一个表,并且定位到包含行 Foo 的 region. 一旦获取到 region, 打印出服务器名称和 region 名称。

示例: Shows the use of server and region names

    TableName tableName = TableName.valueOf("testtable");
    HColumnDescriptor coldef1 = new HColumnDescriptor("colfam1");
    HTableDescriptor desc = new HTableDescriptor(tableName)
        .addFamily(coldef1)
        .setValue("Description", "Chapter 5 - ServerAndRegionNameExample");
    
    byte[][] regions = new byte[][] { Bytes.toBytes("ABC"),
        Bytes.toBytes("DEF"), Bytes.toBytes("GHI"), Bytes.toBytes("KLM"),
        Bytes.toBytes("OPQ"), Bytes.toBytes("TUV")
        };
        
    admin.createTable(desc, regions);
    RegionLocator locator = connection.getRegionLocator(tableName);
    HRegionLocation location = locator.getRegionLocation(Bytes.toBytes("Foo"));
    HRegionInfo info = location.getRegionInfo();
    System.out.println("Region Name: " + info.getRegionNameAsString());
    System.out.println("Server Name: " + location.getServerName());

输出结果类似:
    Region Name: testtable,DEF,1428681822728.acdd15c7050ec597b484b30b7c744a93.
    Server Name: srv1.foobar.com,63360,1428669931467

region name:
    联合 table 和 region 信息(start key, 以及 region 的创建时间),加上一个可选的名称前缀的 MD5 哈希值,由(.) 包围起来:
    
        <table name>,<region start key>,<region creation time>[.<md5hash(prefix)>.]

    在例子中 "acdd15c7050ec597b484b30b7c744a93" 是 "testtable,DEF,1428681822728" 的 MD5 哈希值。HRegionInfo 的 getEncodedName() 方法返回的
    仅仅是这个哈希值,而不是可读的前缀。
    
    这个哈希值本身用于系统在存储层内创建底层文件结构。例如,列出 HBase 存储目录内容时会看到例子中的 region 哈希值,在存储路径中:
    
    $ bin/hdfs dfs -ls -R /hbase
    drwxr-xr-x - larsgeorge supergroup 0 2015-04-10 18:03 /hbase/data/default/testtable/acdd15c7050ec597b484b30b7c744a93/colfam1

    region creation timestamp 在一个 region 创建时产生,例如,当一个表创建时,或者一个存在的 region 拆分时。
    
server name:
    也是几个不同部分的组合,包括主机名称:
    
        <host name>,<RPC port>,<server start time>
    
    server start time 用于处理在同一物理机器上多个进程。
    
    ServerName 类将细节封装到一个方便的结构中。有些 API 调用要求接收该类的一个实例,可以直接创建该类的实例,但实践方法是通过 API 获取一个
    存在的实例,例如,使用 getServerName() 方法。

 

1.3 表属性 (Table Properties)
-----------------------------------------------------------------------------------------------------------------------------------------
表描述符提供了 getter 和 setter 来设置表的很多选项。由于可以通过这些选项调节表的性能,因此了解它们很重要。按选项影响的属性将这些方法分组
讨论:

    ● 表名 (Name)
    -------------------------------------------------------------------------------------------------------------------------------------    
    构造器已经有了指定 table name 的参数,Java API 有另外的方法可以访问表的名称:

        TableName getTableName()
        String getNameAsString()    

    这两个方法返回表的名称。

    ● 列族 (Column Families)
    -------------------------------------------------------------------------------------------------------------------------------------
    这是一个表定义最重要的部分。创建表时需要指定想要使用的列族(column families):

        HTableDescriptor addFamily(final HColumnDescriptor family)
        HTableDescriptor modifyFamily(final HColumnDescriptor family)
        HColumnDescriptor removeFamily(final byte[] column)
        HColumnDescriptor getFamily(final byte[] column)
        boolean hasFamily(final byte[] familyName)
        Set<byte[]> getFamiliesKeys()
        HColumnDescriptor[] getColumnFamilies()
        Collection<HColumnDescriptor> getFamilies()

    可以添加列族,修改列族,检查其是否存在,获取所有列族的列表,以及获取或移除一个列族。


    ● 最大文件大小 (Maximum File Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    这个参数限制了表中 region 可以增长的大小。文件大小由字节单位设置,通过如下方法读取和这种:
    
        long getMaxFileSize()
        HTableDescriptor setMaxFileSize(long maxFileSize)

    最大文件大小在 region 增长到配置的限制时帮助切分 region. 在 HBase 中,扩展和负载均衡单元就是 region. 因此用户需要确定设置这个值为多少
    合适。默认情况下,该值设为 10 GB(实际的值为 10737418240, 因为以字节为单位,这个值在默认配置文件的 hbase.hregion.max.filesize 属性设置)
    这个值对于大多数场景都是合适的。
        

    ● Memstore 刷写大小 (Memstore Flush Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    之前讨论过存储模型,并指出 HBase 利用一个 in-memory 存储来缓存数据,在某个操作中将数据作为一个新的存储文件写入磁盘,这个过程称为刷写(
    flush). 这个参数用于控制何时进行刷写操作,单位为字节。通过如下方法控制:
    
        long getMemStoreFlushSize()
        HTableDescriptor setMemStoreFlushSize(long memstoreFlushSize)

    默认值为 128 MB(默认配置文件中,由属性 hbase.hregion.memstore.flush.size 设置为 134217728 bytes)。


    ● Memstore 刷写大小 (Compactions)
    -------------------------------------------------------------------------------------------------------------------------------------
    可以设置每个表的底层存储文件是否将压缩作为自动处理的一部分。利用如下方法设置和读取该标记:
    
        boolean isCompactionEnabled()
        HTableDescriptor setCompactionEnabled(final boolean isEnable)


    ● 拆分策略 (Split Policy)
    -------------------------------------------------------------------------------------------------------------------------------------
    除了设置 maximum file size ,还可以进一步影响 region 拆分。使用如下方法设置一个不同的拆分策略类,会覆盖系统范围设定的拆分策略,该策略由
    默认配置文件的 hbase.regionserver.region.split.policy 属性设置:
    
        HTableDescriptor setRegionSplitPolicyClassName(String clazz)
        String getRegionSplitPolicyClassName()


    ● Region 复本数 (Region Replicas)
    -------------------------------------------------------------------------------------------------------------------------------------
    为表设置 region 复本数。默认为 1,意为着只有一个主 region. 例如,将该属性设置为 2,会为这个表的每个 region 添加另外一个复本。由表描述
    符的如下方法控制:
    
        int getRegionReplication()
        HTableDescriptor setRegionReplication(int regionReplication)

        
    ● Durability
    -------------------------------------------------------------------------------------------------------------------------------------
    在表级别控制数据持久化 durability 方面的保证。
    通过如下方法控制:

        HTableDescriptor setDurability(Durability durability)
        Durability getDurability()


    ● 只读 (Read-only)
    -------------------------------------------------------------------------------------------------------------------------------------
    默认情况下,所有表都是可写的(writable), 但将某个特殊表设定为只读选项有时是有意义的。如果该参数设为 true, 只能从这个表中读取数据而不能
    修改它。
    
    通过如下方法控制:
        
        boolean isReadOnly()
        HTableDescriptor setReadOnly(final boolean readOnly)


    ● 协处理器 (Coprocessors)
    -------------------------------------------------------------------------------------------------------------------------------------
    下面列出可以为表配置协处理器的方法调用。这些方法可以在当前表描述符实例上添加、检查、列出、以及移除协处理器的方法:

        HTableDescriptor addCoprocessor(String className) throws IOException
        HTableDescriptor addCoprocessor(String className, Path jarFilePath, int priority, final Map<String, String> kvs) throws IOException
        boolean hasCoprocessor(String className)
        List<String> getCoprocessors()
        void removeCoprocessor(String className)

        
    ● 描述符参数 (Descriptor Parameters)
    -------------------------------------------------------------------------------------------------------------------------------------
    如下方法可用于设置任意的 key/value 对:
    
        byte[] getValue(byte[] key)
        String getValue(String key)
        Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues()
        HTableDescriptor setValue(byte[] key, byte[] value)
        HTableDescriptor setValue(final ImmutableBytesWritable key, final ImmutableBytesWritable value)
        HTableDescriptor setValue(String key, String value)
        void remove(final String key)
        void remove(ImmutableBytesWritable key)
        void remove(final byte[] key)


    ● 配置 (Configuration)
    -------------------------------------------------------------------------------------------------------------------------------------
    允许用户在每个表的基础上,覆盖任何 HBase 配置属性。在运行时它会与默认值,以及集群范围的配置文件合并。注意只有与 region 和 table 相关的
    属性设置有用。其它不相关的属性不会起作用,即便覆盖了它们。

        String getConfigurationValue(String key)
        Map<String, String> getConfiguration()
        HTableDescriptor setConfiguration(String key, String value)
        void removeConfiguration(final String key)


    ● 杂项调用 (Miscellaneous Calls)
    -------------------------------------------------------------------------------------------------------------------------------------
        boolean isRootRegion()
        boolean isMetaRegion()
        boolean isMetaTable()
        
        String toString()
        String toStringCustomizedValues()
        String toStringTableAttributes()    


1.4 列族 (Column Families)
-----------------------------------------------------------------------------------------------------------------------------------------
我们已经看到 HTableDescriptor 类提供的方法向一个表中添加列族。与此相关,HColumnDescriptor 类封装了每个列族的设置。

    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    在 Java 中这个类的名称有点儿词不达意。更适合的名称应该为 HColumnFamilyDescriptor, 这样才能给表达定义列族属性的真正含义。

列族定义了在其中创建的所有列的公共特征。客户端通过列限定符(column qualifier)可以在其中创建任意数量的列。定位某一列可以联合列族名称和列限
定符(有时也称为 column key),其间由冒号(:)分隔:

    `family:qualifier`

列族名称必须是由可打印字符组成,并且不能以冒号(:)开始,或者完全为空。列限定符(column qualifier) 可以由任意的二进制字节组成。回顾之前提到
过的 Bytes 类,可以利用它将选择的名称转换为字节数组。列族名称必须是由可打印字符组成的原因是,这个名称会用作低级存储层目录的一部分。列族名
被加入到路径中,并且必须遵循文件名规范。

也需要对空列限定符(empty column qualifier)有所了解。可以简单地忽略限定符而只适应列族名,HBase 使用特殊的空限定符创建该列。用户可以读写这
个列,就像其它列一样,但很明显,一个列族内只能有一个这样的列,必须给其它列命名以与该列区别。对于简单的应用,使用没有限定符是一种选择,但
在查看数据时没什么意义,例如,使用 HBase shell.

应该在一开始时就给列命名,因为不能在之后简单地重命名列限定符。

使用 HBase Shell, 尝试创建一个没有名称的列:

    hbase(main):001:0> create 'testtable', 'colfam1'
    0 row(s) in 0.1400 seconds

    => Hbase::Table - testtable
    hbase(main):002:0> put 'testtable', 'row1', 'colfam1:', 'val1'
    0 row(s) in 0.1130 seconds

    hbase(main):003:0> scan 'testtable'
    ROW COLUMN+CELL
    row1 column=colfam1:, timestamp=1428488894611, value=val1
    1 row(s) in 0.0590 seconds

    hbase(main):004:0> create 'testtable', 'col/fam1'

    ERROR: Illegal character <47>. Family names cannot contain control
    characters or colons: col/fam1
    Here is some help for this command:
    ...

可以使用静态的帮助方法验证名称:

    static byte[] isLegalFamilyName(final byte[] b)

在自己的程序中使用该方法验证用户提供的输入是否遵循名称规范。这个方法不返回 boolean 标志,而是在名称非法时抛出 IllegalArgumentException
异常,如果合法,它直接返回给定的参数值。


    NOTE
    -------------------------------------------------------------------------------------------------------------------------------------
    列族不能重命名。重命名一个列族一般的方法是,使用新名创建一个新的列族,然后使用 API 将数据拷贝到新列族中去.
    
创建列族时,有多个构造器可以创建实例:

    HColumnDescriptor(final String familyName)
    HColumnDescriptor(final byte[] familyName)
    HColumnDescriptor(HColumnDescriptor desc)    
    
前两个构造器简单地接收 String 类型或 byte[] 数组类型的 familyName. 另外一个接收一个已存在的 HColumnDescriptor 实例,从其中拷贝所有状态和
设置创建新实例。不通过构造器,也可以使用 getter 和 setter 来设置各种细节信息,下面按其作用分组讨论:
    
    
    ● 列族名称 (Name)
    -------------------------------------------------------------------------------------------------------------------------------------    
    每个列族都有一个名称,并且可以使用如下方法从一个已存在的 HColumnDescriptor 实例上获取到该名称:
    
        byte[] getName();
        String getNameAsString();
    
    不能设置列族名称,但可以通过构造器设定它。
    
        NOTE
        ---------------------------------------------------------------------------------------------------------------------------------
        列族名称不能以句点(.)开始,并且不能包含冒号(:), 斜线(/), 或者 ISO 控制符。
    
    
    ● 最大版本数 (Maximum Versions)
    -------------------------------------------------------------------------------------------------------------------------------------
    对于每个列族,可以设定每个值可以保留的版本数量。HBase 的内部管理会移除超出最大版本数的数据。通过如下方法获取或设置该值:
    
        int getMaxVersions()
        HColumnDescriptor setMaxVersions(int maxVersions)

    默认值为 1,由 hbase.column.max.version 配置属性设置。默认值适用于大多数应用场景。如果需要,可以增加这个数量,例如,对于存储密码的列,
    可以将这个值设为 10 来保留使用过的密码历史。
    
    
    ● 最小版本数 (Minimum Versions)
    -------------------------------------------------------------------------------------------------------------------------------------    
    指定一个列总是保留的版本数量。这个值与 time-to-live 配合使用,避免移除列中最后存储的值。默认值为 0,意为禁用该特性:
    
        int getMinVersions()
        HColumnDescriptor setMinVersions(int minVersions)
    
    
    ● 保留删除的单元 (Keep Deleted Cells)
    -------------------------------------------------------------------------------------------------------------------------------------
    控制后台 housekeeping 进程是否移除已删除的 cell:
    
        KeepDeletedCells getKeepDeletedCells()
        HColumnDescriptor setKeepDeletedCells(boolean keepDeletedCells)
        HColumnDescriptor setKeepDeletedCells(KeepDeletedCells keepDeletedCells)    
    
    使用的 KeepDeletedCells 是个枚举类型,有如下选项:
    
    The KeepDeletedCells enumeration
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | Value    | Description
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | FALSE    | Deleted cells are not retained.
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | TRUE    | Deleted cells are retained until they are removed by other means such as time-to-live (TTL) or the max number of versions.
    |        | If no TTL is specified or no new versions of delete cells are written, they are retained forever
    +-------+--------------------------------------------------------------------------------------------------------------------------
    | TTL    | Deleted cells are retained until the delete marker expires due to TTL. This is useful when TTL is combined with the number
    |        | of minimum versions, and you want to keep a minimum number of versions around, but at the same time remove deleted cells
    |        | after the TTL.
    +-------+--------------------------------------------------------------------------------------------------------------------------
    
    默认值为 FALSE, 意为在 housekeeping 操作期间,不保留已删除的 cell.
    
    
    ● 压缩 (Compression)
    -------------------------------------------------------------------------------------------------------------------------------------    
    HBase 支持插件式压缩算法,允许用户为存储在特定列族中的数据选择最合适的压缩算法,或者选择不压缩。可用的算法列于下表:
    
    Supported compression algorithms
    +-------+-------------------------------------------------------------------------------------------
    | Value    | Description
    +-------+-------------------------------------------------------------------------------------------
    | NONE    | Disables compression (default).
    +-------+-------------------------------------------------------------------------------------------
    | GZ    | Uses the Java-supplied or native GZip compression (which needs to be installed separately).
    +-------+-------------------------------------------------------------------------------------------
    | LZO    | Enables LZO compression; must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    | LZ4    | Enables LZ4 compression; must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    | SNAPPY| Enables Snappy compression; binaries must be installed separately
    +-------+-------------------------------------------------------------------------------------------
    
    默认值为 NONE, 换句话说,创建列族时没有启用压缩。使用 API 和列描述符实例,可以通过如下方法改变设置:
    
        Compression.Algorithm getCompression()
        Compression.Algorithm getCompressionType()
        HColumnDescriptor setCompressionType(Compression.Algorithm type)
        
        Compression.Algorithm getCompactionCompression()
        Compression.Algorithm getCompactionCompressionType()
        HColumnDescriptor setCompactionCompressionType(Compression.Algorithm type)
    
    注意参数类型为 Compression.Algorithm 枚举类型,其选项为上表所列。另外注意到的是,这里有两套方法,一套是常规的压缩(general compression)
    设置,另一套是紧凑压缩(compaction compression)设置。
    
    
    ● 编码 (Encoding)
    -------------------------------------------------------------------------------------------------------------------------------------    
    设置数据块的编码。如果启用,可以进一步影响是否使用相同的设置应用到 cell 标记(tag). 方法如下:
    
        DataBlockEncoding getDataBlockEncoding()
        HColumnDescriptor setDataBlockEncoding(DataBlockEncoding type)
    
    这两个方法控制使用的编码类型,使用的 DataBlockEncoding 枚举类型包含如下选项:
    
    Options of the DataBlockEncoding enumeration
    +---------------+------------------------------------------------------------------------------------------
    | Option        | Description
    +---------------+------------------------------------------------------------------------------------------
    | NONE            | No prefix encoding takes place (default).
    +---------------+------------------------------------------------------------------------------------------
    | PREFIX        | Represents the prefix compression algorithm, which removes repeating common prefixes
    |                | from subsequent cell keys.
    +---------------+------------------------------------------------------------------------------------------
    | DIFF            | The diff algorithm, which further compresses the key of subsequent cells by storing
    |                | only differences to previous keys.
    +---------------+------------------------------------------------------------------------------------------
    | FAST_DIFF        | An optimized version of the diff encoding, which also omits repetitive cell value data
    +---------------+------------------------------------------------------------------------------------------
    | PREFIX_TREE    | Trades increased write time latencies for faster read performance. Uses a tree structure
    |                | to compress the cell key.
    +---------------+------------------------------------------------------------------------------------------
    
    除了为每个 cell key 设置编码之外,cell 可能会携带用于不同目的的标记列表(list of tags), 例如安全信息和 cell
    级别的 TTL 等。下面的方法可以设置是否将编码属性也应用到这些标记上:
    
        HColumnDescriptor setCompressTags(boolean compressTags)
        boolean isCompressTags()
        
    默认值为 true, 因此所有可选的 cell 标记也作为整个 cell 编码的一部分编码。
    
    
    ● 块大小 (Block Size)
    -------------------------------------------------------------------------------------------------------------------------------------
    HBase 中,在 get() 或 scan() 操作期间,所有存储文件都被划分为很小的数据块载入,类似于 RDBMS 中的页(page)。数据块大小默认被设置为 64KB
    可以通过如下方法调整:
    
        synchronized int getBlocksize()
        HColumnDescriptor setBlocksize(int s)

    该值以字节为单位设置,用于控制在获取数据时,要求 HBase 从存储文件中一次读取多少数据放入到内存中缓存起来,以用于后续的访问。

        NOTE
        ---------------------------------------------------------------------------------------------------------------------------------
        注意,列族的数据块大小,或者说是 HFile 块大小,与 HDFS 级别的数据块大小之间有着重要的区别。Hadoop 和 HDFS 使用的数据块大小,默认
        为 128 MB,用于拆分较大的文件以提供分布式存储,以便于 YARN 框架进行并发处理。对于 HBase, HFile 数据块大小,默认为 64 KB, 是 HDFS
        数据块大小的 2048 分之一,是为了在块操作中高效加载和缓存数据,与 HDFS 块大小不相关,并且只为内部使用。


    ● 块缓存 (Block Cache)
    -------------------------------------------------------------------------------------------------------------------------------------
    由于为了高效利用 I/O, HBase 读取整块的数据到内存中缓存下来,这样后续的读取就不需要任何的磁盘操作。默认为 true, 为每次读取操作启用块缓
    存。但如果用户的应用场景是要顺序地读取某个列族,最好将这个属性设置为 false, 从而禁止其使用块缓存。下列方法用于控制该属性:
    
        boolean isBlockCacheEnabled()
        HColumnDescriptor setBlockCacheEnabled(boolean blockCacheEnabled)
    
    还有其它方法可用于影响块缓存的使用,例如,在 scan() 操作时,可以通过 setCacheBlocks(false) 调用来禁用块缓存。这在全表扫描时很有用,这
    样就不会搞乱缓存。
    
    除了缓存本身,也可以配置系统的行为:数据被写入时,存储文件要关闭或打开时,下列方法定义这些属性:
    
        boolean isCacheDataOnWrite()
        HColumnDescriptor setCacheDataOnWrite(boolean value)
        
        boolean isCacheDataInL1()
        HColumnDescriptor setCacheDataInL1(boolean value)
        
        boolean isCacheIndexesOnWrite()
        HColumnDescriptor setCacheIndexesOnWrite(boolean value)
        
        boolean isCacheBloomsOnWrite()
        HColumnDescriptor setCacheBloomsOnWrite(boolean value)
        
        boolean isEvictBlocksOnClose()
        HColumnDescriptor setEvictBlocksOnClose(boolean value)
        
        boolean isPrefetchBlocksOnOpen()
        HColumnDescriptor setPrefetchBlocksOnOpen(boolean value)    
        
    注意,目前为止,这些属性默认设置为 false, 意为这些属性都没有激活,除非某个列族启用它们。
    
    
    ● 生存期 (Time-to-Live)
    -------------------------------------------------------------------------------------------------------------------------------------
    HBase 支持每个值在版本数量上断言删除,也支持基于时间的删除。生存期(time-to-live, TTL) 设置了一个基于时间戳的临界值,内部管理(internal
    housekeeping)程序自动检查值的生存期是否超过其 TTL 设置。如果超出,会在 major 合并过程中丢弃这个数据。下面的方法用于读写 TTL:
    
        int getTimeToLive()
        HColumnDescriptor setTimeToLive(int timeToLive)
    
    该值以秒为单位指定,默认值为 HConstants.FOREVER, 设置为 Integer.MAX_VALUE, 即 2,147,483,647 秒,意为永远保留该数据,即任何小于该默认
    值的正数都会启用该特性。
    
    
    ● 在内存中 (In-Memory)
    -------------------------------------------------------------------------------------------------------------------------------------
    之前提到过快缓存,以及如何利用块缓存来将整块的数据保留在内存中,以提高顺序访问数据的效率。in-memory 标志默认为 false, 但可以通过如下
    方法读取或修改该属性:
    
        boolean isInMemory()
        HColumnDescriptor setInMemory(boolean inMemory)
    
    将该值设为 true 并不能保证整个列族的所有数据块载入到内存中,也不能保证其一直保留。把它当做承诺,或者较高的优先级,只要在正常的获取操作,
    就会将数据载入保留到内存中,直到堆内存的压力太大,这时就需要丢掉它们。
    
    
    ● 布隆过滤器 (Bloom Filter)
    -------------------------------------------------------------------------------------------------------------------------------------
    布隆过滤器是 HBase 系统的高级功能,它通过特定访问模式减少查询时间。虽然会增加存储和内存占用的开销,但会提升查找和读取性能。
    
    Supported Bloom Filter Types
    +-----------+--------------------------------------------------------------------------------------------------------------
    | Type        | Description
    +-----------+--------------------------------------------------------------------------------------------------------------
    | NONE        | Disables the filter.
    +-----------+--------------------------------------------------------------------------------------------------------------
    | ROW        | Use the row key for the filter (default).
    +-----------+--------------------------------------------------------------------------------------------------------------
    | ROWCOL    | Use the row key and column key (family+qualifier) for the filter
    +-----------+--------------------------------------------------------------------------------------------------------------

    从 HBase 0.96 开始,对所有用户表的所有列族默认设置为 ROW, 对系统目录表没有启用该功能。
    可以通过如下方法获取或改变布隆过滤器,其中 BloomType 枚举类型如上表所示:
    
        BloomType getBloomFilterType()
        HColumnDescriptor setBloomFilterType(final BloomType bt)
    
    
    ● 复制范围 (Replication Scope)
    -------------------------------------------------------------------------------------------------------------------------------------    
    HBase 的另一个高级功能时复制(replication)。它提供了跨集群同步的功能,本地集群的数据更新可以及时同步到其它集群。默认情况下,复制功能是
    禁用的,复制范围(replication scop) 设置为 0,意为禁用复制功能。可以通过如下方法改变设置:
    
        int getScope()
        HColumnDescriptor setScope(int scope)

    另一个支持的值是 1,意为启用到远程集群的复制。
    
    Supported Replication Scopes
    +-------+---------------------------+----------------------------------------------------------------
    | Scope    | Constant                    | Description
    +-------+---------------------------+----------------------------------------------------------------
    | 0        | REPLICATION_SCOPE_LOCAL    | Local scope, i.e., no replication for this family (default).
    +-------+---------------------------+-------------------------------------------------------------------
    | 1        | REPLICATION_SCOPE_GLOBAL    | Global scope, i.e., replicate family to a remote cluster.
    +-------+---------------------------+----------------------------------------------------------------


    ● 加密 (Encryption)
    -------------------------------------------------------------------------------------------------------------------------------------
    设置加密相关的信息,方法如下:
    
        String getEncryptionType()
        HColumnDescriptor setEncryptionType(String algorithm)
        byte[] getEncryptionKey()
        HColumnDescriptor setEncryptionKey(byte[] keyBytes)    


    ● 描述符参数 (Descriptor Parameters)
    -------------------------------------------------------------------------------------------------------------------------------------
    下列方法用于设置任意的 key/value 对属性:
    
        byte[] getValue(byte[] key)
        String getValue(String key)
        Map<ImmutableBytesWritable, ImmutableBytesWritable> getValues()
        HColumnDescriptor setValue(byte[] key, byte[] value)
        HColumnDescriptor setValue(String key, String value)
        void remove(final byte[] key)

    可以利用这些方法访问所有配置的值,以上提及的所有方法都是通过这个列表中的方法设置它们的参数的。这些方法的另一个应用场景是,用于存储应用
    相关的元数据(metadata), 因为它们持久化到服务器上,因此之后可以由客户端读取。

    
    ● 配置 (Configuration)
    -------------------------------------------------------------------------------------------------------------------------------------
    允许用户在列族级别覆盖任何 HBase 的配置属性。这些属性在运行时与默认值、集群范围的配置文件、以及表级别的设置合并。注意,只有与 region
    或 table 相关的属性可以设置,其它不相关属性,即便已被覆盖,也不会读取。

    方法如下:
    
        String getConfigurationValue(String key)
        Map<String, String> getConfiguration()
        HColumnDescriptor setConfiguration(String key, String value)
        void removeConfiguration(final String key)

        
    ● 杂项调用 (Miscellaneous Calls)
    -------------------------------------------------------------------------------------------------------------------------------------
        static Unit getUnit(String key)
        static Map<String, String> getDefaultValues()
        String toString()
        String toStringCustomizedValues()    

    目前支持的 Unit 只有 TTL。

下面的示例利用 API 创建了一个描述符,设置自定义属性,并以各种方法打印出来:

示例: Example how to create a HColumnDescriptor in code

    HColumnDescriptor desc = new HColumnDescriptor("colfam1")
                                .setValue("test-key", "test-value")
                                .setBloomFilterType(BloomType.ROWCOL);

    System.out.println("Column Descriptor: " + desc);
    System.out.print("Values: ");

    for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry : desc.getValues().entrySet()) {
        System.out.print(Bytes.toString(entry.getKey().get()) +
        " -> " + Bytes.toString(entry.getValue().get()) + ", ");
    }

    System.out.println();
    System.out.println("Defaults: " + HColumnDescriptor.getDefaultValues());
    System.out.println("Custom: " + desc.toStringCustomizedValues());
    System.out.println("Units:");
    System.out.println(HColumnDescriptor.TTL + " -> " + desc.getUnit(HColumnDescriptor.TTL));
    System.out.println(HColumnDescriptor.BLOCKSIZE + " -> " + desc.getUnit(HColumnDescriptor.BLOCKSIZE));

输出结果:

    Column Descriptor: {NAME => 'colfam1', DATA_BLOCK_ENCODING =>'NONE',
    BLOOMFILTER => 'ROWCOL', REPLICATION_SCOPE => '0',COMPRESSION => 'NONE', VERSIONS => '1', TTL => 'FOREVER',
    MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'FALSE',    BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true',
    METADATA => {'test-key' => 'test-value'}}
    Values: DATA_BLOCK_ENCODING -> NONE, BLOOMFILTER -> ROWCOL,    REPLICATION_SCOPE -> 0, COMPRESSION -> NONE, VERSIONS -> 1,
    TTL -> 2147483647, MIN_VERSIONS -> 0, KEEP_DELETED_CELLS ->    FALSE,BLOCKSIZE -> 65536, IN_MEMORY -> false, test-key -> test-value,
    BLOCKCACHE -> true
    Defaults: {CACHE_BLOOMS_ON_WRITE=false, CACHE_DATA_IN_L1=false,    PREFETCH_BLOCKS_ON_OPEN=false, BLOCKCACHE=true,
    CACHE_INDEX_ON_WRITE=false, TTL=2147483647, DATA_BLOCK_ENCODING=NONE,BLOCKSIZE=65536, BLOOMFILTER=ROW, EVICT_BLOCKS_ON_CLOSE=false,
    MIN_VERSIONS=0, CACHE_DATA_ON_WRITE=false, KEEP_DELETED_CELLS=FALSE,COMPRESSION=none, REPLICATION_SCOPE=0, VERSIONS=1, IN_MEMORY=
    false}
    Custom: {NAME => 'colfam1', BLOOMFILTER => 'ROWCOL', METADATA => {'test-key' => 'test-value'}}
    Units:
    TTL -> TIME_INTERVAL
    BLOCKSIZE -> NONE

    
table 描述符中使用的序列化方法,在列族描述符中也存在,用于通过 RPC 发送经过配置的实例:

    byte[] toByteArray()
    static HColumnDescriptor parseFrom(final byte[] bytes) throws DeserializationException
    static HColumnDescriptor convert(final ColumnFamilySchema cfs)
    ColumnFamilySchema convert()

 

参考:

    《HBase - The Definitive Guide - 2nd Edition》Early release —— 2015.7 Lars George

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值