HBase
- 1. HBase是什麼
- 2. HBase集羣安裝部署
- 3. HBase表的數據模型
- 4. HBase整體架構
- 5. HBase shell 命令基本操作
- 5.1 進入HBase客戶端命令操作界面
- 5.2 help 幫助命令
- 5.3 list 查看有哪些表
- 5.4 create 創建表
- 5.5 put 插入數據操作
- 5.6 查詢數據操作
- 5.6.1 通過rowkey進行查詢
- 5.6.2 查看rowkey下某個列族的信息
- 5.6.3 查看rowkey指定列族指定字段的值
- 5.6.4 查看rowkey指定多個列族的信息
- 5.6.5 指定rowkey與列值過濾器查詢
- 5.6.6 指定rowkey與列名模糊查詢
- 5.6.7 查詢所有行的數據
- 5.6.8 列族查詢
- 5.6.9 多列族查詢
- 5.6.10 指定列族與某個列名查詢
- 5.6.11 指定多個列族與按照數據值模糊查詢
- 5.6.12 指定rowkey的範圍查詢
- 5.6.13 指定rowkey模糊查詢
- 5.6.14 指定數據版本的範圍查詢
- 5.7 更新數據操作
- 5.8 刪除數據以及刪除表操作
- 5.9 統計一張表有多少行數據
- 6. HBase的高級shell管理命令
- 6.1 status
- 6.2 whoami
- 6.3 list
- 6.4 count
- 6.5 describe
- 6.6 exists
- 6.7 is_enabled、is_disabled
- 6.8 alter
- 6.9 disable/enable
- 7. HBase的JavaAPI操作
1. HBase是什麼
1.1 HBase的概念
- HBase基於Google的BigTable論文,是建立的HDFS之上,提供高可靠性、高性能、列存儲、可伸縮、實時讀寫的分佈式數據庫系統。
- 在需要實時讀寫隨機訪問超大規模數據集時,可以使用HBase。
1.2 HBase的特點
- 海量存儲
- 可以存儲大批量的數據
- 列式存儲
- HBase表的數據是基於列族進行存儲的,列族是在列的方向上的劃分。
- 極易擴展
- 底層依賴HDFS,當磁盤空間不足的時候,只需要動態增加datanode節點就可以了
- 可以通過增加服務器來對集羣的存儲進行擴容
- 高併發
- 支持高併發的讀寫請求
- 稀疏
- 稀疏主要是針對HBase列的靈活性,在列族中,你可以指定任意多的列,在列數據爲空的情況下,是不會佔用存儲空間的。
- 數據的多版本
- HBase表中的數據可以有多個版本值,默認情況下是根據版本號去區分,版本號就是插入數據的時間戳
- 數據類型單一
- 所有的數據在HBase中是以字節數組進行存儲
2. HBase集羣安裝部署
2.1 準備安裝包
-
下載安裝包並上傳到node01服務器
-
安裝包下載地址:
http://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.14.2.tar.gz
-
將安裝包上傳到node01服務器/zsc/soft路徑下,並進行解壓
[hadoop@node01 ~]$ cd /zsc/soft/
[hadoop@node01 soft]$ tar -xzvf hbase-1.2.0-cdh5.14.2.tar.gz -C /zsc/install/
2.2 修改HBase配置文件
2.2.1 hbase-env.sh
- 修改文件
[hadoop@node01 soft]$ cd /zsc/install/hbase-1.2.0-cdh5.14.2/conf/
[hadoop@node01 conf]$ vim hbase-env.sh
- 修改如下兩項內容,值如下
export JAVA_HOME=/kkb/install/jdk1.8.0_141
export HBASE_MANAGES_ZK=false
2.2.2 hbase-site.xml
- 修改文件
[hadoop@node01 conf]$ vim hbase-site.xml
- 內容如下
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://node01:8020/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- 0.98後的新變動,之前版本沒有.port,默認端口爲60000 -->
<property>
<name>hbase.master.port</name>
<value>16000</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>node01,node02,node03</value>
</property>
<!-- 此屬性可省略,默認值就是2181 -->
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/kkb/install/zookeeper-3.4.5-cdh5.14.2/zkdatas</value>
</property>
<!-- 此屬性可省略,默認值就是/hbase -->
<property>
<name>zookeeper.znode.parent</name>
<value>/hbase</value>
</property>
</configuration>
2.2.3 regionservers
- 修改文件
[hadoop@node01 conf]$ vim regionservers
- 指定HBase集羣的從節點
node01
node02
node03
2.2.4 back-masters
- 創建back-masters配置文件,裏邊包含
備份HMaster
節點的主機名,每個機器獨佔一行,實現HMaster的高可用
[hadoop@node01 conf]$ vim backup-masters
- 將node02作爲備份的HMaster節點,內容如下
node02
2.3 分發安裝包
- 將node01上的HBase安裝包,拷貝到其他機器上
[hadoop@node01 conf]$ cd /zsc/install
[hadoop@node01 install]$ scp -r hbase-1.2.0-cdh5.14.2/ node02:$PWD
[hadoop@node01 install]$ scp -r hbase-1.2.0-cdh5.14.2/ node03:$PWD
2.4 創建軟連接
-
注意:所有機器均做如下操作
-
因爲HBase集羣需要讀取hadoop的core-site.xml、hdfs-site.xml的配置文件信息,所以我們三臺機器都要執行以下命令,在相應的目錄創建這兩個配置文件的軟連接
-
Linux下的軟連接類似於win下的快捷方式
ln -s /zsc/install/hadoop-2.6.0-cdh5.14.2/etc/hadoop/core-site.xml /zsc/install/hbase-1.2.0-cdh5.14.2/conf/core-site.xml
ln -s /zsc/install/hadoop-2.6.0-cdh5.14.2/etc/hadoop/hdfs-site.xml /zsc/install/hbase-1.2.0-cdh5.14.2/conf/hdfs-site.xml
2.5 添加HBase環境變量
- 所有機器均執行以下命令,添加環境變量
sudo vim /etc/profile
- 文件末尾添加如下內容
export HBASE_HOME=/zsc/install/hbase-1.2.0-cdh5.14.2
export PATH=$PATH:$HBASE_HOME/bin
- 讓環境變量生效
source /etc/profile
2.6 HBase的啓動與停止
-
需要提前啓動HDFS及ZooKeeper集羣
-
第一臺機器node01(HBase主節點)執行以下命令,啓動HBase集羣
[hadoop@node01 ~]$ start-hbase.sh
-
啓動完後,jps查看HBase相關進程
-
node01、node02上有進程HMaster、HRegionServer
-
node03上有進程HRegionServer
-
-
警告提示:HBase啓動的時候會產生一個警告,這是因爲jdk7與jdk8的問題導致的,如果linux服務器安裝jdk8就會產生這樣的一個警告
-
可以註釋掉所有機器的hbase-env.sh當中的
“HBASE_MASTER_OPTS”
和“HBASE_REGIONSERVER_OPTS”
配置 來解決這個問題。不過警告不影響我們正常運行,可以不用解決 -
我們也可以執行以下命令,單節點啓動相關進程
#HMaster節點上啓動HMaster命令
hbase-daemon.sh start master
#啓動HRegionServer命令
hbase-daemon.sh start regionserver
2.7 訪問WEB頁面
- 瀏覽器頁面訪問 : http://node01:60010
2.8 停止HBase集羣
- 停止HBase集羣的正確順序
- node01上運行
[hadoop@node01 ~]$ stop-hbase.sh
- 若需要關閉虛擬機,則還需要關閉ZooKeeper、Hadoop集羣
3. HBase表的數據模型
3.1 rowkey行鍵
- table的主鍵,table中的記錄按照rowkey 的字典序進行排序
- Row key行鍵可以是任意字符串(最大長度是
64KB
,實際應用中長度一般爲10-100bytes
)
3.2 Column Family列族
- 列族或列簇
- HBase表中的每個列,都歸屬與某個列族
- 列族是表的schema的一部分(而列不是),即建表時至少指定一個列族
- 比如創建一張表,名爲
user
,有兩個列族,分別是info
和data
,建表語句create 'user', 'info', 'data'
3.3 Column列
- 列肯定是表的某一列族下的一個列,用
列族名:列名
表示,如info
列族下的name
列,表示爲info:name
- 屬於某一個ColumnFamily,類似於我們mysql當中創建的具體的列
3.4 cell單元格
-
指定row key行鍵、列族、列,可以確定的一個cell單元格
-
cell中的數據是沒有類型的,全部是以
字節數組
進行存儲
3.5 Timestamp時間戳
- 可以對錶中的Cell多次賦值,每次賦值操作時的時間戳timestamp,可看成Cell值的版本號version number
- 即一個Cell可以有
多個版本
的值
4. HBase整體架構
4.1 Client客戶端
- Client是操作HBase集羣的入口
- 對於管理類的操作,如表的增、刪、改操縱,Client通過RPC與HMaster通信完成
- 對於表數據的讀寫操作,Client通過RPC與RegionServer交互,讀寫數據
- Client類型:
- HBase shell
- Java編程接口
- Thrift、Avro、Rest等等
4.2 ZooKeeper集羣
- 作用:
-
實現了HMaster的高可用,多HMaster間進行主備選舉
-
保存了HBase的元數據信息meta表,提供了HBase表中region的尋址入口的線索數據
-
對HMaster和HRegionServer實現了監控
-
4.3 HMaster
- HBase集羣也是主從架構,HMaster是主的角色,是老大
- 主要負責Table表和Region的相關管理工作:
- 關於Table
- 管理Client對Table的增刪改的操作
- 關於Region
- 在Region分裂後,負責新Region分配到指定的HRegionServer上
- 管理HRegionServer間的負載均衡,遷移region分佈
- 當HRegionServer宕機後,負責其上的region的遷移
4.4 HRegionServer
-
HBase集羣中從的角色,是小弟
-
作用
- 響應客戶端的讀寫數據請求
- 負責管理一系列的Region
- 切分在運行過程中變大的region
4.5 Region
- HBase集羣中分佈式存儲的最小單元
- 一個Region對應一個Table表的部分數據
HBase使用,主要有兩種形式:①shell 命令;②Java編程
5. HBase shell 命令基本操作
5.1 進入HBase客戶端命令操作界面
- node01執行以下命令,進入HBase的shell客戶端
cd /zsc/install/hbase-1.2.0-cdh5.14.2/
bin/hbase shell
5.2 help 幫助命令
hbase(main):001:0> help
5.3 list 查看有哪些表
- 查看當前數據庫中有哪些表
hbase(main):002:0> list
5.4 create 創建表
- 創建user表,包含info、data兩個列族
hbase(main):010:0> create 'user', 'info', 'data'
或者
hbase(main):010:0> create 'user', {NAME => 'info', VERSIONS => '3'},{NAME => 'data'}
5.5 put 插入數據操作
- 向表中插入數據
向user表中插入信息,row key爲rk0001,列族info中添加名爲name的列,值爲zhangsan
hbase(main):011:0> put 'user', 'rk0001', 'info:name', 'zhangsan'
向user表中插入信息,row key爲rk0001,列族info中添加名爲gender的列,值爲female
hbase(main):012:0> put 'user', 'rk0001', 'info:gender', 'female'
向user表中插入信息,row key爲rk0001,列族info中添加名爲age的列,值爲20
hbase(main):013:0> put 'user', 'rk0001', 'info:age', 20
向user表中插入信息,row key爲rk0001,列族data中添加名爲pic的列,值爲picture
hbase(main):014:0> put 'user', 'rk0001', 'data:pic', 'picture'
5.6 查詢數據操作
5.6.1 通過rowkey進行查詢
- 獲取user表中row key爲rk0001的所有信息(即所有cell的數據)
hbase(main):015:0> get 'user', 'rk0001'
5.6.2 查看rowkey下某個列族的信息
- 獲取user表中row key爲rk0001,info列族的所有信息
hbase(main):016:0> get 'user', 'rk0001', 'info'
5.6.3 查看rowkey指定列族指定字段的值
- 獲取user表中row key爲rk0001,info列族的name、age列的信息
hbase(main):017:0> get 'user', 'rk0001', 'info:name', 'info:age'
5.6.4 查看rowkey指定多個列族的信息
- 獲取user表中row key爲rk0001,info、data列族的信息
hbase(main):018:0> get 'user', 'rk0001', 'info', 'data'
或者你也可以這樣寫
hbase(main):019:0> get 'user', 'rk0001', {COLUMN => ['info', 'data']}
或者你也可以這樣寫,也行
hbase(main):020:0> get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic']}
5.6.5 指定rowkey與列值過濾器查詢
- 獲取user表中row key爲rk0001,cell的值爲zhangsan的信息
hbase(main):030:0> get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"}
5.6.6 指定rowkey與列名模糊查詢
- 獲取user表中row key爲rk0001,列標示符中含有a的信息
hbase(main):031:0> get 'user', 'rk0001', {FILTER => "QualifierFilter(=,'substring:a')"}
繼續插入一批數據
hbase(main):032:0> put 'user', 'rk0002', 'info:name', 'fanbingbing'
hbase(main):033:0> put 'user', 'rk0002', 'info:gender', 'female'
hbase(main):034:0> put 'user', 'rk0002', 'info:nationality', '中國'
hbase(main):035:0> get 'user', 'rk0002', {FILTER => "ValueFilter(=, 'binary:中國')"}
5.6.7 查詢所有行的數據
- 查詢user表中的所有信息
- 使用scan命令
hbase(main):032:0> scan 'user'
5.6.8 列族查詢
- 查詢user表中列族爲info的信息
scan 'user', {COLUMNS => 'info'}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3}
5.6.9 多列族查詢
- 查詢user表中列族爲info和data的信息
scan 'user', {COLUMNS => ['info', 'data']}
5.6.10 指定列族與某個列名查詢
- 查詢user表中列族爲info、列標示符爲name的信息
scan 'user', {COLUMNS => 'info:name'}
- 查詢info:name列、data:pic列的數據
scan 'user', {COLUMNS => ['info:name', 'data:pic']}
- 查詢user表中列族爲info、列標示符爲name的信息,並且版本最新的5個
scan 'user', {COLUMNS => 'info:name', VERSIONS => 5}
5.6.11 指定多個列族與按照數據值模糊查詢
- 查詢user表中列族爲info和data且列標示符中含有a字符的信息
scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}
5.6.12 指定rowkey的範圍查詢
- 查詢user表中列族爲info,rk範圍是[rk0001, rk0003)的數據
scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}
5.6.13 指定rowkey模糊查詢
- 查詢user表中row key以rk字符開頭的數據
scan 'user',{FILTER=>"PrefixFilter('rk')"}
5.6.14 指定數據版本的範圍查詢
- 查詢user表中指定範圍的數據(前閉後開)
scan 'user', {TIMERANGE => [1392368783980, 1392380169184]}
5.7 更新數據操作
5.7.1 更新數據值
- 更新操作同插入操作一模一樣,只不過有數據就更新,沒數據就添加
- 使用put命令
5.7.2 更新版本號
- 將user表的f1列族版本數改爲5
hbase(main):050:0> alter 'user', NAME => 'info', VERSIONS => 5
5.8 刪除數據以及刪除表操作
5.8.1 指定rowkey以及列名進行刪除
- 刪除user表row key爲rk0001,列標示符爲info:name的數據
hbase(main):045:0> delete 'user', 'rk0001', 'info:name'
5.8.2 指定rowkey,列名以及版本號進行刪除
- 刪除user表row key爲rk0001,列標示符爲info:name,timestamp爲1392383705316的數據
delete 'user', 'rk0001', 'info:name', 1392383705316
5.8.3 刪除一個列族
- 刪除一個列族:
alter 'user', NAME => 'info', METHOD => 'delete'
或 alter 'user', 'delete' => 'info'
5.8.4 清空表數據
hbase(main):017:0> truncate 'user'
5.8.5 刪除表
- 首先需要先讓該表爲disable狀態,使用命令:
hbase(main):049:0> disable 'user'
- 然後使用drop命令刪除這個表
hbase(main):050:0> drop 'user'
(注意:如果直接drop表,會報錯:Drop the named table. Table must first be disabled)
5.9 統計一張表有多少行數據
hbase(main):053:0> count 'user'
6. HBase的高級shell管理命令
6.1 status
- 顯示服務器狀態
hbase(main):058:0> status 'node01'
6.2 whoami
- 顯示HBase當前用戶
hbase> whoami
6.3 list
- 顯示當前所有的表
hbase > list
6.4 count
- 統計指定表的記錄數
hbase> count 'user'
6.5 describe
- 展示表結構信息
hbase> describe 'user'
6.6 exists
- 檢查表是否存在,適用於表量特別多的情況
hbase> exists 'user'
6.7 is_enabled、is_disabled
- 檢查表是否啓用或禁用
hbase> is_enabled 'user'
hbase> is_disabled 'user'
6.8 alter
-
該命令可以改變表和列族的模式
-
爲當前表增加列族:
hbase> alter 'user', NAME => 'CF2', VERSIONS => 2
- 爲當前表刪除列族:
hbase(main):002:0> alter 'user', 'delete' => 'CF2'
6.9 disable/enable
- 禁用一張表/啓用一張表
hbase> disable 'user'
hbase> enable 'user'
7. HBase的JavaAPI操作
- HBase是一個分佈式的NoSql數據庫,在實際工作當中,我們一般都可以通過JavaAPI來進行各種數據的操作,包括創建表,以及數據的增刪改查等等
7.1 創建maven工程
- 添加pom依賴
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.6.0-mr1-cdh5.14.2</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.2.0-cdh5.14.2</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.2.0-cdh5.14.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*/RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
7.2 創建myuser表
- 創建myuser表,此表有兩個列族f1和f2
/**
* 操作數據庫 第一步:獲取連接 第二步:獲取客戶端對象 第三步:操作數據庫 第四步:關閉
* 創建myuser表,有兩個列族 f1 f2
* @throws IOException
*/
@Test
public void createTable() throws IOException {
//獲得連接
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "node01:2181,node02:2181,node03:2181");
//創建連接對象
Connection connection = ConnectionFactory.createConnection(configuration);
//操作:建表、刪除表、修改表 -> 管理員;創建管理員對象
Admin admin = connection.getAdmin();
//添加了表名信息
HTableDescriptor myuser = new HTableDescriptor(TableName.valueOf("myuser"));
//給表添加列族
myuser.addFamily(new HColumnDescriptor("f1"));
myuser.addFamily(new HColumnDescriptor("f2"));
//創建表
admin.createTable(myuser);
//關閉連接
admin.close();
connection.close();
}
7.3向表中添加數據
private Connection connection;
private Table table;
//建立連接
@BeforeTest
public void init() throws IOException {
//獲得連接
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "node01:2181,node02:2181,node03:2181");
//configuration.set("zookeeper.znode.parent", "/HBase");
connection = ConnectionFactory.createConnection(configuration);
//獲得表
table = connection.getTable(TableName.valueOf("myuser"));
}
@AfterTest
public void close() throws IOException {
table.close();
connection.close();
}
//向表中添加數據
@Test
public void putData() throws IOException {
Put put = new Put("0001".getBytes());//創建Put對象,並指定rowkey值
//添加cell值:列族名稱+列名+值
put.addColumn("f1".getBytes(), "name".getBytes(), "zhangsan".getBytes());
put.addColumn("f1".getBytes(), "age".getBytes(), Bytes.toBytes(18));
put.addColumn("f1".getBytes(),"id".getBytes(), Bytes.toBytes(25));
put.addColumn("f1".getBytes(),"address".getBytes(), Bytes.toBytes("地球人"));
table.put(put);
}
7.4 查詢數據
- 初始化一批數據到HBase表當中,用於查詢
@Test
public void batchInsert() throws IOException {
//創建put對象,並指定rowkey
Put put = new Put("0002".getBytes());
//向f1列族添加數據
put.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(1));
put.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("曹操"));
put.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(30));
//向f2列族添加數據
put.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("沛國譙縣"));
put.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("16888888888"));
put.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("helloworld"));
Put put2 = new Put("0003".getBytes());
put2.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(2));
put2.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("劉備"));
put2.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(32));
put2.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put2.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("幽州涿郡涿縣"));
put2.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("17888888888"));
put2.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("talk is cheap , show me the code"));
Put put3 = new Put("0004".getBytes());
put3.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(3));
put3.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("孫權"));
put3.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(35));
put3.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put3.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("下邳"));
put3.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("12888888888"));
put3.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("what are you 弄啥嘞!"));
Put put4 = new Put("0005".getBytes());
put4.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(4));
put4.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("諸葛亮"));
put4.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(28));
put4.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put4.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("四川隆中"));
put4.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("14888888888"));
put4.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("出師表你背了嘛"));
Put put5 = new Put("0006".getBytes());
put5.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(5));
put5.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("司馬懿"));
put5.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(27));
put5.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put5.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("哪裏人有待考究"));
put5.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("15888888888"));
put5.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("跟諸葛亮死掐"));
Put put6 = new Put("0007".getBytes());
put6.addColumn("f1".getBytes(),"id".getBytes(),Bytes.toBytes(5));
put6.addColumn("f1".getBytes(),"name".getBytes(),Bytes.toBytes("xiaobubu—呂布"));
put6.addColumn("f1".getBytes(),"age".getBytes(),Bytes.toBytes(28));
put6.addColumn("f2".getBytes(),"sex".getBytes(),Bytes.toBytes("1"));
put6.addColumn("f2".getBytes(),"address".getBytes(),Bytes.toBytes("內蒙人"));
put6.addColumn("f2".getBytes(),"phone".getBytes(),Bytes.toBytes("15788888888"));
put6.addColumn("f2".getBytes(),"say".getBytes(),Bytes.toBytes("貂蟬去哪了"));
List<Put> listPut = new ArrayList<Put>();
listPut.add(put);
listPut.add(put2);
listPut.add(put3);
listPut.add(put4);
listPut.add(put5);
listPut.add(put6);
table.put(listPut);
}
7.4.1 Get查詢
- 按照rowkey進行查詢,獲取所有列的所有值
- 查詢主鍵rowkey爲0003的人
//查詢rowkey爲0003的數據
@Test
public void getDataByRowkey() throws IOException {
//通過get對象,指定rowkey
Get get = new Get("0003".getBytes());
//獲取某列族
get.addFamily("f1".getBytes());//限定查詢f1列族下面所有列的值
get.addColumn("f2".getBytes(), "say".getBytes());//查詢f2列族say列的值
//通過get查詢,返回0003行,f1列族、f2:say列的所有cell的值,封裝到一個Result對象
Result result = table.get(get);
//獲得Result中的所有Cell
List<Cell> cells = result.listCells();
//遍歷Cell
for(Cell cell: cells) {
//cell單元格
//獲得rowkey
byte[] rowkey_bytes = CellUtil.cloneRow(cell);
//獲得列族
byte[] family_bytes = CellUtil.cloneFamily(cell);
//獲得列
byte[] qualifier_bytes = CellUtil.cloneQualifier(cell);
//獲得值
byte[] cell_bytes = CellUtil.cloneValue(cell);
if("age".equals(Bytes.toString(qualifier_bytes)) || "id".equals(Bytes.toString(qualifier_bytes))) {
System.out.println(Bytes.toString(rowkey_bytes));
System.out.println(Bytes.toString(family_bytes));
System.out.println(Bytes.toString(qualifier_bytes));
System.out.println(Bytes.toInt(cell_bytes));//age或id的值是int類型,得用Bytes.toInt
} else {
System.out.println(Bytes.toString(rowkey_bytes));
System.out.println(Bytes.toString(family_bytes));
System.out.println(Bytes.toString(qualifier_bytes));
System.out.println(Bytes.toString(cell_bytes));
}
}
}
7.4.2 Scan查詢
/**
* 不知道rowkey的具體值,我想查詢rowkey範圍值是0003 到0006
* select * from myuser where age > 30 and id < 8 and name like 'zhangsan'
*/
@Test
public void scanData() throws IOException {
Scan scan = new Scan();//若沒有指定startRow以及stopRow,則全表掃描
//掃描f1列族
scan.addFamily("f1".getBytes());
//掃描 f2列族 phone列
scan.addColumn("f2".getBytes(),"phone".getBytes());
//設置起始結束rowkey,前閉後開
scan.setStartRow("0003".getBytes());
scan.setStopRow("0007".getBytes());
//設置每批次返回客戶端的數據條數
scan.setBatch(20);
//從cacheBlock中讀取數據
scan.setCacheBlocks(true);
scan.setMaxResultSize(4);
scan.setMaxVersions(2);//獲取歷史2個版本
//通過getScanner查詢獲取到了表裏面所有的數據,是多條數據
ResultScanner scanner = table.getScanner(scan);
//遍歷ResultScanner 得到每一條數據,每一條數據都是封裝在result對象裏面了
for (Result result : scanner) {
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
byte[] family_name = CellUtil.cloneFamily(cell);
byte[] qualifier_name = CellUtil.cloneQualifier(cell);
byte[] rowkey = CellUtil.cloneRow(cell);
byte[] value = CellUtil.cloneValue(cell);
//判斷id和age字段,這兩個字段是整形值
if("age".equals(Bytes.toString(qualifier_name)) || "id".equals(Bytes.toString(qualifier_name))){
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toInt(value));
}else{
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toString(value));
}
}
}
}
7.5 HBase過濾器查詢(
7.5.1 過濾器
-
過濾器的作用是在服務端判斷數據是否滿足條件,然後只將滿足條件的數據返回給客戶端
-
過濾器的類型很多,但是可以分爲兩大類
- 比較過濾器
- 專用過濾器
7.5.2 比較過濾器使用
- HBase過濾器的比較運算符:
LESS <
LESS_OR_EQUAL <=
EQUAL =
NOT_EQUAL <>
GREATER_OR_EQUAL >=
GREATER >
NO_OP 排除所有
- Hbase比較過濾器的比較器(指定比較機制):
BinaryComparator 按字節索引順序比較指定字節數組,採用Bytes.compareTo(byte[])
BinaryPrefixComparator 跟前面相同,只是比較左端前綴的數據是否相同
NullComparator 判斷給定的是否爲空
BitComparator 按位比較
RegexStringComparator 提供一個正則的比較器,僅支持 EQUAL 和非EQUAL
SubstringComparator 判斷提供的子串是否出現在中
- 比較過濾器
1、rowKey過濾器RowFilter
- 通過RowFilter過濾比rowKey 0003小的所有值出來
/**
* 查詢所有的rowkey比0003小的所有的數據
*/
@Test
public void rowFilter() throws IOException {
Table table = connection.getTable(TableName.valueOf("myuser"));
Scan scan = new Scan();
//獲取比較對象
BinaryComparator binaryComparator = new BinaryComparator("0003".getBytes());
/**
* rowFilter需要加上兩個參數
* 第一個參數就是我們的比較規則
* 第二個參數就是我們的比較對象
*/
RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.LESS, binaryComparator);
//爲我們的scan對象設置過濾器
scan.setFilter(rowFilter);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
byte[] family_name = CellUtil.cloneFamily(cell);
byte[] qualifier_name = CellUtil.cloneQualifier(cell);
byte[] rowkey = CellUtil.cloneRow(cell);
byte[] value = CellUtil.cloneValue(cell);
//判斷id和age字段,這兩個字段是整形值
if("age".equals(Bytes.toString(qualifier_name)) || "id".equals(Bytes.toString(qualifier_name))){
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toInt(value));
}else{
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toString(value));
}
}
}
}
2、列族過濾器FamilyFilter
- 查詢列族名包含f2的所有列族下面的數據
/**
* 通過familyFilter來實現列族的過濾
* 需要過濾,列族名包含f2
* f1 f2 hello world
*/
@Test
public void familyFilter() throws IOException {
Table table = connection.getTable(TableName.valueOf("myuser"));
Scan scan = new Scan();
SubstringComparator substringComparator = new SubstringComparator("f2");
//通過familyfilter來設置列族的過濾器
FamilyFilter familyFilter = new FamilyFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
scan.setFilter(familyFilter);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
byte[] family_name = CellUtil.cloneFamily(cell);
byte[] qualifier_name = CellUtil.cloneQualifier(cell);
byte[] rowkey = CellUtil.cloneRow(cell);
byte[] value = CellUtil.cloneValue(cell);
//判斷id和age字段,這兩個字段是整形值
if("age".equals(Bytes.toString(qualifier_name)) || "id".equals(Bytes.toString(qualifier_name))){
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toInt(value));
}else{
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toString(value));
}
}
}
}
3、列過濾器QualifierFilter
- 只查詢列名包含
name
的列的值
/**
* 列名過濾器 只查詢包含name列的值
* 列名包含“name”
*/
@Test
public void qualifierFilter() throws IOException {
Scan scan = new Scan();
SubstringComparator substringComparator = new SubstringComparator("name");
//定義列名過濾器,只查詢列名包含name的列
QualifierFilter qualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
scan.setFilter(qualifierFilter);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
}
private void printlReult(ResultScanner scanner) {
for (Result result : scanner) {
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
byte[] family_name = CellUtil.cloneFamily(cell);
byte[] qualifier_name = CellUtil.cloneQualifier(cell);
byte[] rowkey = CellUtil.cloneRow(cell);
byte[] value = CellUtil.cloneValue(cell);
//判斷id和age字段,這兩個字段是整形值
if("age".equals(Bytes.toString(qualifier_name)) || "id".equals(Bytes.toString(qualifier_name))){
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toInt(value));
}else{
System.out.println("數據的rowkey爲" + Bytes.toString(rowkey) +"======數據的列族爲" + Bytes.toString(family_name)+"======數據的列名爲" + Bytes.toString(qualifier_name) + "==========數據的值爲" +Bytes.toString(value));
}
}
}
}
4、列值過濾器ValueFilter
- 查詢所有列當中包含8的數據
/**
* 查詢哪些字段值 包含"8"
*/
@Test
public void contains8() throws IOException {
Scan scan = new Scan();
SubstringComparator substringComparator = new SubstringComparator("8");
//列值過濾器,過濾列值當中包含數字8的所有的列
ValueFilter valueFilter = new ValueFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
scan.setFilter(valueFilter);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
}
7.5.3 專用過濾器使用
1、單列值過濾器 SingleColumnValueFilter
-
SingleColumnValueFilter會返回滿足條件的cell。所在行的所有cell的值
-
查詢名字爲劉備的數據
/**
* select * from myuser where name = '劉備'
* 會返回我們符合條件數據的所有的字段
*
* SingleColumnValueExcludeFilter 列值排除過濾器
* select * from myuser where name != '劉備'
*/
@Test
public void singleColumnValueFilter() throws IOException {
//查詢 f1 列族 name 列 值爲劉備的數據
Scan scan = new Scan();
//單列值過濾器,過濾 f1 列族 name 列 值爲劉備的數據
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("f1".getBytes(), "name".getBytes(), CompareFilter.CompareOp.EQUAL, "xiaobubu—呂布".getBytes());
scan.setFilter(singleColumnValueFilter);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
}
2、列值排除過濾器SingleColumnValueExcludeFilter
- 與SingleColumnValueFilter相反,會排除掉指定的列,其他的列全部返回
3、rowkey前綴過濾器PrefixFilter
- 查詢以00開頭的所有前綴的rowkey
/**
* 查詢rowkey前綴以 00開頭的所有的數據
*/
@Test
public void prefixFilter() throws IOException {
Scan scan = new Scan();
//過濾rowkey以 00開頭的數據
PrefixFilter prefixFilter = new PrefixFilter("0001".getBytes());
scan.setFilter(prefixFilter);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
}
4、分頁過濾器PageFilter
- 通過pageFilter實現分頁過濾器
//分頁過濾器
@Test
public void pageFilter() throws IOException {
//頁碼
int pageNum = 3;
//每頁的大小
int pageSize = 2;
Scan scan = new Scan();
if(pageNum == 1) {//獲取第一頁的數據
scan.setMaxResultSize(pageSize);
scan.setStartRow("".getBytes());
//使用分頁過濾器,實現數據的分頁
PageFilter pageFilter = new PageFilter(pageSize);
scan.setFilter(pageFilter);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
} else {//如果所讀分頁不是第一頁
//先取得此分頁的第一個rowkey值
String startRow = "";
//掃描多少條 5
int scanDatas = (pageNum - 1) * pageSize + 1;
scan.setMaxResultSize(scanDatas);
PageFilter pageFilter = new PageFilter(scanDatas);
scan.setFilter(pageFilter);
ResultScanner scanner = table.getScanner(scan);
for(Result result : scanner) {
byte[] row_bytes = result.getRow();
startRow = Bytes.toString(row_bytes);
}
scan.setStartRow(startRow.getBytes());
scan.setMaxResultSize(pageSize);
PageFilter pageFilter1 = new PageFilter(pageSize);
scan.setFilter(pageFilter1);
ResultScanner scanner1 = table.getScanner(scan);
printlReult(scanner1);
}
}
7.5.4 多過濾器綜合查詢FilterList
- 需求:使用SingleColumnValueFilter查詢f1列族,name爲劉備的數據,並且同時滿足rowkey的前綴以00開頭的數據(PrefixFilter)
/**
* 查詢 f1 列族 name 爲劉備數據值
* 並且rowkey 前綴以 00開頭數據
*/
@Test
public void filterList() throws IOException {
Scan scan = new Scan();
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("f1".getBytes(), "name".getBytes(), CompareFilter.CompareOp.EQUAL, "劉備".getBytes());
PrefixFilter prefixFilter = new PrefixFilter("00".getBytes());
FilterList filterList = new FilterList();
filterList.addFilter(singleColumnValueFilter);
filterList.addFilter(prefixFilter);
scan.setFilter(filterList);
ResultScanner scanner = table.getScanner(scan);
printlReult(scanner);
}
7.6 HBase的刪除操作
1、根據rowkey刪除數據
- 刪除rowkey爲003的數據
/**
* 刪除數據
*/
@Test
public void deleteData() throws IOException {
Delete delete = new Delete("0003".getBytes());
delete.addFamily("f1".getBytes());
delete.addColumn("f2".getBytes(), "phone".getBytes());
table.delete(delete);
}
2、刪除表操作
/**
* 刪除表
*/
@Test
public void deleteTable() throws IOException {
//獲取管理員對象,用於表的刪除
Admin admin = connection.getAdmin();
//刪除一張表之前,需要先禁用表
admin.disableTable(TableName.valueOf("myuser"));
admin.deleteTable(TableName.valueOf("myuser"));
}