一、扫描:原生扫描(专家) ----------------------------------------------------------- 1.一般的扫描,如果不指定版本,仅仅扫描一个版本的数据。指定了就扫指定版本的数据,但是版本不会超过创建表时指定的版本数 2.但是,如果想扫描更多的版本(大于创建表时指定的版本数),可以使用原生扫描,可以将所有的历史版本全部扫描出来 $hbase> scan 'ns1:t2', {COLUMN=>'f1', RAW => true, VERSIONS => 10} 二、扫描:缓存扫描和批量扫描 --------------------------------------------------------------- 1.扫描之扫描器缓存--面向行级别的,一次RPC读取多少行 a.扫描的每一个next()调用都会为每行数据生成一个单独的PRC,当循环调用的时候,很耗费性能 b.扫描器缓存可以让一次RPC请求获取多行数据。默认扫描器缓存是关闭的 c.扫描器缓存分为表缓存[整个表的扫描均应用]和单次扫描缓存[仅当次扫描应用] a)表层面(全局) <property> <name>hbase.client.scanner.caching</name> <!-- 整数最大值 --> <value>2147483647</value> <source>hbase-default.xml</source> </property> b)操作层面 //设置量 scan.setCaching(10); d.代码测试
/**
* 测试全表扫描-带扫描器缓存
*/
@Test
public void tsScanTable_3() throws Exception {
long time = System.currentTimeMillis();
Scan scan = new Scan();
scan.setCaching(10); //1 --> 7060ms 10 -->1353ms 1000--> 420ms
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
System.out.print(Bytes.toString(result.getValue(Bytes.toBytes("f1"), Bytes.toBytes("name"))));
}
System.out.println();
System.out.println(System.currentTimeMillis() - time);
}
2.扫描之批量扫描 -- 面向列级别的,一次RPC读取多少列 a.控制scanner的next函数返回的列的数量 b.scanner.setBatch(5); //一次next会返回5列,加入一行一共有17列,那么就会分片返回,分4片,5,5,5,2 三、扫描:过滤器 ------------------------------------------------------------------ 1.RowFilter 行过滤器
/**
* 测试行过滤器RowFilter
* 扫描所有rowkey二进制数小于‘row0200’的行
*/
@Test
public void tsRowFilter() throws Exception {
Scan scan = new Scan();
//新建一个行对比器,使用的是小于或等于对比方式,比较器是二进制比较器BinaryComparator
RowFilter filter = new RowFilter(CompareFilter.CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("row0200")));
scan.setFilter(filter);
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
System.out.println("rowkey-->" + Bytes.toString(result.getRow()));
}
}
2.FamilyFilter 列族过滤器
/**
* 测试列族过滤器FamilyFilter
* 扫描所有family二进制数小于‘f2’的列族
*/
@Test
public void tsFamilyFilter() throws Exception {
TableName tbName = TableName.valueOf("ns1:t7");
tb = conn.getTable(tbName);
Scan scan = new Scan();
//新建一个列族对比器,使用的是小于的对比方式,比较器是二进制比较器BinaryComparator
FamilyFilter filter = new FamilyFilter(CompareFilter.CompareOp.LESS, new BinaryComparator(Bytes.toBytes("f2")));
scan.setFilter(filter);
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
byte[] f1name = result.getValue(Bytes.toBytes("f1"), Bytes.toBytes("name"));
byte[] f2name = result.getValue(Bytes.toBytes("f2"), Bytes.toBytes("name"));
byte[] f3name = result.getValue(Bytes.toBytes("f3"), Bytes.toBytes("name"));
System.out.println(f1name + ":" + f2name + ":" + f3name);
}
}
3.QualifierFilter 列过滤器
/**
* 测试列过滤器QualifierFilter
* 扫描所有column二进制数小于‘name’的列族
*/
@Test
public void tsColumnFilter() throws Exception {
TableName tbName = TableName.valueOf("ns1:t7");
tb = conn.getTable(tbName);
Scan scan = new Scan();
QualifierFilter filter = new QualifierFilter(CompareFilter.CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("id")));
scan.setFilter(filter);
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
Map<byte[],byte[]> map = result.getFamilyMap(Bytes.toBytes("f1"));
Set<byte[]> set = map.keySet();
for( byte [] bs: set )
{
System.out.println(Bytes.toString(bs) + ":" + Bytes.toString(map.get(bs)));
}
}
}
4.ValueFilter值过滤器
/**
* 测试Value过滤器ValueFilter
* 扫描所有含有‘to’的cell
*/
@Test
public void tsValueFilter() throws Exception {
TableName tbName = TableName.valueOf("ns1:t7");
tb = conn.getTable(tbName);
Scan scan = new Scan();
//新建一个值对比器,使用的是等于的对比方式,比较器是字符串比较器SubstringComparator
ValueFilter filter = new ValueFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator("tom"));
scan.setFilter(filter);
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
Map<byte[],byte[]> map = result.getFamilyMap(Bytes.toBytes("f1"));
Set<byte[]> set = map.keySet();
for( byte [] bs: set )
{
System.out.println(Bytes.toString(bs) + ":" + Bytes.toString(map.get(bs)));
}
}
}
5.SingleColumnValueFilter单列值过滤器
/**
* 测试单列值过滤器SingleColumnFilter
* 如果cell value 不满足条件,整行过滤掉[f1:name列的值不等于tom1的行,全部过滤掉]
*/
@Test
public void tsSingleColumnFilter() throws Exception {
TableName tbName = TableName.valueOf("ns1:t7");
tb = conn.getTable(tbName);
Scan scan = new Scan();
SingleColumnValueFilter filter = new SingleColumnValueFilter(
Bytes.toBytes("f1"),
Bytes.toBytes("name"),
CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("tom1"))
);
scan.setFilter(filter);
ResultScanner scanner = tb.getScanner(scan);
Result result = null;
while((result = scanner.next()) != null)
{
System.out.println("=================================================");
byte[] bb = result.getRow();
System.out.println("row:" + Bytes.toString(bb));
System.out.println("=================================================");
//得到一行的所有map==> [ key=>f1 , value=> map< column , map< timestamp, finalvalue > > ]
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = result.getMap();
Set<byte[]> set1 = map.keySet();
for(byte[] bs1 : set1)
{
//key => f1
String f1 = Bytes.toString(bs1);
//System.out.println("列族名:" +f1);
//value
NavigableMap<byte[], NavigableMap<Long, byte[]>> map2 = map.get(bs1);
Set<byte[]> set2 = map2.keySet();
for(byte[] bs2 : set2)
{
String column = Bytes.toString(bs2);
//System.out.println(f1 + "_" + column);
NavigableMap<Long, byte[]> map3 = map2.get(bs2);
Set<Long> set3 = map3.keySet();
for(Long l3 : set3)
{
//System.out.println("time_stamp:" + l3);
byte[] value = map3.get(l3);
System.out.println(f1 + "_" + column + "_"+Bytes.toString(value));
}
}
}
}
}
6.SingleColumnValueExcludeFilter单列值排除过滤器 -- 如果cell value 不满足条件,整行过滤掉,而且会将过滤条件中的列也过滤掉 -- SingleColumnValueExcludeFilter filter = new SingleColumnValueExcludeFilter( Bytes.toBytes("f1"), Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("tom1")) ); -- 结果会将f1:name列的值不等于tom1的行,全部过滤掉,并且在过滤结果中过滤掉name列的值(不要过滤条件列值) 7.PrefixFilter 前缀过滤 -- PrefixFilter filter = new PrefixFilter(Bytes.toBytes("row4")); -- 只显示 rowkey 以 ‘row4’ 开头的行[row40,row41,...,row422等等] 8.分页过滤器PageFilter -- PageFilter filter = new PageFilter(10); -- 显示表的前10行记录[但是注意,如果一个表分了3个区域储存,就会显示30行数据,显示每个区域的前10行数据] 9.keyonly过滤器 -- 只提取key,丢弃value -- KeyOnlyFilter filter = new KeyOnlyFilter(true/false); -- true -->结果只显示rowkey,familykey,columnkey,而用value的值的字节数组长度代替。可以帮助查看表结构 -- false -->结果只显示rowkey,familykey,columnkey,而不显示他们的值。可以帮助查看表结构 10.首次rowkey过滤器 -- 当首次找到指定的rowkey,就不再往下找了,类似于循环的break 11.列分页过滤器 -- 过滤列,列不在指定范围中,就会被过滤掉 -- ColumnPaginationFilter filter = new ColumnPaginationFilter(limit:2, offect:4); -- limit 2,保留2个列的长度 -- offect:4,表示偏移量,偏移四列 -- 结果就是只显示第5列和第6列,这两个列的数据 12.正则表达式对比器 -- 只保留RegexStringComparator对比器中的正则表达式的对象 -- ValueFilter filter = new ValueFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^tom1")); -- 保留所有以tom1开头的值 13.FilterList 过滤器组合实现复杂查询 -- 实现类似sql语句的复杂查询:select * from t7 where id <= 4 and name like '%3'; //where id <= 4 SingleColumnValueFilter f1 = new SingleColumnValueFilter( Bytes.toBytes("f1"), Bytes.toBytes("id"), CompareFilter.CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("4")) ); //where name end with 3 ValueFilter f2 = new ValueFilter ( CompareFilter.CompareOp.EQUAL, new RegexStringComparator("om6$") //^3 以3开头 ); FilterList flist = new FilterList(FilterList.Operator.MUST_PASS_ALL); flist.addFilter(f1); flist.addFilter(f2); 四、计数器 ------------------------------------------------------ 1.针对实时统计(鼠标点击流等)的优化方案 2.shell使用 $hbase> create 'ns1:t8', 'f1' $hbase> incr 'ns1:t8' , 'row1','f1:click' , 1 //将ns1:t8的row1行的f1:click + 1 ,模拟点击 $hbase> get_counter 'ns1:t8','row1', 'f1:click' //统计点击量 3.API使用
@Test
public void tsCounter() throws Exception {
// tb.incrementColumnValue(
// Bytes.toBytes("row2"),
// Bytes.toBytes("f1"),
// Bytes.toBytes("click"),
// 1
// );
//创建计数器
Increment incr = new Increment(Bytes.toBytes("row1"));
incr.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("daily"), 1);
incr.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("weekly"), 10);
incr.addColumn(Bytes.toBytes("f1"), Bytes.toBytes("monthly"), 100);
//绑定计数器
tb.increment(incr);
}
五、coprocessor 协处理器 ------------------------------------------------------------------ 1.相当于mysql中的储存过程。用预制好的语句,来进行批量处理的一种机制。 2.配置[hbase-site.xml]
<property>
<name>hbase.coprocessor.region.classes</name>
<value>coprocessor.RegionObserverExample, coprocessor.AnotherCoprocessor</value>
</property>
<property>
<name>hbase.coprocessor.master.classes</name>
<value>coprocessor.MasterObserverExample</value>
</property>
<property>
<name>hbase.coprocessor.wal.classes</name>
<value>coprocessor.WALObserverExample, bar.foo.MyWALObserver</value>
</property>
3.协处理框架的类主要分为两个大类,一个是observer[观察者],另一个是endpoint[终端] a.观察者 1)类似触发器,具有回调机制。当感兴趣的事件发生了,就执行注册好的回调方法 2)重要的实现类 -- RegionObserver 区域观察者:用户可以用这种处理器处理发生在region上的数据修改事件 -- MasterObserver 管理观察者:用户可以用这种处理器处理发生在master或者集群层面的DDL类型的数据修改事件 -- WALObserver WAL观察者:用户可以用这种处理器处理发生在WAL,HLOG层面的数据修改事件 b.endpoint[终端] 1)类似于储存过程。预先预制好处理的语句过程,将用户自定义的操作存储在服务端,在服务端层面做一些计算的工作 4.RegionObserver的执行过程分析 [ RegionObserver ] unassigned --> [ pending open --> open --> pending close ] --> closed 5.RegionObserver 代码实现:对客户的每次put 或者 get都做一次记录 a.编写代码
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
/**
* 测试自定义区域观察者
*/
public class TsRegionObserver extends BaseRegionObserver {
//输出日志
private void outLogs(String str)
{
try {
FileWriter fw = new FileWriter("/home/ubuntu/tsRegionServer.txt",true);
fw.write(str);
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void start(CoprocessorEnvironment e) throws IOException {
super.start(e);
outLogs("TsRegionObserver.start()");
}
@Override
public void stop(CoprocessorEnvironment e) throws IOException {
super.stop(e);
outLogs("TsRegionObserver.stop()");
}
@Override
public void preOpen(ObserverContext<RegionCoprocessorEnvironment> e) throws IOException {
super.preOpen(e);
outLogs("TsRegionObserver.preOpen()");
}
@Override
public void postOpen(ObserverContext<RegionCoprocessorEnvironment> e) {
super.postOpen(e);
outLogs("TsRegionObserver.postOpen()");
}
@Override
public void preClose(ObserverContext<RegionCoprocessorEnvironment> c, boolean abortRequested) throws IOException {
super.preClose(c, abortRequested);
outLogs("TsRegionObserver.preClose()");
}
@Override
public void postClose(ObserverContext<RegionCoprocessorEnvironment> e, boolean abortRequested) {
super.postClose(e, abortRequested);
outLogs("TsRegionObserver.postClose()");
}
@Override
public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results) throws IOException {
super.preGetOp(e, get, results);
String rowkey = Bytes.toString(get.getRow());
outLogs("TsRegionObserver.preGetOp():rowkey -->" + rowkey );
}
@Override
public void postGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results) throws IOException {
super.postGetOp(e, get, results);
String rowkey = Bytes.toString(get.getRow());
outLogs("TsRegionObserver.postGetOp():rowkey -->" + rowkey );
}
@Override
public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
super.prePut(e, put, edit, durability);
String rowkey = Bytes.toString(put.getRow());
outLogs("TsRegionObserver.prePut():rowkey-->" + rowkey);
}
@Override
public void postPut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException {
super.postPut(e, put, edit, durability);
String rowkey = Bytes.toString(put.getRow());
outLogs("TsRegionObserver.postPut():rowkey-->" + rowkey);
}
@Override
public void preDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
super.preDelete(e, delete, edit, durability);
String rowkey = Bytes.toString(delete.getRow());
outLogs("TsRegionObserver.preDelete():rowkey-->" + rowkey);
}
@Override
public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
super.postDelete(e, delete, edit, durability);
String rowkey = Bytes.toString(delete.getRow());
outLogs("TsRegionObserver.postDelete():rowkey-->" + rowkey);
}
}
b.注册协处理器,并分发到所有hbase节点 [hbase-site.xml] <property> <name>hbase.coprocessor.region.classes</name> <value>ts.hbase.TsRegionObserver</value> </property> c.导出jar包 d.拷贝jar包到hbase所有节点的lib目录下 e.在hbase shell 端进行get和put操作,查看打印日志/home/ubuntu/tsRegionServer.txt内容的变化