团队内部要分享HBase的知识,以前研究了一段时间,知识比较零散,这一次就系统化的整理一番,以后在想到Hbase的时候,看着一篇就够了。html
Hbase是一种NoSQL数据库,这意味着它不像传统的RDBMS数据库那样支持SQL做为查询语言。Hbase是一种分布式存储的数据库,技术上来说,它更像是分布式存储而不是分布式数据库,它缺乏不少RDBMS系统的特性,好比列类型,辅助索引,触发器,和高级查询语言等待。那Hbase有什么特性呢?以下:java
Hbase不适合解决全部的问题:node
Hbase在单机环境也能运行,可是请在开发环境的时候使用。web
不过在公司使用的时候,通常不使用原生的Hbase API,使用原生的API会致使访问不可监控,影响系统稳定性,以至于版本升级的不可控。shell
HMaster是Master Server的实现,负责监控集群中的RegionServer实例,同时是全部metadata改变的接口,在集群中,一般运行在NameNode上面,这里有一篇更细的HMaster介绍数据库
HRegionServer是RegionServer的实现,服务和管理Regions,集群中RegionServer运行在DataNodeapache
Regions,表明table,Region有多个Store(列簇),Store有一个Memstore和多个StoreFiles(HFiles),StoreFiles的底层是Block。vim
在Hbase中,表被分割成多个更小的块而后分散的存储在不一样的服务器上,这些小块叫作Regions,存放Regions的地方叫作RegionServer。Master进程负责处理不一样的RegionServer之间的Region的分发。在Hbase实现中HRegionServer和HRegion类表明RegionServer和Region。HRegionServer除了包含一些HRegions以外,还处理两种类型的文件用于数据存储缓存
MasterProcWAL:HMaster记录管理操做,好比解决冲突的服务器,表建立和其它DDLs等操做到它的WAL文件中,这个WALs存储在MasterProcWALs目录下,它不像RegionServer的WALs,HMaster的WAL也支持弹性操做,就是若是Master服务器挂了,其它的Master接管的时候继续操做这个文件。bash
WAL记录全部的Hbase数据改变,若是一个RegionServer在MemStore进行FLush的时候挂掉了,WAL能够保证数据的改变被应用到。若是写WAL失败了,那么修改数据的完整操做就是失败的。
WAL的配置:
// 启用multiwal
<property>
<name>hbase.wal.provider</name>
<value>multiwal</value>
</property>
复制代码
HFile是Hbase在HDFS中存储数据的格式,它包含多层的索引,这样在Hbase检索数据的时候就不用彻底的加载整个文件。索引的大小(keys的大小,数据量的大小)影响block的大小,在大数据集的状况下,block的大小设置为每一个RegionServer 1GB也是常见的。
探讨数据库的数据存储方式,其实就是探讨数据如何在磁盘上进行有效的组织。由于咱们一般以如何高效读取和消费数据为目的,而不是数据存储自己。
起初,HFile中并无任何Block,数据还存在于MemStore中。
Flush发生时,建立HFile Writer,第一个空的Data Block出现,初始化后的Data Block中为Header部分预留了空间,Header部分用来存放一个Data Block的元数据信息。
然后,位于MemStore中的KeyValues被一个个append到位于内存中的第一个Data Block中:
注:若是配置了Data Block Encoding,则会在Append KeyValue的时候进行同步编码,编码后的数据再也不是单纯的KeyValue模式。Data Block Encoding是HBase为了下降KeyValue结构性膨胀而提供的内部编码机制。
这一次来部署一个单机版的Hbase,单独的Hbase daemon(Master,RegionServers和ZooKeeper)运行在同一个JVM进程中,而后持久化存储到文件系统中。这是最简单的部署,可是却能帮助咱们更好的理解Hbase。安装完成以后,咱们在演示一下hbase命令行的用法。
yum install java-1.8.0-openjdk* -y
复制代码
tar -xf hbase-1.2.8-bin.tar.gz
cd hbase-1.2.8
复制代码
vim conf/hbase-env.sh
// 注意这个是在CentOS上的java位置
export JAVA_HOME=/etc/alternatives/java_sdk_1.8.0/
复制代码
我将hbase的目录放在hadoop用户家目录的hbase目录下。咱们不用事先建立好hbase的data目录,hbase会自动帮咱们建立好的,若是已经存在了data目录,hbase会将存在的目录进行迁移。
useradd -s /sbin/nologin -m hadoop
vim conf/hbase-site.xml
<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///home/hadoop/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/hadoop/zookeeper</value>
</property>
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
<description>
Controls whether HBase will check for stream capabilities (hflush/hsync).
Disable this if you intend to run on LocalFileSystem, denoted by a rootdir
with the 'file://' scheme, but be mindful of the NOTE below.
WARNING: Setting this to false blinds you to potential data loss and
inconsistent system state in the event of process and/or node failures. If
HBase is complaining of an inability to use hsync or hflush it's most likely not a false positive. </description> </property> </configuration> 复制代码
./bin/start-hbase.sh
复制代码
若是启动以后,能够打开http://localhost:16010查看Hbase的Web UI
咱们能够先用Hbase提供的命令行工具,位于hbase的/bin/目录下
./hbase shell
复制代码
>help
复制代码
hbase(main):003:0> create 'test', 'cf'
0 row(s) in 1.6320 seconds
=> Hbase::Table - test
复制代码
其他的命令能够自行尝试
退出shell,使用quit
这里演示了下单机版的hbase如何安装,了解hbase shell的基本用法,关于Hbase更深刻的东西,能够了解下官方文档。
在Hbase中,有一些术语须要提早了解。以下:
HBase 是一个稀疏的、分布式、持久、多维、排序的映射,它以行键(row key),列键(column key)和时间戳(timestamp)为索引。
Hbase在存储数据的时候,有两个SortedMap,首先按照rowkey进行字典排序,而后再对Column进行字典排序。
create 'user','info','ship';
put 'user', '524382618264914241', 'info:name', 'zhangsan'
put 'user', '524382618264914241', 'info:age',30
put 'user', '524382618264914241', 'info:height',168
put 'user', '524382618264914241', 'info:weight',168
put 'user', '524382618264914241', 'info:phone','13212321424'
put 'user', '524382618264914241', 'ship:addr','beijing'
put 'user', '524382618264914241', 'ship:email','sina@sina.com'
put 'user', '524382618264914241', 'ship:salary',3000
put 'user', '224382618261914241', 'info:name', 'lisi'
put 'user', '224382618261914241', 'info:age',24
put 'user', '224382618261914241', 'info:height',158
put 'user', '224382618261914241', 'info:weight',128
put 'user', '224382618261914241', 'info:phone','13213921424'
put 'user', '224382618261914241', 'ship:addr','chengdu'
put 'user', '224382618261914241', 'ship:email','qq@sina.com'
put 'user', '224382618261914241', 'ship:salary',5000
put 'user', '673782618261019142', 'info:name', 'zhaoliu'
put 'user', '673782618261019142', 'info:age',19
put 'user', '673782618261019142', 'info:height',178
put 'user', '673782618261019142', 'info:weight',188
put 'user', '673782618261019142', 'info:phone','17713921424'
put 'user', '673782618261019142', 'ship:addr','shenzhen'
put 'user', '673782618261019142', 'ship:email','126@sina.com'
put 'user', '673782618261019142', 'ship:salary',8000
put 'user', '813782218261011172', 'info:name', 'wangmazi'
put 'user', '813782218261011172', 'info:age',19
put 'user', '813782218261011172', 'info:height',158
put 'user', '813782218261011172', 'info:weight',118
put 'user', '813782218261011172', 'info:phone','12713921424'
put 'user', '813782218261011172', 'ship:addr','xian'
put 'user', '813782218261011172', 'ship:email','139@sina.com'
put 'user', '813782218261011172', 'ship:salary',10000
put 'user', '510824118261011172', 'info:name', 'yangyang'
put 'user', '510824118261011172', 'info:age',18
put 'user', '510824118261011172', 'info:height',188
put 'user', '510824118261011172', 'info:weight',138
put 'user', '510824118261011172', 'info:phone','18013921626'
put 'user', '510824118261011172', 'ship:addr','shanghai'
put 'user', '510824118261011172', 'ship:email','199@sina.com'
put 'user', '510824118261011172', 'ship:salary',50000
复制代码
只要是数据库都存在,模式设计的问题,关系型中有模式设计的范式,Hbase做为列式存储数据库,其模式设计也很是重要。
设计时须要关注的属性,如何设计这些属性等
属性 | Hbase | RDBMS |
---|---|---|
数据类型 | 只有字符串 | 丰富的数据类型 |
数据操做 | 增删改查,不支持join | 各类各样的函数与表链接 |
存储模式 | 基于列式存储 | 基于表结构和行式存储 |
数据保护 | 更新后仍然保留旧版本 | 替换 |
可伸缩性 | 轻易增长节点 | 须要中间层,牺牲性能 |
Hbase关键概念:表,rowkey,列簇,时间戳
关键部分,直接关系到后续服务的访问性能。若是行健设计不合理,后续查询服务效率会成倍的递减。
列簇是一些列的集合,一个列簇的成员有相同的前缀,以冒号(:)做为分隔符。
如今Hbase不能很好处理2~3个以上的列簇,因此尽量让列簇少一些,若是表有多个列簇,列簇A有100万行数据,列簇B有10亿行,那么列簇A会分散到不少的Region致使扫描列簇A的时候效率底下。
列簇名的长度要尽可能小,一个为了节省空间,另外加快效率,好比d表示data,v表示value
> create 'mytable',{NAME => 'cf1', BLOCKSIZE => '65536'}
复制代码
> create 'mytable',{NAME => 'cf1', BLOCKCACHE => 'FALSE'}
复制代码
> create 'mytable',{NAME => 'cf1', COMPRESSION => 'SNAPPY'}
复制代码
Hbase表设计是和需求相关的,可是遵照表设计的一些硬性指标对性能的提高仍是颇有帮助的,这里整理了一些设计时用到的要点。
Hbase有多种不一样的客户端,如REST客户端,Thift客户端,ORM框架Kundera等等。 Hbase也提供了Java的API来操做表与列簇等信息,它的shell就是对Java的API作了一层封装。
Hbase的Java API提供了不少高级的特性:
咱们仍是直接看代码这样理解的更容易
Hbase的客户端版本不一致实验结果很容易出现问题,尽可能采用一样的版本。由于服务端实验的是Hbase0.98,客户端也用0.98,另外因为Hadoop 2.x的版本现对于1.x作了很大的提高,建议采用Hbase-hadoop 2.x的客户端。
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>0.98.24-hadoop2</version>
</dependency>
复制代码
直接新建HTable("tableName"),可是这种每次建立表的时候由于都要查询.meta表,来判断表是否是存在,致使建立表的过程会有点慢,因此不建议每一个请求都建立一个Htable
使用HTablePool,它和HTable的建立方式很像,可是若是采用链接池的话,它就不会给每一个请求都单首创建一个Htable了。
在建立Htable或者HtablePool的时候均可以指定更详细的配置信息。
HTablePool hTablePool = new HTablePool();
hTablePool.getTable("user");
复制代码
rowkey是表明Hbase中表的惟一一个行,同时像列簇 ,时间戳等用来定位表中的部分数据,Java的API对Hbas的CURD提供了以下的类:
咱们详细的讨论几个类,剩余的能够触类旁通。
当写请求收到的时候,默认数据同步的写到Hlog中和MemStore,同时在两个地方写是为了保证数据的持久性,Memstore最终会持久化到磁盘中的Hfile中。每次MemStore进行Flush的时候,就会建立一个新的Hfile。
Put类用于向Hbase的表中存储数据,存储数据时,Put的实例必需要指定Rowkey
建立完Put实例后,再向其中添加数据
public void put() throws IOException {
// 获取默认的配置
Configuration conf = HBaseConfiguration.create();
// 获取Table实例
HTable table = new HTable(conf, "tab1");
// 建立Put实例,而且指定rowKey
Put put = new Put(Bytes.toBytes("row-1"));
// 添加一个 column,值为 "Hello",在 "cf1:greet" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("greet"), Bytes.toBytes("Hello"));
// 添加一个 column,值为 "John",在 "cf1:person" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("person"), Bytes.toBytes("John"));
table.put(put);
table.close();
}
复制代码
数据也能够批量的进行插入:
// table对象能够传入List参数 table.put(final List puts)
执行结果:
Hbase使用LRU缓存读取数据。Htable对象使用下面的方法读取数据
而Get实例的构造方法和Put很像,构造方法要指定一个rowkey。
若是要查找特定的cell,就是特定列的数据,能够采用额外的方法进行更加精细的调控。
看一下以下的案例代码:
public void get() throws IOException {
// 获取默认的配置
Configuration conf = HBaseConfiguration.create();
// 获取Table实例
HTable table = new HTable(conf, "tab1");
// 建立Put实例,而且指定rowKey
Get get = new Get(Bytes.toBytes("row-1"));
//
get.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
// 添加一个 column,值为 "John",在 "cf1:person" 列中
Result result = table.get(get);
byte[] value = result.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
System.out.println("获取到的值" + new String(value));
table.close();
}
复制代码
执行结果
更新数据与写数据基本一致,只是在Put实例赋值的时候,在相同的列上设置不一样的值,操做的时候就会更新为新的值。
代码以下:
public void update() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 获取Table实例
HTable table = new HTable(conf, "tab1");
// 建立Put实例,而且指定rowKey
Put put = new Put(Bytes.toBytes("row-1"));
// 添加一个 column,值为 "Hello",在 "cf1:greet" 列中
put.add(Bytes.toBytes("cf1"), Bytes.toBytes("greet"), Bytes.toBytes("Good Morning"));
// 添加一个 column,值为 "John",在 "cf1:person" 列中
// put.add(Bytes.toBytes("cf1"), Bytes.toBytes("person"), Bytes.toBytes("John"));
table.put(put);
table.close();
}
复制代码
执行结果:
Delete命令只是标记当前的数据为删除状态,而不是马上的删除,也就是先进行逻辑删除。实际上的删除是在Hfile进行压缩的时候,这些被标记的记录就会被删除掉。
Delete对象与Put和Get也很像
构造Delete实例
若是想要进行更加详细的指定,能够再指定具体的列等信息
看下面的案例代码:
public void delete() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 获取Table实例
HTable table = new HTable(conf, "tab1");
// 建立Delete实例,而且指定rowKey
Delete delete = new Delete(Bytes.toBytes("row-1"));
// 删除 column "cf1:greet"
delete.deleteColumn(Bytes.toBytes("cf1"), Bytes.toBytes("greet"));
table.delete(delete);
table.close();
}
复制代码
执行结果:连续执行两次删除
一个系统上线以后,开发和调优将一直贯穿系统的生命周期中,HBase也不列外。这里主要说一些Hbase的调优
做为NoSQL数据库,增删改查是其最基本的功能,其中查询是最经常使用的一项。
HBase中Scan查询能够设置缓存,方法是setCaching(),这样能够有效的减小服务端与客户端的交互,更有效的提高扫描查询的性能。
/** * Set the number of rows for caching that will be passed to scanners. * If not set, the default setting from {@link HTable#getScannerCaching()} will apply. * Higher caching values will enable faster scanners but will use more memory. * @param caching the number of rows for caching * 设置scanners缓存的行数 */
public void setCaching(int caching) {
this.caching = caching;
}
复制代码
当使用Scan或者GET获取大量的行时,最好指定所须要的列,由于服务端经过网络传输到客户端,数据量太大多是瓶颈。若是能有效过滤部分数据,能很大程度的减小网络I/O的花费。
/** * Get all columns from the specified family. * <p> * Overrides previous calls to addColumn for this family. * @param family family name * @return this * 获取指定列簇的全部列 */
public Scan addFamily(byte [] family) {
familyMap.remove(family);
familyMap.put(family, null);
return this;
}
/** * Get the column from the specified family with the specified qualifier. * <p> * Overrides previous calls to addFamily for this family. * @param family family name * @param qualifier column qualifier * @return this * 获取指定列簇的特定列 */
public Scan addColumn(byte [] family, byte [] qualifier) {
NavigableSet<byte []> set = familyMap.get(family);
if(set == null) {
set = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
}
if (qualifier == null) {
qualifier = HConstants.EMPTY_BYTE_ARRAY;
}
set.add(qualifier);
familyMap.put(family, set);
return this;
}
复制代码
通常用: scan.addColumn(...)
若是在使用table.getScanner以后,忘记关闭该类,它会一直和服务端保持链接,资源没法释放,从而致使服务端的某些资源不可用。
因此在用完以后,须要执行关闭操做,这点与JDBS操做MySQL相似
scanner.close()
若是批量进行全表扫描,默认是有缓存的,若是此时有缓存,会下降扫描的效率。
scan.setCacheBlocks(true|false);
对于常常读到的数据,建议使用默认值,开启块缓存
对于频繁查询HBase的应用场景,能够考虑在应用程序和Hbase之间作一层缓存系统,新的查询先去缓存查,缓存没有再去查Hbase。
写也是Hbase常有的操做之一,而且Hbase在写入操做上有着其余NoSQL没法比拟的优点,下面讲如何优化写入操做
通常为了保证系统的高可用性,WAL日志默认是开启状态,WAL主要用于灾难恢复的,若是应用能够容忍必定的数据丢失风险,能够在写数据的时候,关闭写WAL。
风险: 当RegionServer宕机时,写入的数据出现丢失,且没法恢复
Htable有一个属性是AutoFlush,该属性用于支持客户端的批量更新,默认是true,当客户端每收到一条数据,马上发送到服务端,若是设置为false,当客户端提交put请求时候,先将该请求在客户端缓存,到达阈值的时候或者执行hbase.flushcommits(),才向RegionServer提交请求。
风险 在请求未发送到RegionServer以前客户端崩溃,数据也会丢失
table.setAutoFlush(false);
table.setWriteBufferSize( 12 * 1024 * 1024 );
复制代码
通常表刚开始只有一个Region,插入该表的数据都会保存在此Region中,插入该表的全部塑化剂都会保存在该Region中,当到达必定的阈值时,才发生分裂。 这样开始时刻针对该表的写操做都集中在某台服务器上,形成这台服务器的压力很紧张,同时对整个集群资源的浪费
建议刚开始的时候预建立Region,可使用Hbase自带的RegionSplitter
默认写入操做,首先写入WAL,而且在1S内写入HDFS,这个时间默认是1S,能够经过参数配置
hbase.regionserver.optionallogflushinterval
能够配置大一点的值,好比5s,这段时间数据会保留在内存中,直到RegionServer周期性的执行flush操做。
Scan是操做Hbase中很是经常使用的一个操做,虽然前面的Hbase API操做简单的介绍了Scan的操做,但不够详细,因为Scan很是经常使用,关于其详细的整理也是颇有必要的。
HBase中的数据表经过划分红一个个的Region来实现数据的分片,每个Region关联一个RowKey的范围区间,而每个Region中的数据,按RowKey的字典顺序进行组织。
正是基于这种设计,使得HBase可以轻松应对这类查询:"指定一个RowKey的范围区间,获取该区间的全部记录", 这类查询在HBase被称之为Scan。
1 . 构建Scan,指定startRow与stopRow,若是未指定的话会进行全表扫描 2 . 获取ResultScanner 3 . 遍历查询结果 4 . 关闭ResultScanner
public void stringFilter() throws IOException {
Configuration conf = HBaseConfiguration.create();
// 获取Table实例
HTable table = new HTable(conf, "user");
// 构建Scan
Scan scan = new Scan();
scan = scan.setStartRow(Bytes.toBytes("startRowxxx")).setStopRow(Bytes.toBytes("StopRowxxx"));
RowFilter filter = new RowFilter(
CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("224382618261914241"))
);
scan.setFilter(filter);
// 获取resultScanner
ResultScanner scanner = table.getScanner(scan);
Result result = null;
// 处理结果
while ((result = scanner.next()) != null) {
byte[] value = result.getValue(Bytes.toBytes("ship"), Bytes.toBytes("addr"));
if (value == null || value.length == 0) {
continue;
}
System.out.println(
new String(value)
);
System.out.println("hello World");
}
// 关闭ResultScanner
scanner.close();
table.close();
}
复制代码
其它的设置参数
下面的示例代码设定了一次读取回来的Results数量为100:
scan.setCaching(100);
复制代码
Client每一次往RegionServer发送scan请求,都会批量拿回一批数据(由Caching决定过了每一次拿回的Results数量),而后放到本次的Result Cache中:
应用每一次读取数据时,都是从本地的Result Cache中获取的。若是Result Cache中的数据读完了,则Client会再次往RegionServer发送scan请求获取更多的数据。
下面的示例代码设定了每个Result中的列的数量的限制值为3:
scan.setBatch(3);
复制代码
该参数适用于一行数据过大的场景,这样,一行数据被请求的列会被拆成多个Results返回给Client。
举例说明以下:
假设一行数据中共有十个列: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09, Col10} 假设Scan中设置的Batch为3,那么,这一行数据将会被拆成4个Results返回:
Result1 -> {Col01,Col02,Col03}
Result2 -> {Col04,Col05,Col06}
Result3 -> {Col07,Col08,Col09}
Result4 -> {Col10}
复制代码
关于Caching参数,咱们说明了是Client每一次从RegionServer侧获取到的Results的数量,上例中,一行数据被拆成了4个Results,这将会致使Caching中的计数器被减了4次。结合Caching与Batch,咱们再列举一个稍复杂的例子:
假设,Scan的参数设置以下:
final byte[] start = Bytes.toBytes("Row1"); final byte[] stop = Bytes.toBytes("Row5"); Scan scan = new Scan(); scan.withStartRow(start).withStopRow(stop); scan.setCaching(10); scan.setBatch(3);
待读取的数据RowKey与所关联的列集以下所示:
Row1: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
Row2: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10,Col11}
Row3: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
再回顾一下Caching与Batch的定义:
Caching: 影响一次读取返回的Results数量。
Batch: 限定了一个Result中所包含的列的数量,若是一行数据被请求的列的数量超出Batch限制,那么这行数据会被拆成多个Results。
那么, Client往RegionServer第一次请求所返回的结果集以下所示:
Result1 -> Row1: {Col01,Col02,Col03} Result2 -> Row1: {Col04,Col05,Col06} Result3 -> Row1: {Col07,Col08,Col09} Result4 -> Row1: {Col10} Result5 -> Row2: {Col01,Col02,Col03} Result6 -> Row2: {Col04,Col05,Col06} Result7 -> Row2: {Col07,Col08,Col09} Result8 -> Row2: {Col10,Col11} Result9 -> Row3: {Col01,Col02,Col03} Result10 -> Row3: {Col04,Col05,Col06}
同SQL语法中的limit子句,限制一次Scan操做所获取的行的总量:
scan.setLimit(10000);
注意:Limit参数是在2.0版本中新引入的。但在2.0.0版本中,当Batch与Limit同时设置时,彷佛还存在一个BUG,初步分析问题缘由应该与BatchScanResultCache中的numberOfCompletedRows计数器逻辑处理有关。所以,暂时不建议同时设置这两个参数。
scan.setCacheBlocks(true);
e) Raw Scan: 是否能够读取到删除标识以及被删除但还没有被清理的数据
scan.setRaw(true);
下面的示例代码将返回结果集的最大值设置为5MB:
scan.setMaxResultSize(5 * 1024 * 1024);
普通的Scan操做是按照字典顺序从小到大的顺序读取的,而Reversed Scan则刚好相反:
scan.setReversed(true);
Filter能够在Scan的结果集基础之上,对返回的记录设置更多条件值,这些条件能够与RowKey有关,能够与列名有关,也能够与列值有关,还能够将多个Filter条件组合在一块儿,等等。
最经常使用的Filter是SingleColumnValueFilter,基于它,能够实现以下相似的查询:
"返回知足条件{列I:D的值大于等于10}的全部行"
示例代码以下:
Filter丰富了HBase的查询能力,但使用Filter以前,须要注意一点:Filter可能会致使查询响应时延变的不可控制。由于咱们没法预测,为了找到一条符合条件的记录,背后须要扫描多少数据量,若是在有效限制了Scan范围区间(经过设置StartRow与StopRow限制)的前提下,该问题可以获得有效的控制。这些信息都要求使用Filter以前应该详细调研本身的业务数据模型。
本文有点长,做为参考吧