注:本文示例來源於《HBase不睡覺書》第六章 6.2協處理器,文中HBase版本爲1.2.2,本文采用1.2.0-cdh5.8.0。
=================================================
需求:
=================================================
需求:
當插入數據時,如果遇到單元格爲mycf:name=JACK,則在mycf:message這個列插入一句話:Hello World! Welcome back!。這個需求在關係型數據庫中使用觸發器來實現。在HBase中我們使用協處理器來實現。
step1
step1
新建maven項目,打包方式選擇jar。原生版本只需添加hbase-server依賴(不要同時添加hbase-client依賴)。而cdh版本需要同時添加hbase-server、hbase-client,hbase-common以及guava包。
pom.xml
打包,放到HDFS上。我的jar包名是coprocessor-1.0-SNAPSHOT.jar,上傳到HDFS目錄下。
step5
在HBase中啓用這個觀察者,登錄服務器,使用hbase shell 執行以下命令:
通過hbase shell 添加數據:
可以看到通過java api 和hbase shell添加數據 協處理器都生效了。
下面我們再添加一條名字不是JACK的
可以看到第三行只有一條記錄,並沒有在message那一列添加數據。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.idayan</groupId>
<artifactId>coprocessor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>coprocessor</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-common</artifactId>
<version>1.2.0-cdh5.8.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>12.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
step 2
新建類:HelloWorldObserver雖然所有的協處理器都要實現接口Coprocessor,但是實現接口需要實現很多不必要的方法。所以我選擇直接繼承BaseRegionObserver類,這樣很多方法都有了基本你的實現,我們只需要重寫需要的方法即可。
step 3
編碼:
HelloWorldObserver.java
package com.idayan;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Durability;
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 java.io.IOException;
import java.util.List;
/**
* @author: xianghu.wang
* @Date: 2018/3/15
* @Description:
*/
public class HelloWorldObserver extends BaseRegionObserver{
public static final String JACK = "JACK";
/**
* 重寫prePut方法。
* 這個方法會在Put動作之前進行操作
* @param e
* @param put
* @param edit
* @param durability
* @throws IOException
*/
@Override
public void prePut(ObserverContext<RegionCoprocessorEnvironment> e,
Put put, WALEdit edit, Durability durability) throws IOException {
//獲取mycf:name的單元格
List<Cell> name = put.get(Bytes.toBytes("mycf"),Bytes.toBytes("name"));
//如果該put中不存在mycf:name,則不作操作,這個單元格直接返回
if (name == null || name.size() == 0) {
return;
}
//如果該put中存在mycf:name,則判斷mycf:name是否爲JACK
if (JACK.equals(Bytes.toString(CellUtil.cloneValue(name.get(0))))) {
//如果mycf:name是JACK,則在mycf:message中添加一句話
put.addColumn(Bytes.toBytes("mycf"),Bytes.toBytes("message"),Bytes.toBytes("Hello World! Welcome back !"));
}
}
}
step 4打包,放到HDFS上。我的jar包名是coprocessor-1.0-SNAPSHOT.jar,上傳到HDFS目錄下。
[maxiu@idayan00 hadoop-2.6.0-cdh5.8.0]$ bin/hdfs dfs -put /home/maxiu/myData/coprocessor-1.0-SNAPSHOT.jar /user/maxiu
18/03/15 11:09:20 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[maxiu@idayan00 hadoop-2.6.0-cdh5.8.0]$ bin/hdfs dfs -ls /user/maxiu
18/03/15 11:10:03 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Found 1 items
-rw-r--r-- 1 maxiu supergroup 2844 2018-03-15 11:09 /user/maxiu/coprocessor-1.0-SNAPSHOT.jar
我的jar:鏈接:https://pan.baidu.com/s/1vUw66lCjypE0EO8O3aO-5Q 密碼:8wdmstep5
在HBase中啓用這個觀察者,登錄服務器,使用hbase shell 執行以下命令:
hbase(main):002:0> create 'mytable','mycf' //創建表
0 row(s) in 1.5240 seconds
=> Hbase::Table - mytable
hbase(main):003:0> alter 'mytable' , METHOD =>'table_att','coprocessor'=>'hdfs://idayan00//user/maxiu/coprocessor-1.0-SNAPSHOT.jar|com.idayan.HelloWorldObserver||'
Updating all regions with the new schema... //啓用協處理器
1/1 regions updated.
Done.
0 row(s) in 2.5410 seconds
hbase(main):004:0> desc 'mytable' //查看錶屬性
Table mytable is ENABLED
mytable, {TABLE_ATTRIBUTES => {coprocessor$1 => 'hdfs://idayan00//user/maxiu/coprocessor-1.0-SNAPSHOT.jar|com.idayan.HelloWorldObserver||'}
COLUMN FAMILIES DESCRIPTION
{NAME => 'mycf', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'
}
1 row(s) in 0.0490 seconds
hbase(main):005:0>
- table_att是固定詞組,意思就是調用setValue()方法給表設置屬性
- 屬性名爲 coprocessor,就是協處理器的意思
- 屬性值爲<包所在路徑>|<協處理器類全名>||,並且中間不能有空格。
如果想刪除該協處理器可以執行以下命令:
hbase(main):005:0> alter 'mytable',METHOD =>'table_att_unset',NAME => 'coprocessor$1'
Updating all regions with the new schema...
1/1 regions updated.
Done.
0 row(s) in 2.5900 seconds
測試協處理器
現在嘗試用Java API來添加包含有mycf:name=JACK的數據
Put put = new Put(Bytes.toBytes("row1"));
put.addColumn(Bytes.toBytes("mycf"),Bytes.toBytes("name"),Bytes.toBytes("JACK"));
table.put(put);
查看結果:通過hbase shell 添加數據:
put 'mytable','row2','mycf:name','JACK'
可以看到通過java api 和hbase shell添加數據 協處理器都生效了。
下面我們再添加一條名字不是JACK的
put 'mytable','row3','mycf:name','MAXIU'
可以看到第三行只有一條記錄,並沒有在message那一列添加數據。