Hadoop學習(7)-hive的安裝和命令行使用和java操作

Hive的用處,就是把hdfs裏的文件建立映射轉化成數據庫的表

 

但hive裏的sql語句都是轉化成了mapruduce來對hdfs裏的數據進行處理

,並不是真正的在數據庫裏進行了操作。

而那些表的定義則是儲存在了mysql數據庫中,他只是記錄相應表的定義

所以你的集羣中要有一臺機器裝了mysql

裝hive,裝到哪都行

然後解壓tar –zxvf xxxxx –C apps

然後進入到這個目錄裏下的conf裏

創建hive-site.xml文件

告訴他mysql在哪,連接驅動是啥,用戶名和密碼

然後進入lib目錄下,把jdbc jar 包放到該目錄下

 

然後是啓動hive

你的hadoop和hive要配置的有環境變量

 echo $PATH   //可以查看配置的環境變量

echo $HADOOP-HOME //可以查看具體的哪一個

然後最好把hadoop和yarn都啓動起來

然後再安裝目錄裏bin/hive就可以啓動了

 

默認的是default數據庫

創建數據庫和表都會在真正的hdfs裏面創建目錄

 

 

 然後如果你要是想往表裏面導數據,你需要把相應的文件用 ^A 來分割放到hdfs裏的相應目錄下

 

 

 

然後把這個文件上傳到hdfs裏面

  hadoop fs  -put stu.info /user/hive/warehouse/t_big24/

 

在hive交互頁面中,顯示當前庫

 

設置一些基本參數,讓hive使用起來更便捷,比如:

1、讓提示符顯示當前庫:

hive>set hive.cli.print.current.db=true;

2、顯示查詢結果時顯示字段名稱:

hive>set hive.cli.print.header=true;

 

但是這樣設置只對當前會話有效,重啓hive會話後就失效,解決辦法:

在linux的當前用戶目錄中,編輯一個.hiverc文件,將參數寫入其中:

vi .hiverc

set hive.cli.print.header=true;

set hive.cli.print.current.db=true;

 

配置hive環境變量

比如我hive是解壓在  /root/apps/hive-1.2.1

Vi /etc/profile

然後在最後加上

Export HIVE_HOME=/root/apps/hive-1.2.1

Export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$HIVE_HOME/bin

 

還可以把hive當成一個服務,使用客戶端來訪問這個服務

服務端口號10000

啓動hive服務

 bin/hiveserver2

然後可以在linux監聽端口號netstat -nltp

 

啓動成功後,可以在別的節點上用beeline去連接

啓動服務  bin/beeline

然後要連接他

!connect jdbc:hive2://hdp-01:10000

然後輸入賬戶root  沒有密碼

 

課外知識  標準輸出重定向。Linux裏1就是標準輸出

./linux腳本文件 1>/要輸入的文件名 2>/錯誤時要定向到的文件名 &

這樣就不會再終端打印了

/dev/null  是一個“黑洞”什麼東西都會刪除

 

上述啓動,會將這個服務啓動在前臺,如果要啓動在後臺,則命令如下:

nohup bin/hiveserver2 1>/dev/null 2>&1 &

前面加上nohup就是就算這個用戶退出,這個進程也會繼續

 

 

hive -e "sql命令"

 

這樣可以不用進到hive直接運行

 

然後,進一步,可以將上述命令寫入shell腳本中,以便於腳本化運行hive任務,並控制、調度衆多hive任務,示例如下:

vi t_order_etl.sh

#!/bin/bash

hive -e "select * from db_order.t_order"

hive -e "select * from default.t_user"

hql="create table  default.t_bash as select * from db_order.t_order"

hive -e "$hql"

 

如果要執行的hql語句特別複雜,那麼,可以把hql語句寫入一個文件:

vi x.hql

select * from db_order.t_order;

select count(1) from db_order.t_user;

 

然後,用hive -f /root/x.hql 來執行

 

 

 

use db_order;

