《HBase实战》一2.6 表扫描-阿里云开发者社区

开发者社区> 开发与运维> 正文

《HBase实战》一2.6 表扫描

简介:

本节书摘来异步社区《HBase实战》一书中的第2章,第2.6节,作者: 【美】Nick Dimiduk , Amandeep Khurana 译者: 谢磊 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.6 表扫描

HBase实战
你可能发现,没有查询(query)命令。到目前为止,你都找不到这样的命令。查找包含某个特定值的记录的唯一办法是,使用扫描(Scan)命令读出表的某些部分,然后再使用过滤器(filter)来得到有关记录。可以想到,扫描返回的记录是排好序的。HBase设计上支持这种方式,因此速度很快。

要扫描得到整个表的内容,单独使用Scan构造函数即可:


q11

但是,你经常只对整张表的一个子集感兴趣。比如,你想得到所有以字母T开头的ID的用户。给Scan构造函数增加起始行和结束行的信息即可:


q10

这个例子也许有些牵强,但可以帮助你理解。一个实战的例子是什么样呢?假设你存储了推帖,你一定想进一步了解某个特定用户的最新推帖。让我们开始实现这一点。

2.6.1 设计用于扫描的表
就像设计关系模式一样,为HBase表设计模式(Schema)也需要考虑数据形态和访问模式。推帖数据的访问模型不同于用户,因此我们为它们新建自己的表。为了练手,这里使用Java API 而不是Shell来新建表。

可以使用HBaseAdmin对象的一个实例来执行表的操作:


q9

创建HBaseAdmin实例显然需要一个Configuration实例,默认的HTable和HTablePool构造函数帮你隐藏细节。这一步很简单。现在你可以定义一个新表并且创建它:


q8

HTableDescriptor对象建立新表的描述信息,其名字是twits。同样,使用HColumnDescriptor建立列族,名字也是twits。和users表一样,这里只需要一个列族。你不需要推帖的多个时间版本,所以限定保留的版本数为一个。

现在可以开始存储推帖到这个有趣的新twits表。推帖包含内容和发布的日期和时间等。你需要一个唯一值作为行键,所以我们选择用户名加上时间戳来做行键。很简单,我们存储一些推帖,如下所示:


q7

好了,基本如此。首先请注意,用户ID是个变长字符串。当你使用复合行键时这会带来一些麻烦,因为你需要某种分隔符来切分出用户ID。一种变通的办法是对行键的变长类型部分做散列(hash)处理。选择一种散列算法生成固定长度的值。因为你想基于用户分组存储不同用户的推帖,MD5算法是一种好选择。这些组按序存储。在组内,推帖是基于发布日期时间先后顺序存储的。MD5是一种单向散列算法,所以不要忘了把未经编码处理的用户ID另外存储在一个列里,以防后面用到。如下所示,向twits表中写入数据。

q6

一般来说,你会先用到最新推帖。HBase在物理数据模型里按照行键顺序存储行。你可以利用这个特性。在行键里包括推帖的时间戳,并且乘以−1,就可以先得到最新的推帖。

在HBase模式中行键设计至关重要

这一点如何强调都不为过:HBase的行键在设计表时是第一重要的考量因素。我们会在第4章进一步讨论。我们现在提到它是为了让你在学习例子时脑子里有个概念。当你看到HBase模式时第一个应该问自己的问题是:“行键是什么?”下一个问题是:“我可以怎样让行键更有效率?”

2.6.2 执行扫描

使用用户ID作为twits表行键的第一部分证明是好办法。它可以基于用户以自然行的顺序有效地生成数据桶(bucket)。来自同一用户的数据以连续行的形式存储在一起。现在Scan命令如何使用呢?或多或少和之前介绍的类似,只是计算停止键时复杂一点:

q5

本例中,你可以通过对行键中用户ID部分的最后字符加1来生成停止键。扫描器返回包括起始键但是不包括停止键的记录,因此你只得到了匹配用户的推帖。

再通过一个简单的循环从ResultScanner中读出推帖:


q12

循环中唯一需要处理的是分离出时间戳,并且把字节数组byte[]转换成合适的数据类型。你会得到如下数据:


q4

2.6.3 扫描器缓存

在HBase的设置里扫描每次RPC调用得到一批行数据。这可以在扫描对象上使用setCaching(int)在每个扫描器(scanner)层次上设置,也可以在hbasesite.xml 配置文件里使用HBase.client.scanner.caching属性来设置。如果缓存值设置为n,每次RPC调用扫描器返回n行,然后这些数据缓存在客户端。这个设置的默认值是1,这意味着客户端对HBase的每次RPC调用在扫描整张表后仅仅返回一行。这个数字很保守,你可以调整它以获得更好的性能。但是该值设置过高意味着客户端和HBase的交互会出现较长暂停,这会导致HBase端的超时。

ResultScanner接口也有一个next(int)调用,你可以用来要求返回扫描的下面n行。这是在API层面提供的便利,与为了获得那n行数据客户端对HBase的RPC调用次数无关。

在内部机制中,ResultScanner使用了多次RPC调用来满足这个请求,每次RPC调用返回的行数只取决于你为扫描器设置的缓存值。

2.6.4 使用过滤器

并不总能设计一个行键来完美地匹配你的访问模式。有时你的使用场景需要扫描HBase的一组数据但是只返回它的子集给客户端。这时需要使用过滤器(filter)。为你的Scan对象增加过滤器,如下所示:


q3

过滤器是在HBase服务器端上而不是在客户端执行判断动作。当你在Scan里设定Filter``时,HBase使用它来决定一个记录是否返回。这样避免了许多不必要的数据传输。这个特性在服务器上执行过滤动作而不是把负担放在客户端。

使用过滤器需要实现org.apache.hadoop.hbase.filter.filter接口。HBase提供了许多种过滤器,但实现你自己的过滤器也很容易。

为了过滤所有提到TwitBase的推帖,你可以结合RegexStringComparator使用ValueFilter:


q2

HBase也提供了一个过滤器构造类。ParseFilter对象实现了一种查询语言,可以用来构造Filter实例。可以用一个表达式构造同样的TwitBase 过滤器:


q1

这两个例子中,数据在到达客户端之前在region中编译和使用了正则表达式。

上面是一个在应用中使用过滤器的简单例子。HBase中过滤器可以应用到行键、列限定符或者数据值。你也可以使用FilterList和WhileMatchFilter对象组合多个过滤器。过滤器允许对数据分页处理,限制扫描器返回的行数。我们将在第4章深入讨论组合型过滤器(bundled filter)。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章