Python happaybase使用Thrift API和Filter实现Hbase的复杂查询

1 背景

HappyBase是一个开发人员友好的Python库,可与Apache HBase进行交互。 HappyBase为应用程序开发人员提供了Pythonic API与HBase交互。这些api包括:

详细的文档参考这里
happybase在scanapi中也提供了hbase thrift的Filter查询接口,但是却没有详细的Filter语法文档,在互联网上也没有找到很详细的文档。
为此,我查看了hbase的的文档,翻译了Thrift API and Filter Language部分的内容。接下来2.1介绍了happybase的scan接口,2.2为hbase的翻译内容。

2 使用Filter进行复杂的Hbase查询

2.1 happybase的scan接口

scan(row_start=None, row_stop=None, row_prefix=None, columns=None, filter=None, timestamp=None, include_timestamp=False, batch_size=1000, scan_batching=None, limit=None, sorted_columns=False, reverse=False)
其中的filter参数就是用于hbase的Filter查询。下面是一个简单的示例:

import happybase
hbase_host = ''
hbase_port = 9090
# hbase连接
conn = happybase.Connection(host=hbase_host, port=hbase_port)
table = conn.table('test')
# filter
scan_filter = "SingleColumnValueFilter('info', 'item_delivery_status', =, 'binary:1', true, true) " 
# 查询
result = table.scan(filter=scan_filter)
# 打印查询结果
for row_key, item in result:
    print(row_key)
    print(item)

2.2 Filter语法

这一部分的文字内容翻译自:hbase文档-Thrift API and Filter Language,代码为自己书写,使用时需要将host、表名、列名等信息更改为自己信息。

2.2.1 基本查询语法

"FilterName (argument, argument,... , argument)"

语法指导:

  • 首先指定过滤器的名称,后跟括号,括号中为参数列表,使用逗号分隔。
  • 如果参数是字符串, 应该使用单引号'把字符串包起来.
  • 如果参数是布尔型、整型或者操作符(如<, >!=),不能使用单引号包裹。
  • filter name 必须是一个单词,换句话说必须是除空格、引号、括号之外的ASCII 字符。
  • Filter的参数可以包含任意的ASCII字符,如果一个参数中包含单引号,那么必须使用另外一个单引号对其转义

2.2.2 多个过滤条件和逻辑运算符

二元运算符

  • AND
    同时满足两个条件
  • OR
    满足其中一个条件即可

一元运算符

  • SKIP
    For a particular row, if any of the key-values fail the filter condition, the entire row is skipped.
    -WHILE
    For a particular row, key-values will be emitted until a key-value is reached that fails the filter condition.

例子

(Filter1 AND Filter2) OR (Filter3 AND Filter4)

运算优先级

  • 括号拥有最高的优先级;
  • 一元运算符 SKIPWHILE 次之, 它们拥有相同的优先级;
  • 接下来是二元运算符。 AND 的优先级高于 OR

例子1

Filter1 AND Filter2 OR Filter
is evaluated as
(Filter1 AND Filter2) OR Filter3

例子2

Filter1 AND SKIP Filter2 OR Filter3
is evaluated as
(Filter1 AND (SKIP Filter2)) OR Filter3

2.2.3 比较运算符

  • 小于 LESS (<)
  • 小于等于 LESS_OR_EQUAL (⇐)
  • 等于 EQUAL (=)
  • 不等于 NOT_EQUAL (!=)
  • 大于等于GREATER_OR_EQUAL (>=)
  • 大于GREATER (>)
  • 无操作NO_OP (no operation)

用户需要使用这些符号 (<, ⇐, =, !=, >, >=) 表示比较运算符

2.2.4 比较器(Comparator)

  • BinaryComparator - 以字典序与特定的字节数组进行比较,使用Bytes.compareTo(byte[], byte[])
  • BinaryPrefixComparator- 前缀比较,以字典序与特定的字节数组进行比较,比较的长度仅仅是该字节数组的长度;
  • RegexStringComparator - 正则表达式比较,使用正则表达式来匹配. 仅可以使用 EQUALNOT_EQUAL 两种比较运算符;
  • SubStringComparator - 子串比较,如果给定的子字符串出现,则返回该查询结果。该比较器是大小写敏感的。仅可以使用 EQUALNOT_EQUAL 两种比较运算符。