create table t_order(id string,create_time string,amount float,uid string);

表建好後,會在所屬的庫目錄中生成一個表目錄

/user/hive/warehouse/db_order.db/t_order

只是,這樣建表的話,hive會認爲表數據文件中的字段分隔符爲 ^A

 

正確的建表語句爲:

create table t_order(id string,create_time string,amount float,uid string)

row format delimited

fields terminated by ',';

 

這樣就指定了,我們的表數據文件中的字段分隔符爲 ","

 

內部表(MANAGED_TABLE):表目錄按照hive的規範來部署,位於hive的倉庫目錄/user/hive/warehouse中

 

外部表(EXTERNAL_TABLE):表目錄由建表用戶自己指定

create external table t_access(ip string,url string,access_time string)

row format delimited

fields terminated by ','

location '/access/log';

外部表和內部表的特性差別:

1、內部表的目錄在hive的倉庫目錄中 VS 外部表的目錄由用戶指定

2、drop一個內部表時:hive會清除相關元數據,並刪除表數據目錄

3、drop一個外部表時:hive只會清除相關元數據;

 

分區表的實質是:在表目錄中爲數據文件創建分區子目錄,以便於在查詢時,MR程序可以針對分區子目錄中的數據進行處理,縮減讀取數據的範圍。

 

比如,網站每天產生的瀏覽記錄,瀏覽記錄應該建一個表來存放,但是,有時候,我們可能只需要對某一天的瀏覽記錄進行分析

 

1、創建帶分區的表

create table t_access(ip string,url string,access_time string)

partitioned by(dt string)

row format delimited

fields terminated by ',';

注意:分區字段不能是表定義中的已存在字段

 

 

向分區中導入數據

load data local inpath '/root/access.log.2017-08-04.log' into table t_access partition(dt='20170804');

load data local inpath '/root/access.log.2017-08-05.log' into table t_access partition(dt='20170805');

 

針對分區數據進行查詢

統計8月4號的總PV

select count(*) from t_access where dt='20170804';

實質:就是將分區字段當成表字段來用,就可以使用where子句指定分區了

 

 

建表:

create table t_partition(id int,name string,age int)

partitioned by(department string,sex string,howold int)

row format delimited fields terminated by ',';

 

導數據:

load data local inpath '/root/p1.dat' into table t_partition partition(department='xiangsheng',sex='male',howold=20);

 

可以通過已存在表來建表:

1、create table t_user_2 like t_user;

新建的t_user_2表結構定義與源表t_user一致,但是沒有數據

 

2、在建表的同時插入數據

create table t_access_user

as

select ip,url from t_access;

t_access_user會根據select查詢的字段來建表,同時將查詢的結果插入新表中

 

1.1.1.   將hive表中的數據導出到指定路徑的文件

1、將hive表中的數據導入HDFS的文件

insert overwrite directory '/root/access-data'

row format delimited fields terminated by ','

select * from t_access;

 

 

2、將hive表中的數據導入本地磁盤文件

insert overwrite local directory '/root/access-data'

row format delimited fields terminated by ','

select * from t_access limit 100000;

 

hql裏面的數據類型和普通的沒什麼區別

 array數組類型

arrays: ARRAY<data_type> (Note: negative values and non-constant expressions are allowed as of Hive 0.14.)

 

示例:array類型的應用

假如有如下數據需要用hive的表去映射:

戰狼2,吳京:吳剛:龍母,2017-08-16

三生三世十里桃花,劉亦菲:癢癢,2017-08-20

設想:如果主演信息用一個數組來映射比較方便

 

 

建表:

create table t_movie(moive_name string,actors array<string>,first_show date)

row format delimited fields terminated by ','

collection items terminated by ':';

 

導入數據:

load data local inpath '/root/movie.dat' into table t_movie;

 

查詢:

select * from t_movie;

select moive_name,actors[0] from t_movie;

select moive_name,actors from t_movie where array_contains(actors,'吳剛');

