HBase如何实现模糊查询?

分析&回答


看下图hbase在对key值进行过滤尤其是rowkey(行键)进行过滤的时候,性能是最优的。
image.png
我们尽量设计通过 RowKey 前缀的方式进行模糊查询。

反思&扩展


HBase RowKey 的设计原则?

扩展阅读

针对事务数据Rowkey设计

事务数据是带时间属性的,建议将时间信息存入到Rowkey中,这有助于提示查询检索速度。对于事务数据建议缺省就按天为数据建表,这样设计的好处是多方面的。按天分表后,时间信息就可以去掉日期部分只保留小时分钟毫秒,这样4个字节即可搞定。加上散列字段2个字节一共6个字节即可组成唯一 Rowkey。如下图所示:

事务数据Rowkey设计
第0字节第1字节第2字节第3字节第4字节第5字节
散列字段时间字段(毫秒)扩展字段
0 ~ 65535(0x0000 ~ 0xFFFF)0 ~ 86399999(0x00000000 ~ 0x05265BFF)

这样的设计从操作系统内存管理层面无法节省开销,因为64位操作系统是必须8字节对齐。但是对于持久化存储中Rowkey部分可以节省25%的开销。也许有人要问为什么不将时间字段以主机字节序保存,这样它也可以作为散列字段了。这是因为时间范围内的数据还是尽量保证连续,相同时间范围内的数据查找的概率很大,对查询检索有好的效果,因此使用独立的散列字段效果更好,对于某些应用,我们可以考虑利用散列字段全部或者部分来存储某些数据的字段信息,只要保证相同散列值在同一时间(毫秒)唯一。

针对统计数据的Rowkey设计

统计数据也是带时间属性的,统计数据最小单位只会到分钟(到秒预统计就没意义了)。同时对于统计数据我们也缺省采用按天数据分表,这样设计的好处无需多说。按天分表后,时间信息只需要保留小时分钟,那么0~1400只需占用两个字节即可保存时间信息。由于统计数据某些维度数量非常庞大,因此需要4个字节作为序列字段,因此将散列字段同时作为序列字段使用也是6个字节组成唯一Rowkey。如下图所示:

统计数据Rowkey设计
第0字节第1字节第2字节第3字节第4字节第5字节
散列字段(序列字段)时间字段(分钟)扩展字段
0x00000000 ~ 0xFFFFFFFF)0 ~ 1439(0x0000 ~ 0x059F)

同样这样的设计从操作系统内存管理层面无法节省开销,因为64位操作系统是必须8字节对齐。但是对于持久化存储中Rowkey部分可以节省25%的开销。预统计数据可能涉及到多次反复的重计算要求,需确保作废的数据能有效删除,同时不能影响散列的均衡效果,因此要特殊处理。

针对通用数据的Rowkey设计

通用数据采用自增序列作为唯一主键,用户可以选择按天建分表也可以选择单表模式。这种模式需要确保同时多个入库加载模块运行时散列字段(序列字段)的唯一性。可以考虑给不同的加载模块赋予唯一因子区别。设计结构如下图所示。

通用数据Rowkey设计
第0字节第1字节第2字节第3字节
散列字段(序列字段)扩展字段(控制在12字节内)
0x00000000 ~ 0xFFFFFFFF)可由多个用户字段组成
支持多条件查询的RowKey设计

HBase按指定的条件获取一批记录时,使用的就是scan方法。 scan方法有以下特点:

(1)scan可以通过setCaching与setBatch方法提高速度(以空间换时间);

(2)scan可以通过setStartRow与setEndRow来限定范围。范围越小,性能越高。

通过巧妙的RowKey设计使我们批量获取记录集合中的元素挨在一起(应该在同一个Region下),可以在遍历结果时获得很好的性能。

(3)scan可以通过setFilter方法添加过滤器,这也是分页、多条件查询的基础。

在满足长度、三列、唯一原则后,我们需要考虑如何通过巧妙设计RowKey以利用scan方法的范围功能,使得获取一批记录的查询速度能提高。下例就描述如何将多个列组合成一个RowKey,使用scan的range来达到较快查询速度。

例子:

我们在表中存储的是文件信息,每个文件有5个属性:文件id(long,全局唯一)、创建时间(long)、文件名(String)、分类名(String)、所有者(User)。

我们可以输入的查询条件:文件创建时间区间(比如从20120901到20120914期间创建的文件),文件名(“中国好声音”),分类(“综艺”),所有者(“浙江卫视”)。