比较器的语法是: ComparatorType:ComparatorValue

ComparatorType与comparators的对应关系如下:

  • BinaryComparator - binary
  • BinaryPrefixComparator - binaryprefix
  • RegexStringComparator - regexstring
  • SubStringComparator - substring

例子

  1. binary:abc 将匹配字典序大于 abc的数据;
  2. binaryprefix:abc 将匹配前三个字符的字典序与abc相等的数据;
  3. regexstring:ab*yz 将会根据正则表达式 ab*yz 进行匹配(该正则表达式表示:不以ab为开头和以yz为结束的数据)
  4. substring:abc123将会匹配包含子字符串 abc123 的数据

2.2.5 Filter

  • KeyOnlyFilter
    这个filter不接受任何参数,只返回所有键值对中的键和row_key(不包含值)

英文原文: This filter doesn’t take any arguments. It returns only the key component of each key-value.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "KeyOnlyFilter()"
result = table.scan(filter=scan_filter)
for item in result:
    print(item)
  • FirstKeyOnlyFilter
    该filter不接受任何的参数,只返回每一行中的第一个键值对和row_key

英文原文: This filter doesn’t take any arguments. It returns only the first key-value from each row.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "FirstKeyOnlyFilter()"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • PrefixFilter
    该filter仅仅包含一个参数-主键的前缀,返回前缀相匹配的行

英文原文: This filter takes one argument – a prefix of a row key. It returns only those key-values present in a row that starts with the specified row prefix

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "PrefixFilter('0047a')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • ColumnPrefixFilter
    该filter接受一个参数-列的前缀,仅返回列名前缀与给定参数相同的列

英文原文: This filter takes one argument – a column prefix. It returns only those key-values present in a column that starts with the specified column prefix. The column prefix must be of the form: “qualifier”.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "ColumnPrefixFilter('box')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • MultipleColumnPrefixFilter
    该filter接受一组列前缀,仅仅返回与列表中的前缀相匹配的列

英文原文: This filter takes a list of column prefixes. It returns key-values that are present in a column that starts with any of the specified column prefixes. Each of the column prefixes must be of the form: “qualifier”.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "MultipleColumnPrefixFilter('box', 'create')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • ColumnCountGetFilter
    该filter接受一个参数 - limit, 返回第一行,前limit列的数据

英文原文: This filter takes one argument – a limit. It returns the first limit number of columns in the table.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "ColumnCountGetFilter(6)"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • PageFilter
    该filter接受一个参数 -- page-size, 返回page size行数据

英文原文: This filter takes one argument – a page size. It returns page size number of rows from the table.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "PageFilter(5)"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • ColumnPaginationFilter
    该filter接受两个参数 -- limit 和 offset,它返回偏移列数后的列数限制。它为所有行执行此操作。

英文原文: This filter takes two arguments – a limit and offset. It returns limit number of columns after offset number of columns. It does this for all the rows.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "ColumnPaginationFilter(3, 7)"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • InclusiveStopFilter
    该filter接受一个参数--row key(在该row key处停止scanning),返回截止row key之前的行(包含)的所有列

英文原文: This filter takes one argument – a row key on which to stop scanning. It returns all key-values present in rows up to and including the specified row.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "InclusiveStopFilter('005c2_4530489164_10599261608')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • TimeStampsFilter
    该filter接受一组timestamps,

英文原文: This filter takes a list of timestamps. It returns those key-values whose timestamps matches any of the specified timestamps.

  • RowFilter
    该filter接受一个比较操作符(=, !=, >, <, >=, <=)和一个比较器(binary, binaryprefix, regexstring, substring)。使用比较操作符比较所有的行与比较器的匹配情况,如果返回true,则返回该行的row key和所有的列

