API調用
工作中更常用的絕對是通過HBase的API來調用實現類似HBase shell
的操作。
環境準備
IDEA + Maven + HBase
<?xml version="1.0" encoding="UTF-8"?>
<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.sowhat.demo</groupId>
<artifactId>hbasetest</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 屬性的形式指定JDK版本 -->
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!-- 添加若干依賴-->
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<!-- 主要是定製化打包
https://www.cnblogs.com/fnlingnzb-learner/p/10537228.html-->
<version>3.0.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.sowhat.demo.TestHBase</mainClass>
</manifest>
<!-- 指定main方法所在文件 -->
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
<!--將依賴的第三方jar包打包到jar中,這樣方便我們發佈可執行的jar包。 -->
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!--名字任意 -->
<phase>package</phase>
<!-- 綁定到package生命週期階段上 -->
<goals>
<goal>single</goal>
<!-- 只運行一次 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Commons
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
import java.util.ArrayList;
private static Connection connection; // 創建連接
private static Admin admin; // admin 對象
static
{
try
{
//創建配置信息 其中ZK的配置一般要跟 HBase/conf/hbase-site.xml裏 hbase.zookeeper.quorum 配置一樣
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "hadoop102,hadoop103,hadoop104");
//創建連接
connection = ConnectionFactory.createConnection(configuration);
//創建Admin對象
admin = connection.getAdmin();
} catch (IOException e)
{
e.printStackTrace();
}
}
public static void close() // 用完後合理關閉
{
try
{
if (admin != null)
{
admin.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
try
{
if (connection != null)
{
connection.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
API操作HBase
1. 判斷表是否存在
//1.判斷表是否存在 老版本方法,已經棄用
public static boolean isTableExistOld(String tableName) throws IOException
{
//創建配置信息
HBaseConfiguration configuration = new HBaseConfiguration();
//給配置信息添加參數
configuration.set("hbase.zookeeper.quorum", "hadoop102,hadoop103,hadoop104");
//創建HBase客戶端
HBaseAdmin admin = new HBaseAdmin(configuration);
//執行判斷
boolean exists = admin.tableExists(tableName);
//關閉連接
admin.close();
return exists;
}
//1.判斷表是否存在
public static boolean isTableExistNew(String tableName) throws IOException
{
//執行判斷
return admin.tableExists(TableName.valueOf(tableName));
}
2. 創建表
創建表的時候必須制定起碼一個列族。
//2.創建表 多個列族
public static void createTable(String tableName, String... cfs) throws IOException
{
//判斷列族個數
if (cfs.length < 1)
{
System.out.println("請設置正確的列族信息!!!");
return;
}
//判讀表是否存在
if (isTableExistNew(tableName))
{
System.out.println("表" + tableName + "已存在!!!");
return;
}
//創建表描述器
HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));
//循環添加列族信息
for (String cf : cfs)
{
//創建列族描述器
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(cf);
//添加列族信息
hTableDescriptor.addFamily(hColumnDescriptor);
}
//創建表
admin.createTable(hTableDescriptor);
}
3. 刪除表
//3.刪除表
public static void dropTable(String tableName) throws IOException
{
//判斷表是否存在
if (!isTableExistNew(tableName))
{
System.out.println("表" + tableName + "不存在!!!");
return;
}
//使表下線
admin.disableTable(TableName.valueOf(tableName));
//刪除表操作
admin.deleteTable(TableName.valueOf(tableName));
}
4. 創建namespace
//4.創建命名空間
public static void createNS(String nameSpace) throws IOException
{
//創建命名空間描述器 addConfiguration可選擇性添加,
NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(nameSpace).addConfiguration("createTime", System.currentTimeMillis() + "").build();
//創建命名空間
try
{
admin.createNamespace(namespaceDescriptor);
} catch (NamespaceExistException e)
{
System.out.println("命名空間" + nameSpace + "已存在!!!");
} catch (IOException e)
{
e.printStackTrace();
}
}
5. 刪除namespace
//5.刪除命名空間
public static void deleteNS(String nameSpace)
{
try
{
//執行刪除操作
admin.deleteNamespace(nameSpace);
} catch (IOException e)
{
e.printStackTrace();
}
}
6. 插入數據
一個RowKey對應一個Put,可創建
//6.插入數據:put "stu","1001","info:name","qiangquan"
public static void putData(String tableName, String rowKey, String cf, String cn, String value) throws IOException
{
//獲取表對象
Table table = connection.getTable(TableName.valueOf(tableName));
//創建Put對象 一個RowKey 對應一個 Put,可以構建多個Put來配合多個RowKey,
Put put = new Put(Bytes.toBytes(rowKey));
//給Put對象添加數據 可插入 1~N條數據
put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn), Bytes.toBytes(value));
put.addColumn(Bytes.toBytes(cf), Bytes.toBytes("sex"), Bytes.toBytes("male"));
put.addColumn(Bytes.toBytes(cf), Bytes.toBytes("addr"), Bytes.toBytes("SZ"));
//插入數據 支持table.put(List<put>)
table.put(put);
//關閉表連接
table.close();
}
7. get查詢
get 'stu','1001'
get 'stu','1001','info'
get 'stu','1001','info:name'
根據上面的查詢不同傳入不同參數,選擇性配置即可,一個Get,
//7.查詢數據(get):get "stu","1001","info:name"
public static void getData(String tableName, String rowKey, String cf, String cn) throws IOException
{
//1. 獲取表對象
Table table = connection.getTable(TableName.valueOf(tableName));
//2. 創建Get對象 跟Put對應
Get get = new Get(Bytes.toBytes(rowKey));
//2.1 指定查詢的列族 get 'stu','1001','info' 這個跟下面的根據參數不同選擇性使用哦
get.addFamily(Bytes.toBytes(cf));
//2.2 指定查詢的列族 get 'stu','1001','info:name'
get.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn));
//2.3 設置獲取數據的最大版本數
get.setMaxVersions();
//3. 執行查詢
Result result = table.get(get);
//4. 解析result get 'sut','1002' 這樣的格式 解析一行的若干數據
for (Cell cell : result.rawCells())
{
System.out.println("RowKey: " + Bytes.toString(CellUtil.cloneRow(cell)) +
",CF: " + Bytes.toString(CellUtil.cloneFamily(cell)) +
",CN: " + Bytes.toString(CellUtil.cloneQualifier(cell)) +
",Value: " + Bytes.toString(CellUtil.cloneValue(cell)) +
",TimeStamp:" + cell.getTimestamp());
}
//
//關閉連接
table.close();
}
當然也可以同時查詢多個rowKeys
//8.獲取數據(get),批量獲取 若干 rowKeys
public static void getData(String tableName, String... rowKeys) throws IOException
{
//獲取表對象
Table table = connection.getTable(TableName.valueOf(tableName));
//創建存放Get對象的集合
ArrayList<Get> gets = new ArrayList<>();
//循環創建Get對象
for (String rowKey : rowKeys)
{
//創建Get對象
Get get = new Get(Bytes.toBytes(rowKey));
//將Get對象放入gets
gets.add(get);
}
//獲取數據結果
Result[] results = table.get(gets);
//解析results
for (Result result : results)
{
//解析result
for (Cell cell : result.rawCells())
{
System.out.println("RowKey:" + Bytes.toString(CellUtil.cloneRow(cell)) +
",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
",Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
//關閉連接
table.close();
}
8. scan 獲取數據
scan tableName
//9.掃描表數據(scan)
public static void scanTable(String tableName) throws IOException
{
//獲取表對象
Table table = connection.getTable(TableName.valueOf(tableName));
//創建一個Scan對象 還可以傳入 startRow endRow 還可以添加filter
Scan scan = new Scan();
// Scan scan = new Scan(Bytes.toBytes("1001"),Bytes.toBytes("1002"));
//掃描表獲取數據
ResultScanner resultScanner = table.getScanner(scan);
//遍歷resultScanner
for (Result result : resultScanner)
{
//解析result
for (Cell cell : result.rawCells())
{
System.out.println("RowKey:" + Bytes.toString(CellUtil.cloneRow(cell)) +
",CF:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
",Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
//關閉連接
table.close();
}
9. 刪除數據
delete rowkey 刪除的ColumnFamily 刪除多個版本。
delete rowkey cf 刪除的ColumnFamily 刪除多個版本。
delete rowkey cf cn {column,columns}
重點
: 跟蹤HBase的刪除源碼你會發現最終還是進入到了添加數據到業務邏輯代碼中,無非就是 以前我們put數據到時候是value,現在變成了type = Column 跟ColumnFamily而已。
//10.刪除數據
public static void deleteData(String tableName, String rowKey, String cf, String cn) throws IOException
{
//1. 獲取表對象
Table table = connection.getTable(TableName.valueOf(tableName));
//2. 創建一個Delete對象 delete 跟deleteall 都調用此窗口 deleteall 'stu','1001'
Delete delete = new Delete(Bytes.toBytes(rowKey));
//2.1 指定刪除數據的列族和列,默認刪除最新時間戳的數據,帶時間戳就是刪除 指定列指定版本
// 如果插入了 name=old,name=new 但是麼有flush,則刪除new 後還可以查詢到old,
// 如果 name=old,name=new flush後 刪除new 就查詢不到old了,慎用 這個方法。
delete.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn),123);
//2.2 不帶時間戳則刪除所有版本,帶時間戳則刪除所有小於時間戳的版本
delete.addColumns(Bytes.toBytes(cf), Bytes.toBytes(cn));
//指定刪除數據的列族 delete 'stu','1001','info'
delete.addFamily(Bytes.toBytes(cf));
//執行刪除數據操作
table.delete(delete);
//關閉連接
table.close();
}
// 刪除多行數據
public static void deleteMultiRow(String tableName, String... rows) throws IOException{
HTable hTable = new HTable(conf, tableName);
List<Delete> deleteList = new ArrayList<Delete>();
for(String row : rows){
Delete delete = new Delete(Bytes.toBytes(row));
deleteList.add(delete);
}
hTable.delete(deleteList);
hTable.close();
}
10 . main
public static void main(String[] args) throws IOException
{
//判斷表是否存在(舊)
System.out.println(isTableExistOld("dddas"));
//判斷表是否存在(新)
System.out.println(isTableExistNew("bbb"));
//創建表
createTable("fruit", "info");
//刪除表
dropTable("bigdata");
//創建命名空間
createNS("aaa");
//刪除命名空間
deleteNS("bigdata");
//插入數據
putData("aaa", "1006", "info", "name", "xinxin");
//獲取一行數據
getData("aaa", "1001", "1002", "1003", "1005", "1006");
//掃描全表
scanTable("fruit");
//刪除數據
deleteData("aaa", "1006", "info2", "name");
close();
}
可在本地執行,也可以打包後在可訪問HBase服務的集羣上jar方式執行。
MapReduce操作HBase
HBase就把他當做大數據中的數據庫即可,然後任何可以分析HBase的引擎比如MR,Hive,spark鏈接上HBase都可以實現控制。
接下來吧MR需要操作HBase的若干Jar放到MR中。
- 查看MR操作HBase數據需要那些Jar包
$ bin/hbase mapredcp
---顯示出如果用MR來調用Hbase依賴的若干jar
/usr/local/src/hbase/hbase-2.2.2/lib/shaded-clients/hbase-shaded-mapreduce-....
- 環境變量的導入
- 執行環境變量的導入(臨時生效,在命令行執行下述操作)
$ export HBASE_HOME=/opt/module/hbase
$ export HADOOP_HOME=/opt/module/hadoop-2.7.2
$ export HADOOP_CLASSPATH= `${HBASE_HOME}/bin/hbase mapredcp` // 這裏是將變量賦值給mapredcp
- 永久生效:在/etc/profile 配置
export HBASE_HOME=/opt/module/hbase
export HADOOP_HOME=/opt/module/hadoop-2.7.2
並在 Hadoop裏的etc裏面找到 hadoop-env.sh 中配置:(注意:在 for 循環之後配)
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/opt/module/hbase/lib/*
然後重啓Hadoop跟HBase
bin/stop-hbase.sh
hadoop 全部關閉
上述配置後文件全部分`發到所以節點`,
然後重啓Hadoop跟Hbase
1. 官方案例
實現 MR跟 HBase 之間交互數據。
案例一: 讀取HBase數據到MR中
統計 Student 表中有多少行數據,在HBase目錄下執行如下代碼,。
/usr/local/src/hadoop/hadoop-3.1.3/bin/yarn jar /usr/local/src/hbase/hbase-2.2.2/lib/hbase-server-2.2.2.jar rowcounter sowhat
---- 跟在hbase shell 執行 count 'sowhat'一樣
案例二:使用 MapReduce 將本地數據導入到 HBase
- 在本地創建一個tsv格式的文件:fruit.tsv
1001 Apple Red
1002 Pear Yellow
1003 Pineapple Yellow
- 創建HBase表
hbase(main):001:0> create 'fruit','info'
- 在HDFS中創建input_fruit文件夾並上傳fruit.tsv文件
$ /opt/module/hadoop-2.7.2/bin/hdfs dfs -mkdir /input_fruit/
$ /opt/module/hadoop-2.7.2/bin/hdfs dfs -put fruit.tsv /input_fruit/
- 執行MapReduce到HBase的fruit表中
$ /opt/module/hadoop-2.7.2/bin/yarn jar lib/hbase-server-1.3.1.jar importtsv \
-Dimporttsv.columns=HBASE_ROW_KEY,info:name,info:color fruit \
hdfs://hadoop102:9000/input_fruit
- 使用scan命令查看導入後的結果
hbase(main):001:0> scan ‘fruit’
2. 自定義實現
1. 讀HDFS寫到HBase
目標
:實現將HDFS中的數據寫入到HBase表中。
HDFS2HBaseMapper
package com.atguigu.mr2;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
import java.io.IOException;
public class HDFS2HBaseMapper extends Mapper<LongWritable, Text, NullWritable, Put> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//獲取一行數據並切分
String[] fields = value.toString().split("\t");
//創建Put對象
Put put = new Put(Bytes.toBytes(fields[0]));
//給Put對象賦值
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes(fields[1]));
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("color"), Bytes.toBytes(fields[2]));
//寫出
context.write(NullWritable.get(), put);
}
}
HDFS2HBaseReducer
package com.atguigu.mr2;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.NullWritable;
import java.io.IOException;
public class HDFS2HBaseReducer extends TableReducer<NullWritable, Put, NullWritable> {
@Override
protected void reduce(NullWritable key, Iterable<Put> values, Context context) throws IOException, InterruptedException {
//遍歷寫出
for (Put value : values) {
context.write(key, value);
}
}
}
HDFS2HBaseDriver
package com.atguigu.mr2;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class HDFS2HBaseDriver extends Configuration implements Tool {
//聲明配置信息
private Configuration configuration;
@Override
public int run(String[] args) throws Exception {
//1.創建Job對象
Job job = Job.getInstance(configuration);
//2.設置主類
job.setJarByClass(HDFS2HBaseDriver.class);
//3.設置Mapper
job.setMapperClass(HDFS2HBaseMapper.class);
//4.設置Mapper的輸出類型
job.setMapOutputKeyClass(NullWritable.class);
job.setMapOutputValueClass(Put.class);
//5.設置Reducer
TableMapReduceUtil.initTableReducerJob(args[1], HDFS2HBaseReducer.class, job);
//6.設置輸入路徑
FileInputFormat.setInputPaths(job, new Path(args[0]));
//7.提交任務
boolean result = job.waitForCompletion(true);
return result ? 0 : 1;
}
@Override
public void setConf(Configuration conf) {
configuration = conf;
}
@Override
public Configuration getConf() {
return configuration;
}
public static void main(String[] args) {
//創建配置信息
Configuration configuration = new Configuration();
//運行
try {
int run = ToolRunner.run(configuration, new HDFS2HBaseDriver(), args);
System.exit(run);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. HBase to HBase
目標:將fruit表中的一部分數據,通過MR遷入到fruit_mr表中。
package com.atguigu.mr1;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
// 讀取HBase 數據
public class FruitMapper extends TableMapper<ImmutableBytesWritable, Put> {
@Override
protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {
//創建Put對象
Put put = new Put(key.get());
//遍歷value(一行數據)
for (Cell cell : value.rawCells()) {
if ("name".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))) {
//給put設置值
put.add(cell);
}
}
//寫出
context.write(key, put);
}
}
---
package com.atguigu.mr1;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class FruitReducer extends TableReducer<ImmutableBytesWritable, Put, ImmutableBytesWritable> {
@Override
protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context) throws IOException, InterruptedException {
//遍歷寫出
for (Put value : values) {
context.write(key, value);
}
}
}
---
package com.atguigu.mr1;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class FruitDriver extends Configuration implements Tool {
//聲明配置信息
Configuration configuration;
@Override
public int run(String[] args) throws Exception {
//1.創建Job對象
Job job = Job.getInstance(configuration);
//2.設置主類
job.setJarByClass(FruitDriver.class);
//3.設置Mapper類
TableMapReduceUtil.initTableMapperJob("sowhat",
new Scan(),
FruitMapper.class,
ImmutableBytesWritable.class,
Put.class,
job);
//4.設置Reducer類
TableMapReduceUtil.initTableReducerJob("sowhat1412",
FruitReducer.class,
job);
//5.提交
boolean result = job.waitForCompletion(true);
return result ? 0 : 1;
}
@Override
public void setConf(Configuration conf) {
configuration = conf;
}
@Override
public Configuration getConf() {
return configuration;
}
public static void main(String[] args) {
//創建配置信息
Configuration configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.quorum", "host-10-100-34-111,host-10-100-34-120,host-10-100-34-140");
try {
int result = ToolRunner.run(configuration, new FruitDriver(), args);
System.exit(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
PS
: 在集羣上操作時候我們把HBase若干jar放到了Hadoop環境變量中,而本地開發的時候可不幹,是因爲Hbase的依賴中包含了Hadoop的核心代碼。
並且本地開發的話,一般要把Hbase集羣中的hbase-site.xml
文件加載到IDEA的resource中,來幫助本地代碼找到ZK集羣。當然你也可以選擇把ZK的配置寫入到配置文件中。如上。windows運行遇到問題 依賴
Hive操作HBase
我們可以把Hive跟HBase進行關聯起來,然後Hive中的數據不再由HDFS存儲而是存儲到HBase中,並且,關聯後Hive中添加數據在HBase中可看到,HBase中添加數據Hive也可看到。
Hive
- 數據倉庫
Hive的本質其實就相當於將HDFS中已經存儲的文件在Mysql中做了一個雙射關係,以方便使用HQL去管理查詢。 - 用於數據分析、清洗
Hive適用於離線的數據分析和清洗,延遲較高。 - 基於HDFS、MapReduce
Hive存儲的數據依舊在DataNode上,編寫的HQL語句終將是轉換爲MapReduce代碼執行。 - 分析框架,元數據信息給MySQL
HBase
- 數據庫
是一種面向列族存儲的非關係型數據庫。 - 用於存儲結構化和非結構化的數據(其實更多是結構化,MongoDB來存非結構化多一些)
適用於單表非關係型數據的存儲,不適合做關聯查詢 sum ,avg等
,類似JOIN等操作。 - 基於HDFS
數據持久化存儲的體現形式是Hfile,存放於DataNode中,被ResionServer以region的形式進行管理。 - 延遲較低,接入在線業務使用
面對大量的企業數據,HBase可以直線單表大量數據的存儲,同時提供了高效的數據訪問速度
。 - HBase 存儲框架 自己保持元數據信息。
- 數據量不夠大其實用 Redis,ES跟更好點。
HBase與Hive集成使用
尖叫提示
:HBase與Hive的集成在最新的兩個版本中無法兼容。所以,我們只能含着淚勇敢的重新編譯:hive-hbase-handler-1.2.2.jar,兼容後相當於Hive的數據存儲在HBase中了。兼容配置百度即可。
環境準備
因爲我們後續可能會在操作Hive的同時對HBase也會產生影響,所以Hive需要持有操作HBase的Jar,那麼接下來拷貝Hive所依賴的Jar包(或者使用軟連接的形式)。
export HBASE_HOME=/opt/module/hbase
export HIVE_HOME=/opt/module/hive
ln -s $HBASE_HOME/lib/hbase-common-1.3.1.jar $HIVE_HOME/lib/hbase-common-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-server-1.3.1.jar $HIVE_HOME/lib/hbase-server-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-client-1.3.1.jar $HIVE_HOME/lib/hbase-client-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-protocol-1.3.1.jar $HIVE_HOME/lib/hbase-protocol-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-it-1.3.1.jar $HIVE_HOME/lib/hbase-it-1.3.1.jar
ln -s $HBASE_HOME/lib/htrace-core-3.1.0-incubating.jar $HIVE_HOME/lib/htrace-core-3.1.0-incubating.jar
ln -s $HBASE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop2-compat-1.3.1.jar
ln -s $HBASE_HOME/lib/hbase-hadoop-compat-1.3.1.jar $HIVE_HOME/lib/hbase-hadoop-compat-1.3.1.jar
同時在hive-site.xml中修改zookeeper的屬性,如下:
<property>
<name>hive.zookeeper.quorum</name>
<value>hadoop102,hadoop103,hadoop104</value>
<description>The list of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
<property>
<name>hive.zookeeper.client.port</name>
<value>2181</value>
<description>The port of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
1. 案例一
目標
:建立Hive表,關聯HBase表,插入數據到Hive表的同時能夠影響HBase表。
分步實現: 根據位置關係進行映射,有點Hive跟neo4j的映射。
- 在Hive中創建表同時關聯HBase
CREATE TABLE hive_hbase_emp_table(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
提示
:完成之後,可以分別進入Hive和HBase查看,都生成了對應的表
2. 在Hive中創建臨時中間表,用於load文件中的數據
提示
:不能
將數據直接load進Hive所關聯HBase的那張表中
CREATE TABLE emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
row format delimited fields terminated by '\t';
- 向Hive中間表中load數據,結果是失敗的!
hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;
- 通過insert命令將中間表中的數據導入到Hive關聯HBase的那張表中,成功後數據就導入到HBase中了,記得Hbase的flush操作。
hive> insert into table hive_hbase_emp_table select * from emp;
- 查看Hive以及關聯的HBase表中是否已經成功的同步插入了數據
hive> select * from hive_hbase_emp_table;
hbase> scan ‘hbase_emp_table’
2. 更常用案例二
目標
:在HBase中已經
存儲了某一張表hbase_emp_table,然後在Hive中創建一個外部表來關聯HBase中的hbase_emp_table這張表,使之可以藉助Hive來分析HBase這張表中的數據。
注:該案例2緊跟案例1的腳步,所以完成此案例前,請先完成案例1。
- 在Hive中創建
外部表
CREATE EXTERNAL TABLE relevance_hbase_emp(
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
comm double,
deptno int)
STORED BY
'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" =
":key,info:ename,info:job,info:mgr,info:hiredate,info:sal,info:comm,info:deptno")
TBLPROPERTIES ("hbase.table.name" = "hbase_emp_table");
- 關聯後就可以使用Hive函數進行一些分析操作了
hive (default)> select * from relevance_hbase_emp;