官方文档:https://hbase.apache.org/book.html
HBase 是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,用于存储海量的结构化或者半结构化,非结构化的数据
HBase是Hadoop的生态系统之一,是建立在Hadoop文件系统(HDFS)之上的分布式、面向列的数据库,通过利用Hadoop的文件系统提供容错能力。如果需要进行实时读写或者随机访问大规模的数据集的时候,会考虑使用HBase。
HBase作为Google Bigtable的开源实现,Google Bigtable利用GFS作为其文件存储系统类似,则HBase利用Hadoop HDFS作为其文件存储系统;Google通过运行MapReduce来处理Bigtable中的海量数据,同样,HBase利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用Chubby作为协同服务,HBase利用Zookeeper作为对应。在2010年5月,成为apache顶级项目
虽然Hadoop是一个高容错、高延时的分布式文件系统和高并发的批处理系统,但是它不适用于提供实时计算;
HBase是可以提供实时计算的分布式数据库,数据被保存在HDFS分布式文件系统上,由HDFS保证期高容错性;
但是再生产环境中,HBase是如何基于hadoop提供实时性呢?
HBase上的数据是以StoreFile(HFile)二进制流的形式存储在HDFS上block块儿中;
但是HDFS并不知道的HBase用于存储什么,它只把存储文件认为是二进制文件,也就是说,HBase的存储数据对于HDFS文件系统是透明的。
在下面的表格中,我们对HDFS与HBase进行比较:
HDFS
HBase
HDFS适于存储大容量文件的分布式文件系统。
HBase是建立在HDFS之上的数据库。
HDFS不支持快速单独记录查找。
HBase提供在较大的表快速查找
HDFS提供了高延迟批量处理;没有批处理概念。
HBase提供了数十亿条记录低延迟访问单个行记录(随机存取)。
HDFS提供的数据只能顺序访问。
HBase内部使用哈希表和提供随机接入,并且其存储索引,可将在HDFS文件中的数据进行快速查找。
Hbase--->HashMap
1、画图理解分布式是什么样子(region)
2、画图理解列式存储 拿与mysql(必须项:表+列)中的表做对比(必须项:表+列簇)
3、画图理解稀疏(rowkey)
HBase中需要根据行键、列族、列限定符和时间戳来确定一个单元格,因此,可以视为一个“四维坐标”,即[行键, 列族, 列限定符, 时间戳]
HBase通过表格的模式存储数据,每个表格由列和行组成,其中,每个列又被划分为若干个列族(colnum family),请参考下面的图:
表:HBase的数据同样是用表来组织的,表由行和列组成,列分为若干个列族,行和列的坐标交叉决定了一个单元格。
行:每个表由若干行组成,每个行有一个行键作为这一行的唯一标识。访问表中的行只有三种方式:通过单个行键进行查询、通过一个行键的区间来访问、全表扫描。
列族:一个HBase表被分组成许多“列族”的集合,它是基本的访问控制单元。
列修饰符(列限定符):列族里的数据通过列限定符(或列)来定位
单元格:在HBase表中,通过行、列族和列限定符确定一个“单元格”(cell),单元格中存储的数据没有数据类型,总被视为字节数组byte[]
时间戳:每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引
HBase将数据存放在带有标签的表中,表由行和列组成,行和列交叉确定一个单元格,单元格有版本号,版本号自动分配,为数据插入该单元格时的时间戳。单元格的内容没有数据类型,所有数据都被视为未解释的字节数组。
表格中每一行有一个行键(也是字节数组,任何形式的数据都可以表示成字符串,比如数据结构进行序列化之后),整个表根据行键的字节序来排序,所有对表的访问必须通过行键。
表中的列又划分为多个列族(column family),同一个列族的所有成员具有相同的前缀,具体的列由列修饰符标识,因此,列族和列修饰符合起来才可以表示某一列,比如:info:format、cotents:image
在创建一个表的时候,列族必须作为模式定义的一部分预先给出,而列族是支持动态扩展的,也就是列族成员可以随后按需加入。物理上,所有的列族成员一起存放在文件系统上,所以实际上说HBase是面向列的数据库,更准确的应该是面向列族,调优和存储都是在列族这个层次上进行的。一般情况下,同一个列族的成员最后具有相同的访问模式和大小特征。
总结起来,HBase表和我们熟知的RDBMS的表很像,不同之处在于:行按行键排序,列划分为列族,单元格有版本号,没有数据类型。
HBase中需要根据行键、列族、列限定符和时间戳来确定一个单元格(cell),cell中的数据是没有类型的,全部是字节码形式存贮。,因此,可以视为一个“四维坐标”,即[行键, 列族, 列限定符, 时间戳]。
对于上图这样一个HBase表,其数据坐标举例如下:
键
值
[“201505003”, “Info”, “email”, 1174184619081]
[“201505003”, “Info”, “email”, 1174184620720]
HBase自动把表水平划分为区域(Region),每个区域都是有若干连续行构成的,一个区域由所属的表、起始行、终止行(不包括这行)三个要素来表示。
一开始,一个表只有一个区域,但是随着数据的增加,区域逐渐变大,等到它超出设定的阈值大小,就会在某行的边界上进行拆分,分成两个大小基本相同的区域。然后随着数据的再增加,区域就不断的增加,如果超出了单台服务器的容量,就可以把一些区域放到其他节点上去,构成一个集群。也就是说:集群中的每个节点(Region Server)管理整个表的若干个区域。所以,我们说:区域是HBase集群上分布数据的最小单位。
HBase由三种类型的服务器以主从模式构成:
Region Server:负责数据的读写服务,用户通过与Region server交互来实现对数据的访问。
HBase HMaster:负责Region的分配及数据库的创建和删除等操作。
ZooKeeper:负责维护集群的状态(某台服务器是否在线,服务器之间数据的同步操作及master的选举等)。
HDFS的DataNode负责存储所有Region Server所管理的数据,即HBase中的所有数据都是以HDFS文件的形式存储的。出于使Region server所管理的数据更加本地化的考虑,Region server是根据DataNode分布的。HBase的数据在写入的时候都存储在本地。但当某一个region被移除或被重新分配的时候,就可能产生数据不在本地的情况。这种情况只有在所谓的compaction之后才能解决。
包含访问HBase的接口并维护cache来加快对HBase的访问
保证任何时候,集群中只有一个master
存贮所有Region的寻址入口。
实时监控Region server的上线和下线信息。并实时通知Master
存储HBase的schema和table元数据
为Region server分配region
负责Region server的负载均衡
发现失效的Region server并重新分配其上的region
管理用户对table的增删改操作
Region server维护region,处理对这些region的IO请求
Region server负责切分在运行过程中变得过大的region
HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是 HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和 region名字外,同时还包括sequence number和timestamp,timestamp是” 写入时间”,sequence number的起始值为0,或者是最近一次存入文件系 统sequence number。
HLog SequeceFile的Value是HBase的KeyValue对象,即对应HFile中的 KeyValue
HBase自动把表水平划分成多个区域(region),每个region会保存一个表里面某段连续的数据;每个表一开始只有一个region,随着数据不断插 入表,region不断增大,当增大到一个阀值的时候,region就会等分会两个新的region(裂变);
当table中的行不断增多,就会有越来越多的region。这样一张完整的表被保存在多个Regionserver上。
如图:StoreFile 以HFile格式保存在HDFS上。
1、flush刷新在HDFS上呈现究竟是怎么刷新的呢??
我们目前刚刚学习的时候,添加数据,都是一条一条的put进去,而我们在put的数据比较少(小于128M)的时候,我们put完去HDFS上并未查看到我们put的文件,这是因为数据还在内存中,也就是还在memStore中,所以要想在HDFS中查看到,我们必须手动刷新到磁盘中,这是将memStore的数据刷新到StoreFile中去,这样我们在HDFS中就可以查看到了。
2、为什么Hbase不可以使用像Mysql那样进行查询??
首先,我们应该可以感受到,我们在插入的时候,每行数据,有多少列,列名叫什么完全是我们自己定义的,之所以不支持像MySql那样对列进行查询和操作,因为不确定列的个数和名称。
3、数据最后存在HDFS上的,HDFS不支持删改,为什么Hbase就可以呢??
这里有个思想误区,的确,数据是以HFile形式存在HDFS上的,而且HDFS的确是不支持删改的,但是为什么Hbase就支持呢?首先,这里的删除并不是真正意义上的对数据进行删除,而是对数据进行打上标记,我们再去查的时,就不会查到这个打过标记的数据,这个数据Hmaster会每隔1小时清理。修改是put两次,Hbase会取最新的数据,过期数据也是这个方式被清理。
官网下载地址:https://www.apache.org/dyn/closer.lua/hbase/1.7.1/hbase-1.7.1-bin.tar.gz
启动hadoop
start-all.sh
验证
http://master:50070
启动zookeeper(三台分别启动)
zkServer.sh start
检查状态
zkServer.sh status
tar -zxvf hbase-1.4.6-bin.tar.gz
export HBASE_HOME=/usr/local/soft/hbase-1.7.1
$HBASE_HOME/bin
source /etc/profile
增加java配置
export JAVA_HOME=/usr/local/soft/jdk1.8.0_171
关闭默认zk配置(原本是注释的,放开修改false)
export HBASE_MANAGES_ZK=false
如果是伪分布式版本,增加master即可
node1
node2
scp -r hbase-1.7.1 node1:`pwd`
scp -r hbase-1.7.1 node2:`pwd`
start-hbase.sh
http://master:16010
hbase日志文件所在的目录: /usr/local/soft/hbase-1.7.1/logs
stop-hbase.sh
启动顺序
Hadoop及hbase集群启动顺序 zookeepeer -> hadoop -> hbase
停止顺序
Hadoop及hbase集群关闭顺序 hbase -> hadoop -> zookeepeer
1)杀死进程
2)stop-hbase.sh
hdfs dfs -rmr /hbase
zkCli.sh
rmr /hbase
start-hbase.sh
yum install ntp -y
ntpdate -u time.windows.com
命名
描述
语法
help ‘命名名’
查看命令的使用描述
help ‘命令名’
whoami
我是谁
whoami
version
返回hbase版本信息
version
status
返回hbase集群的状态信息
status
table_help
查看如何操作表
table_help
create
创建表
create ‘表名’, ‘列族名1’, ‘列族名2’, ‘列族名N’
alter
修改列族
添加一个列族:alter ‘表名’, ‘列族名’ 删除列族:alter ‘表名’, {NAME=> ‘列族名’, METHOD=> ‘delete’}
describe
显示表相关的详细信息
describe ‘表名’
list
列出hbase中存在的所有表
list
exists
测试表是否存在
exists ‘表名’
put
添加或修改的表的值
put ‘表名’, ‘行键’, ‘列族名’, ‘列值’ put ‘表名’, ‘行键’, ‘列族名:列名’, ‘列值’
scan
通过对表的扫描来获取对用的值
scan ‘表名’ 扫描某个列族: scan ‘表名’, {COLUMN=>‘列族名’} 扫描某个列族的某个列: scan ‘表名’, {COLUMN=>‘列族名:列名’} 查询同一个列族的多个列: scan ‘表名’, {COLUMNS => [ ‘列族名1:列名1’, ‘列族名1:列名2’, …]}
get
获取行或单元(cell)的值
get ‘表名’, ‘行键’ get ‘表名’, ‘行键’, ‘列族名’
count
统计表中行的数量
count ‘表名’
incr
增加指定表行或列的值
incr ‘表名’, ‘行键’, ‘列族:列名’, 步长值
get_counter
获取计数器
get_counter ‘表名’, ‘行键’, ‘列族:列名’
delete
删除指定对象的值(可以为表,行,列对应的值,另外也可以指定时间戳的值)
删除列族的某个列: delete ‘表名’, ‘行键’, ‘列族名:列名’
deleteall
删除指定行的所有元素值
deleteall ‘表名’, ‘行键’
truncate
重新创建指定表
truncate ‘表名’
enable
使表有效
enable ‘表名’
is_enabled
是否启用
is_enabled ‘表名’
disable
使表无效
disable ‘表名’
is_disabled
是否无效
is_disabled ‘表名’
drop
删除表
drop的表必须是disable的 disable ‘表名’ drop ‘表名’
shutdown
关闭hbase集群(与exit不同)
tools
列出hbase所支持的工具
exit
退出hbase shell
HBase Shell 是官方提供的一组命令,用于操作HBase。如果配置了HBase的环境变量了,就可以知己在命令行中输入hbase shell 命令进入命令行。
hbase shell
在hbase中如果输入错误,按住ctrl+退格 才能删除
可以通过
help '命名名称'
来查看命令行的具体使用,包括命令的作用和用法。 通过help ‘hbase’ 命名来查看hbase shell 支持的所有命令,hbase将命令进行分组,其中ddl、dml使用较多。
help 'list'
注意:创建表时只需要指定列族名称,不需要指定列名。
# 语法
create '表名', {NAME => '列族名1'}, {NAME => '列族名2'}, {NAME => '列族名3'}
create '表名', '列族名1', '列族名2', '列族名3'
create '表名', {NAME => '列族名1', VERSIONS => 版本号, TTL => 过期时间, BLOCKCACHE => true}
create 'tbl_user', 'info', 'detail'
create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}
# 语法
alter '表名', '列族名'
alter 'tbl_user', 'address'
# 语法
alter '表名', {NAME=> '列族名', METHOD=> 'delete'}
alter 'tbl_user', {NAME=> 'address', METHOD=> 'delete'}
可以修改列族的VERSIONS、IN_MEMORY
# 修改f1列族的版本为5
alter 't1', NAME => 'f1', VERSIONS => 5
alter 't1', 'f1', {NAME => 'f2', IN_MEMORY => true}, {NAME => 'f3', VERSIONS => 5}
alter 't1', MAX_FILESIZE => '134217728'
# 语法
describe '表名'
describe 'tbl_user'
# 语法
exists '表名'
exists 'tbl_user'
通过enable和disable来启用/禁用这个表,相应的可以通过is_enabled和is_disabled来检查表是否被禁用。
# 语法
enable '表名'
is_enabled '表名'
disable '表名'
is_disabled '表名'
disable 'tbl_user'
is_disabled 'tbl_user'
enable 'tbl_user'
is_enabled 'tbl_user'
.
匹配除“\n”和"\r"之外的任何单个字符
*
匹配前面的子表达式任意次
# 匹配以t开头的表名
disable_all 't.*'
disable_all 'ns:t.*'
disable_all 'ns:.*'
enable_all 't.*'
enable_all 'ns:t.*'
enable_all 'ns:.*'
需要先禁用表,然后再删除表,启用的表是不允许删除的
# 语法
disable '表名'
drop '表名'
disable 'tbl_user'
drop 'tbl_user'
直接删除报错:
先禁用后删除
drop_all 't.*'
drop_all 'ns:t.*'
drop_all 'ns:.*'
通过 var = get_table ‘表名’ 赋值给一个变量对象,然后对象.来调用,就像面向对象编程一样,通过对象.方法来调用,这种方式在操作某个表时就不必每次列举表名了。
locate_region '表名', '行键'
过滤器用于get和scan命令中作为筛选数据的条件,类型关系型数据库中的where的作用
hbase中没有数据库的概念 , 可以使用namespace来达到数据库分类别管理表的作用
describe_namespace 'default'
list_namespace_tables 'default'
list_namespace_tables 'hbase'
create_namespace 'bigdata17'
drop_namespace '命名空间名称'
# 语法
put '表名', '行键', '列族名', '列值'
put '表名', '行键', '列族名:列名', '列值'
create 'users', 'info', 'detail', 'address'
put 'users', 'mengday', 'info:id', '1'
put 'users', 'mengday', 'info:name', '张三'
put 'users', 'mengday', 'info:age', '28'
put 'users', 'mengday', 'detail:birthday', '1990-06-26'
put 'users', 'mengday', 'detail:email', 'abc@163.com'
put 'users', 'mengday', 'detail:create_time', '2019-03-04 14:26:10'
put 'users', 'mengday', 'address', '上海市'
put 'users', 'vbirdbest', 'info:id', '2'
put 'users', 'vbirdbest', 'info:name', '李四'
put 'users', 'vbirdbest', 'info:age', '27'
put 'users', 'vbirdbest', 'detail:birthday', '1990-06-27'
put 'users', 'vbirdbest', 'detail:email', 'xxx@gmail.com'
put 'users', 'vbirdbest', 'detail:create_time', '2019-03-05 14:26:10'
put 'users', 'vbirdbest', 'address', '北京市'
put 'users', 'xiaoming', 'info:id', '3'
put 'users', 'xiaoming', 'info:name', '王五'
put 'users', 'xiaoming', 'info:age', '26'
put 'users', 'xiaoming', 'detail:birthday', '1990-06-28'
put 'users', 'xiaoming', 'detail:email', 'xyz@qq.com'
put 'users', 'xiaoming', 'detail:create_time', '2019-03-06 14:26:10'
put 'users', 'xiaoming', 'address', '杭州市'
# 语法
scan '表名'
scan 'users'
扫描整个列簇
# 语法
scan '表名', {COLUMN=>'列族名'}
scan 'users', {COLUMN=>'info'}
扫描整个列簇的某个列
# 语法
scan '表名', {COLUMN=>'列族名:列名'}
scan 'users', {COLUMN=>'info:age'}
# 语法
get '表名', '行键'
get 'users', 'xiaoming'
根据某一行某列族的数据
# 语法
get '表名', '行键', '列族名'
get 'users', 'xiaoming', 'info'
# 创建表,c1版本为4, 元数据mykey=myvalue
hbase(main):009:0> create 't1', {NAME => 'c1', VERSIONS => 4}, METADATA => { 'mykey' => 'myvalue' }
0 row(s) in 2.2810 seconds
=> Hbase::Table - t1
hbase(main):010:0> alter 't1', 'c2', 'c3'
Updating all regions with the new schema…
1/1 regions updated.
Done.
Updating all regions with the new schema…
1/1 regions updated.
Done.
0 row(s) in 3.8320 seconds
hbase(main):011:0> put 't1', 'r1', 'c1', 'v1'
0 row(s) in 0.1000 seconds
hbase(main):012:0> put 't1', 'r1', 'c1', 'v11'
0 row(s) in 0.0180 seconds
hbase(main):013:0> put 't1', 'r1', 'c1', 'v111'
0 row(s) in 0.0140 seconds
hbase(main):014:0> put 't1', 'r1', 'c1', 'v1111'
0 row(s) in 0.0140 seconds
hbase(main):015:0> put 't1', 'r1', 'c2', 'v2'
0 row(s) in 0.0140 seconds
hbase(main):016:0> put 't1', 'r1', 'c3', 'v3'
0 row(s) in 0.0210 seconds
hbase(main):017:0> get 't1', 'r1'
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
c2: timestamp=1552819392398, value=v2
c3: timestamp=1552819398244, value=v3
3 row(s) in 0.0550 seconds
hbase(main):018:0> get 't1', 'r1', {TIMERANGE => [1552819392398, 1552819398244]}
COLUMN CELL
c2: timestamp=1552819392398, value=v2
1 row(s) in 0.0090 seconds
hbase(main):019:0> get 't1', 'r1', {COLUMN => 'c1'}
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
1 row(s) in 0.0160 seconds
hbase(main):020:0> get 't1', 'r1', {COLUMN => ['c1', 'c2', 'c3']}
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
c2: timestamp=1552819392398, value=v2
c3: timestamp=1552819398244, value=v3
3 row(s) in 0.0170 seconds
hbase(main):021:0> get 't1', 'r1', {COLUMN => 'c1', VERSIONS => 4}
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
c1: timestamp=1552819376343, value=v111
c1: timestamp=1552819368993, value=v11
c1: timestamp=1552819362975, value=v1
4 row(s) in 0.0180 seconds
hbase(main):027:0* get 't1', 'r1', {COLUMN => 'c1', VERSIONS => 3}
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
c1: timestamp=1552819376343, value=v111
c1: timestamp=1552819368993, value=v11
3 row(s) in 0.0090 seconds
hbase(main):022:0> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => 1552819376343}
COLUMN CELL
c1: timestamp=1552819376343, value=v111
1 row(s) in 0.0170 seconds
hbase(main):023:0> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => 1552819376343, VERSIONS => 4}
COLUMN CELL
c1: timestamp=1552819376343, value=v111
1 row(s) in 0.0130 seconds
hbase(main):024:0> get 't1', 'r1', {FILTER => "ValueFilter(=, 'binary:v2')"}
COLUMN CELL
c2: timestamp=1552819392398, value=v2
1 row(s) in 0.0510 seconds
hbase(main):025:0> get 't1', 'r1', {COLUMN => 'c1', ATTRIBUTES => {'mykey'=>'myvalue'}}
COLUMN CELL
c1: timestamp=1552819382575, value=v1111
1 row(s) in 0.0100 seconds
# 语法
delete '表名', '行键', '列族名:列名'
delete 'users','xiaoming','info:age'
create 'tbl_test', 'columnFamily1'
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value1'
put 'tbl_test', 'rowKey1', 'columnFamily1:column2', 'value2'
delete 'tbl_test', 'rowKey1', 'columnFamily1:column1'
# 语法
deleteall '表名', '行键'
deleteall 'users', 'xiaoming'
先disable表,然后再drop表,最后重新create表
truncate '表名'
# 语法
incr '表名', '行键', '列族:列名', 步长值
incr 'tbl_user', 'xiaohong', 'info:age', 1
# 点击量:日、周、月
create 'counters', 'daily', 'weekly', 'monthly'
incr 'counters', '20110101', 'daily:hits', 1
incr 'counters', '20110101', 'daily:hits', 1
get_counter 'counters', '20110101', 'daily:hits'
# 语法
scan '表名', {COLUMNS => [ '列族名1:列名1', '列族名1:列名2', …]}
scan 'tbl_user', {COLUMNS => [ 'info:id', 'info:age']}
# 语法
scan '表名',{TIMERANGE=>[timestamp1, timestamp2]}
scan 'tbl_user',{TIMERANGE=>[1551938004321, 1551938036450]}
默认情况下一个列只能存储一个数据,后面如果修改数据就会将原来的覆盖掉,可以通过指定VERSIONS时HBase一列能存储多个值。
create 'tbl_test', 'columnFamily1'
describe 'tbl_test'
alter 'tbl_test', { NAME=>'columnFamily1', VERSIONS=>3 }
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value1'
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value2'
put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value3'
get 'tbl_test','rowKey1','columnFamily1:column1'
get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>3}
get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>2}
ROWKEY起始行。会先根据这个key定位到region,再向后扫描
# 语法
scan '表名', { STARTROW => '行键名'}
scan 'tbl_user', { STARTROW => 'vbirdbest'}
# 语法
scan '表名', { STOPROW => '行键名'}
scan 'tbl_user', { STOPROW => 'xiaoming'}
# 语法
scan '表名', { LIMIT => 行数}
scan 'tbl_user', { LIMIT => 2 }
过滤器之间可以使用AND、OR连接多个过滤器。
# 语法:binary 等于某个值
scan '表名', FILTER=>"ValueFilter(=,'binary:列值')"
scan '表名', FILTER=>"ValueFilter(=,'substring:列值')"
scan 'tbl_user', FILTER=>"ValueFilter(=, 'binary:26')"
scan 'tbl_user', FILTER=>"ValueFilter(=, 'substring:6')"
# 语法 substring:包含某个值
scan '表名', FILTER=>"ColumnPrefixFilter('列名前缀')"
# 示例
scan 'tbl_user', FILTER=>"ColumnPrefixFilter('birth')"
# 通过括号、AND和OR的条件组合多个过滤器
scan 'tbl_user', FILTER=>"ColumnPrefixFilter('birth') AND ValueFilter(=,'substring:26')"
Table中的所有行都是按照row key的字典排序的
手机扫一扫
移动阅读更方便
你可能感兴趣的文章