英文原文: This filter takes a compare operator and a comparator. It compares each row key with the comparator using the compare operator and if the comparison returns true, it returns all the key-values in that row.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "RowFilter(=, 'binary:0047a_4530641731_102627717')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • FamilyFilter
    该filter接受一个比较运算符(compare operator)和一个比较器(comparator)。根据比较运算符(compare operator)把所有的列族名与比较器(comparator)进行比较,如果返回true,就返回所有行的row key和列族下的列

英文原文: This filter takes a compare operator and a comparator. It compares each column family name with the comparator using the compare operator and if the comparison returns true, it returns all the Cells in that column family.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "FamilyFilter(=, 'binary:info')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • QualifierFilter
    该filter接受一个比较运算符(compare operator)和一个比较器(comparator)。根据比较运算符(compare operator)把所有的列名(Qualifier)与比较器(comparator)进行比较,如果返回true,就返回所有行的row key和匹配的所有列

英文原文: This filter takes a compare operator and a comparator. It compares each qualifier name with the comparator using the compare operator and if the comparison returns true, it returns all the key-values in that column.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "QualifierFilter(=, 'binary:item_delivery_status')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • ValueFilter
    该filter接受一个比较运算符(compare operator)和一个比较器(comparator)。根据比较运算符(compare operator)把所有的value(Qualifier)与比较器(comparator)进行比较,如果返回true,就返回所有行的row key和所匹配的键值对

英文原文: This filter takes a compare operator and a comparator. It compares each value with the comparator using the compare operator and if the comparison returns true, it returns that key-value.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "ValueFilter(=, 'binary:2')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • DependentColumnFilter
    该filter接受两个参数--列族(fanily)和列名(qualifier)

英文原文: This filter takes two arguments – a family and a qualifier. It tries to locate this column in each row and returns all key-values in that row that have the same timestamp. If the row doesn’t contain the specified column – none of the key-values in that row will be returned.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "DependentColumnFilter('info', 'store_code')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • SingleColumnValueFilter
    该filter接受--一个列族(column family), 一个列(qualifier), 一个比较运算符(compare operator) 和一个比较器(comparator)。根据列族和列名确定的的列,把所有的值与比较器(comparator)进行比较, 如果返回true, 则输出该行和所有的列,如果指定的列不存在,那么将返回所有的行。

英文原文: This filter takes a column family, a qualifier, a compare operator and a comparator. If the specified column is not found – all the columns of that row will be emitted. If the column is found and the comparison with the comparator returns true, all the columns of the row will be emitted. If the condition fails, the row will not be emitted.

注意⚠️: 实际上,该filter还有两个参数 <filterIfColumnMissing_boolean>、<latest_version_boolean>分别表示是否过滤缺失数据的行、是否只取最近的版本

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "SingleColumnValueFilter(
    'info', 'item_delivery_status', =, 'binary:2', true, true)"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • SingleColumnValueExcludeFilter
    该过滤器接受的参数与SingleColumnValueFilter相同,与SingleColumnValueFilter不同的是,将会输出与输入条件相同的所有行,除去参数指定的列。

英文原文: This filter takes the same arguments and behaves same as SingleColumnValueFilter – however, if the column is found and the condition passes, all the columns of the row will be emitted except for the tested column value.

conn = happybase.Connection(host=TEST_HBASE_HOST)
table = conn.table('openapi:openapi_suning_purchase_order')
scan_filter = "SingleColumnValueExcludeFilter(
    'info', 'item_delivery_status', =, 'binary:2')"
result = table.scan(filter=scan_filter)
for index, item in enumerate(result):
    print(item)
  • ColumnRangeFilter

英文原文: This filter is used for selecting only those keys with columns that are between minColumn and maxColumn. It also takes two boolean variables to indicate whether to include the minColumn and maxColumn or not.

3 参考资料

1.happybase文档
2.hbase文档-Thrift API and Filter Language

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352