假设当前我们一共有如下文件:

IDCreateTimeNameCategoryUserID
120120902中国好声音第1期综艺1
220120904中国好声音第2期综艺1
320120906中国好声音外卡赛综艺1
420120908中国好声音第3期综艺1
520120910中国好声音第4期综艺1
620120912中国好声音选手采访综艺花絮2
720120914中国好声音第5期综艺1
820120916中国好声音录制花絮综艺花絮2
920120918张玮独家专访花絮3
1020120920加多宝凉茶广告综艺广告4

这里UserID应该对应另一张User表,暂不列出。我们只需知道UserID的含义:

1代表 浙江卫视; 2代表 好声音剧组; 3代表 XX微博; 4代表赞助商。调用查询接口的时候将上述5个条件同时输入find(20120901,20121001,”中国好声音”,”综艺”,”浙江卫视”)。此时我们应该得到记录应该有第1、2、3、4、5、7条。第6条由于不属于“浙江卫视”应该不被选中。我们在设计RowKey时可以这样做:采用 UserID + CreateTime + FileID组成RowKey,这样既能满足多条件查询,又能有很快的查询速度。

需要注意以下几点:

(1)每条记录的RowKey,每个字段都需要填充到相同长度。假如预期我们最多有10万量级的用户,则userID应该统一填充至6位,如000001,000002…

(2)结尾添加全局唯一的FileID的用意也是使每个文件对应的记录全局唯一。避免当UserID与CreateTime相同时的两个不同文件记录相互覆盖。

按照这种RowKey存储上述文件记录,在HBase表中是下面的结构:

rowKey(userID 6 + time 8 + fileID 6) name category ….

00000120120902000001
00000120120904000002
00000120120906000003
00000120120908000004
00000120120910000005
00000120120914000007
00000220120912000006
00000220120916000008
00000320120918000009
00000420120920000010

怎样用这张表?

在建立一个scan对象后,我们setStartRow(00000120120901),setEndRow(00000120120914)。

这样,scan时只扫描userID=1的数据,且时间范围限定在这个指定的时间段内,满足了按用户以及按时间范围对结果的筛选。并且由于记录集中存储,性能很好。

然后使用 SingleColumnValueFilter(org.apache.hadoop.hbase.filter.SingleColumnValueFilter),共4个,分别约束name的上下限,与category的上下限。满足按同时按文件名以及分类名的前缀匹配。

(注意:使用SingleColumnValueFilter会影响查询性能,在真正处理海量数据时会消耗很大的资源,且需要较长的时间)

如果需要分页还可以再加一个PageFilter限制返回记录的个数。


喵呜面试助手: 一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!针对 HBase模糊查询,可以使用 HBase 提供的过滤器(Filter)来实现HBase 中常用的过滤器有前缀过滤器(PrefixFilter)、单列值过滤器(SingleColumnValueFilter)和正则表达式过滤器(RegexStringComparator)等。 其中,正则表达式过滤器是用于实现模糊查询的一种常用方式。您可以通过设置正则表达式来匹配需要的数据。以下是一个示例代码片段,演示如何使用正则表达式过滤器进行模糊查询: ```java import org.apache.hadoop.hbase.client.*; import org.apache.hadoop.hbase.filter.RegexStringComparator; import org.apache.hadoop.hbase.filter.RowFilter; public class HBaseFuzzyQueryExample { public static void main(String[] args) { try { // 创建 HBase 连接 Connection connection = ConnectionFactory.createConnection(); // 获取 HBase 表 Table table = connection.getTable(TableName.valueOf("your_table_name")); // 创建正则表达式过滤器 RegexStringComparator regexComparator = new RegexStringComparator("your_regex_pattern"); RowFilter rowFilter = new RowFilter(CompareOperator.EQUAL, regexComparator); // 创建扫描器并设置过滤器 Scan scan = new Scan(); scan.setFilter(rowFilter); // 执行查询 ResultScanner scanner = table.getScanner(scan); for (Result result : scanner) { // 处理查询结果 // ... } // 关闭资源 scanner.close(); table.close(); connection.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述代码中,您需要将 "your_table_name" 替换为您实际的表名,将 "your_regex_pattern" 替换为您想要匹配的模式。通过调整正则表达式的规则,可以实现不同的模糊查询需求。 希望对您有所帮助!如果您有任何其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵呜刷题

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值