select moive_name,size(actors) from t_movie;

 

map類型

1)         假如有以下數據:

1,zhangsan,father:xiaoming#mother:xiaohuang#brother:xiaoxu,28

2,lisi,father:mayun#mother:huangyi#brother:guanyu,22

3,wangwu,father:wangjianlin#mother:ruhua#sister:jingtian,29

4,mayun,father:mayongzhen#mother:angelababy,26

 

可以用一個map類型來對上述數據中的家庭成員進行描述

 

2)         建表語句:

create table t_person(id int,name string,family_members map<string,string>,age int)

row format delimited fields terminated by ','

collection items terminated by '#'

map keys terminated by ':';

 

3)         查詢

select * from t_person;

 

## 取map字段的指定key的值

select id,name,family_members['father'] as father from t_person;

 

## 取map字段的所有key

select id,name,map_keys(family_members) as relation from t_person;

 

## 取map字段的所有value

select id,name,map_values(family_members) from t_person;

select id,name,map_values(family_members)[0] from t_person;

 

## 綜合:查詢有brother的用戶信息

select id,name,father

from

(select id,name,family_members['brother'] as father from t_person) tmp

where father is not null;

struct類型

1)         假如有如下數據:

1,zhangsan,18:male:beijing

2,lisi,28:female:shanghai

 

其中的用戶信息包含:年齡:整數,性別:字符串,地址:字符串

設想用一個字段來描述整個用戶信息,可以採用struct

 

2)         建表:

create table t_person_struct(id int,name string,info struct<age:int,sex:string,addr:string>)

row format delimited fields terminated by ','

collection items terminated by ':';

 

3)         查詢

select * from t_person_struct;

select id,name,info.age from t_person_struct;

其他的執行語句和sql裏面的是基本一樣的

注意: 一旦有group by子句,那麼,在select子句中就不能有 (分組字段,聚合函數) 以外的字段

 

## 爲什麼where必須寫在group by的前面,爲什麼group by後面的條件只能用having

因爲,where是用於在真正執行查詢邏輯之前過濾數據用的

having是對group by聚合之後的結果進行再過濾;

 

上述語句的執行邏輯:

1、where過濾不滿足條件的數據

2、用聚合函數和group by進行數據運算聚合,得到聚合結果

3、用having條件過濾掉聚合結果中不滿足條件的數據

 

 

假如有以下數據:

1,zhangsan,化學:物理:數學:語文

2,lisi,化學:數學:生物:生理:衛生

3,wangwu,化學:語文:英語:體育:生物

映射成一張表:

create table t_stu_subject(id int,name string,subjects array<string>)

row format delimited fields terminated by ','

collection items terminated by ':';

然後,我們利用這個explode的結果,來求去重的課程:

select distinct tmp.sub

from

(select explode(subjects) as sub from t_stu_subject) tmp;

 

 

然後java代碼操作的話,需要現在服務器上開啓hive2服務,這個跟上面使用beeline連接hive是一個道理

 

 

 

需要的包在解壓後的hive裏面都有

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class getConnection {
 public getConnection() {
 }

 public static Connection getConnection() throws ClassNotFoundException, SQLException {
     Class.forName("org.apache.hive.jdbc.HiveDriver");
     Connection connection = DriverManager.getConnection("jdbc:hive2://hdp-02:10000/test","root","123456");
     
     return connection;
 }
}

這樣就可以獲得一個連接

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class getData {
    public getData() {
    }

    public static void getdata() throws ClassNotFoundException, SQLException {
        Connection connection = getConnection.getConnection();
        Statement statement = connection.createStatement();
        String sql = "select * from people";
        ResultSet res = statement.executeQuery(sql);while(res.next()) {
            System.out.println(res.getString(1) + "  " + res.getString(2) + "  " + res.getString(3) + "  " + res.getString(4));
        }

        res.close();
        statement.close();
        connection.close();
        return res;
        
    }
}

這個其實和連接普通的mysql也沒啥區別........

 

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