hbase-高级API-计数器

计数器一般用于实时统计(点击流或者在线广告),而不是使用高延迟的批量处理

计数器与原子操作检查并修改一样,这种机制可以将列当做计数器。而不用使用对一行加锁、修改、释放行锁这种容易引起大量资源竞争的操作(如果客户端进程崩溃的话,未释放的锁就会等待超时恢复、在高负载的系统中这种后果很严重)

客户端API提供计数器来完成原子操作检查并修改,保证客户端调用的原子性,多次调用可以使用一次RPC请求
客户端可以一次更新多个计数器但是它们必须是同一行,更新多个计数器需通过独立的API调用,即多个RPC请求

//终端的incr命令格式
incr 'table','row','column',[increment-value]
//计数器在列级的细节,每次调用命令返回这个计数器的新值,最后get_counter显示当前计数器值
//daily weekly monthly是列族
hbase(main):001:0> create 'counter','daily','weekly','monthly'
0 row(s) in 1.6090 seconds

=> Hbase::Table - counter
hbase(main):002:0> incr 'counter','20180128','daily:hits',1
COUNTER VALUE = 1
0 row(s) in 0.2970 seconds

hbase(main):003:0> incr 'counter','20180128','daily:hits',1
COUNTER VALUE = 2
0 row(s) in 0.0140 seconds

hbase(main):004:0> get_counter 'counter','20180128','daily:hits'
COUNTER VALUE = 2

用户不用初始化计数器,当列被创建时,计数器的值就被初始化为0。操作时就会返回1或者设定值

//直接读写一个计数器,需要解码
Bytes.toLong()
//编码
Bytes.toBytes(long)//长整型

//类型转换
byte[] b1 = Bytes.toBytes(1L)
byte[] b1 = Bytes.toBytes((long)var)
//也可以使用get访问这个计数器,或者增加更大的设定值
hbase(main):008:0> get 'counter','20180128'
daily:hits                timestamp=1517130705655, value=\x00\x00\x00\x00\x00\x00\x00\x02   
//shell把每一个字节按16进制数打印,get_counter 可以以可读形式读取值

//增加值可以是
0       得到计数器当前值
大于零   增加计数器值
小于零 减少计数器值
//incr一次只能操作一个计数器

单计数器
只能操作一个计数器:需要设定列,方法由HTable提供

long incrementColumnValue(byte[] row,byte[] family,byte[] qualifier, long amount) throws IOException 
long incrementColumnValue(byte[] row,byte[] family,byte[] qualifier, long amount,boolean writeToWAL) throws IOException

两种方法需要提供列的坐标(coordinates)和增加值
参 数 writeToWAL作用与Put.setWriteToWAL()方法一致。忽略参数直接使用默认值true ,也就是说,WAL是有效的

        Configuration hbase = HBaseConfiguration.create();
        String tablename = "counter";
        HTable table = new HTable(hbase,tablename);

        //increment data counter
        table.incrementColumnValue(Bytes.toBytes("2018025"), Bytes.toBytes("daily"), Bytes.toBytes("hits"), 1);     
        table.incrementColumnValue(Bytes.toBytes("2018025"), Bytes.toBytes("daily"), Bytes.toBytes("hits"), 1); 
        //0 == get_counter
        long cnt = table.incrementColumnValue(Bytes.toBytes("2018025"), Bytes.toBytes("daily"), Bytes.toBytes("hits"), 0);      
        table.incrementColumnValue(Bytes.toBytes("2018025"), Bytes.toBytes("daily"), Bytes.toBytes("hits"), -1);
        table.incrementColumnValue(Bytes.toBytes("2018025"), Bytes.toBytes("daily"), Bytes.toBytes("hits"), 1);
        System.out.println("current counter value:"+cnt);

使用正值时增加了计数器的 值,使用0 时可以得到当前计数器的值,使用负值时可以减少当前计数器的值

多计数器
HTablef的方法increment ()

Result increment(Increment increment) throws IOException

需要创建一个Increment实例,同时填充行键,此行应包含此实例需要通过increment () 方法修改的所有计数器

Increment(byte[] row) 
Increment(byte[] row,RowLock rowLock)
//rowLock锁实例,使本次操作完全在用户的控制下完成,例如,当用户需要多次修改同一行时,可以保证其间此行不被其他写程 序修改。

用户可以限制其他写程序修改此行的值,但是用户无法限制读操作。事实上,这里并没有保证读操作的原子性.因为读操作不需要获取锁,所以它可能读到一行中被修改到一半的数 据 ! scan和 get操作同样会出现这种情况

使用行键创建了一个Increment实例后,就需要向其中加入实际的计数器,也就是需要增加列

Increment addColumn(byte[] family,byte[] qualifier,long amount)

Increment类的特别功能是可以添加一个时间范围:

Increment setTimeRange(long minStamp,long maxStamp)

时间范围被送到服务器端来限制内部的get操作来取得当前这些计数器的值。用户可以使用它来使计数器过期(expire),例如,用时间划分一行的计数器:用户限制时间范围,可以用来屏蔽比较老的计数器,使它们看上去不存在。一次增加操作会认为这此较老的计数器不存在,并把它们重置为1

Increment类还提供了其他的一些预定于方法

nuraFarailies() 便捷地取回FamilyMap的大小,其中包括添加的所有列的列族 
numColumns() 返回将要被处理的列的数目
hasFamilies () 检査是否有列或列族被添加到这个Increment实例中
        Configuration hbase = HBaseConfiguration.create();
        String tablename = "counter";
        HTable table = new HTable(hbase,tablename);
        Increment icr = new Increment(Bytes.toBytes("2018028"));
        icr.addColumn(Bytes.toBytes("daily"), Bytes.toBytes("hits"), 1);
        icr.addColumn(Bytes.toBytes("weekly"), Bytes.toBytes("hits"), 0);
        Result result = table.increment(icr);
        for(KeyValue kv : result.raw()){
            System.out.println("kv data:"+kv);
            System.out.println(Bytes.toLong(kv.getValue()));
        }
        table.close();

一次increment调用只能操纵一行的计数器

你可能感兴趣的:(hbase)