第三天:HBase API

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查詢
  1. get 'stu','1001'
  2. get 'stu','1001','info'
  3. 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中。

  1. 查看MR操作HBase數據需要那些Jar包
$ bin/hbase mapredcp
---顯示出如果用MR來調用Hbase依賴的若干jar
/usr/local/src/hbase/hbase-2.2.2/lib/shaded-clients/hbase-shaded-mapreduce-....
  1. 環境變量的導入
  • 執行環境變量的導入(臨時生效,在命令行執行下述操作)
$ 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

  1. 在本地創建一個tsv格式的文件:fruit.tsv
1001	Apple	Red
1002	Pear		Yellow
1003	Pineapple	Yellow
  1. 創建HBase表
hbase(main):001:0> create 'fruit','info'
  1. 在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/
  1. 執行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
  1. 使用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

  1. 數據倉庫
    Hive的本質其實就相當於將HDFS中已經存儲的文件在Mysql中做了一個雙射關係,以方便使用HQL去管理查詢。
  2. 用於數據分析、清洗
    Hive適用於離線的數據分析和清洗,延遲較高。
  3. 基於HDFS、MapReduce
    Hive存儲的數據依舊在DataNode上,編寫的HQL語句終將是轉換爲MapReduce代碼執行。
  4. 分析框架,元數據信息給MySQL

HBase

  1. 數據庫
    是一種面向列族存儲的非關係型數據庫。
  2. 用於存儲結構化和非結構化的數據(其實更多是結構化,MongoDB來存非結構化多一些)
    適用於單表非關係型數據的存儲,不適合做關聯查詢 sum ,avg等,類似JOIN等操作。
  3. 基於HDFS
    數據持久化存儲的體現形式是Hfile,存放於DataNode中,被ResionServer以region的形式進行管理。
  4. 延遲較低,接入在線業務使用
    面對大量的企業數據,HBase可以直線單表大量數據的存儲,同時提供了高效的數據訪問速度
  5. HBase 存儲框架 自己保持元數據信息。
  6. 數據量不夠大其實用 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的映射。

  1. 在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';
  1. 向Hive中間表中load數據,結果是失敗的!
hive> load data local inpath '/home/admin/softwares/data/emp.txt' into table emp;
  1. 通過insert命令將中間表中的數據導入到Hive關聯HBase的那張表中,成功後數據就導入到HBase中了,記得Hbase的flush操作。
hive> insert into table hive_hbase_emp_table select * from emp;
  1. 查看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。

  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");
  1. 關聯後就可以使用Hive函數進行一些分析操作了
hive (default)> select * from relevance_hbase_emp;

參考

API
HBase API

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章