6大數據技術棧

22 一步一步搭建一個Hadoop集羣

經過前面的學習,瞭解了大數據的發展史、大數據在我們日常生活的應用。這一章我們着重講解大數據的實踐,本小結我們先學會搭建一個 Hadoop 集羣。

Hadoop 集羣運行模式

Hadoop 有以下三種運行模型。

  1. 本地模式 (Standalone): 不需要啓用單獨進程,直接可以運行,測試和開發時使用。

    僞分佈式模式 (Pseudo-Distributed): 等同於完全分佈式,只有一個節點。

    完全分佈式模式 (Fully-Distributed Operation): 多個節點一起運行。

Hadoop 運行環境搭建

Hadoop 是一個支持跨平臺運行的系統,既支持 Linux 系統(例如:Centos、Ubuntu ),也支持 Windows 系統。另外對於蘋果的 Mac 系統也是支持的。

在實際的工業大數據生產中,大多數使用 Centos 版本的 Linux 系統來搭建 Hadoop 集羣。我們下面的講解也是基於 Linux 系統來說的。

Hadoop 是用 Java 語言編寫的,所以 Hadoop 最基礎的運行環境就是 Java 環境。不同的 Hadoop 版本需要匹配不同的 Java 版本。Hadoop 版本和 Java 版本的對應關係參考 Hadoop 官網(https://wiki.apache.org/hadoop/HadoopJavaVersions)。

以 Java8 爲例說明 Java 環境搭建步驟。

  1. 下載 JDK Java SE 8 的官方網址是
    http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

    解壓文件 我們在 /home/software 文件夾下面解壓縮剛纔下載好的文件。

    tar -xvf jdk-8u65-linux-x64.tar.gz 添加 Java 環境變量 通過 vim 命令打開
    /etc/profile 文件:

    vim /etc/profile 如果權限不夠請使用 sudo。

    sudo vim /etc/profile 將下面的環境變量信息拷貝到 /etc/profile 文件中,並保存。

    export JAVA_HOME=/home/software/jdk1.8.0_65 export
    JRE_HOME=/home/software/jdk1.8.0_65/jre export
    CLASSPATH=.:JAVAHOME/lib:JAVA_HOME/lib:JRE_HOME/lib:CLASSPATHexportPATH=CLASSPATH export PATH=JAVA_HOME/bin:JREHOME/bin:JRE_HOME/bin:PATH 讓 Java 環境變量生效 source
    /etc/profile Hadoop 集羣運行過程中,經常會有某一個節點的腳本去調用另外一個節點腳本的情況,腳本之間的調用需要使用
    ssh。

    安裝 ssh 以下是 Ubuntu Linux 安裝 ssh 環境的操作。其他版本的 liunx 系統安裝 ssh,同學們可以自行
    Google 搜索安裝方法。

    sudo apt-get install ssh sudo apt-get install pdsh 下載 Hadoop 文件 從
    Hadoop 下載地址:http://www.apache.org/dyn/closer.cgi/hadoop/common/
    選擇你想安裝的 Hadoop 版本下載,並解壓縮。以下以 2.7.7 版本的 Hadoop 爲例。

    tar -xvf hadoop-2.7.7.tar.gz 通過 vim 編輯解押後文件夾下面的
    etc/hadoop/hadoop-env.sh 文件。添加下面的內容並保存 hadoop-env.sh 文件。

    set to the root of your Java installation export

    JAVA_HOME=/home/software/jdk1.8.0_65 查看 Hadoop 環境是否搭建成功 運行以下命令,如果
    Hadoop 的版本能正常打印出來,說明 Hadoop 環境已經搭建好了。

    bin/hadoop 本地模式 (Standalone)

    通過本地模式運行 Word Count 例子,同學們先感受一下 Hadoop。

    在 hadoop-2.7.7 文件夾下面創建一個 wcInput 文件夾

    mkdir wcInput 在 wcInput 文件下創建一個 wc.input 文件,並輸入以下內容

    hello hadoop hello mapreduce hello yarn 在 hadoop-2.7.7 文件夾下面創建一個
    wcOutput 文件夾

    mkdir wcOutput 回到 hadoop-2.7.7 文件夾下,執行程序

    hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    wcInput wcOutput Word count 程序的執行結果在 wcOutput 文件夾裏面。

    僞分佈式模式 (Pseudo-Distributed)

    Hadoop 也可以以僞分佈模式的方式運行在單節點上,這個時候每一個 Hadoop 守護進程都是一個單獨的 Java 進程.

    這種模式需要進行相應的分佈式設置,但是又由於只有一個節點,所以我們稱之爲僞分佈模式。

    由於 Hadoop2.x 增加了 Yarn, 所以有兩個選擇:可以把 MapReduce 程序直接運行在 HDFS 上,也可以選擇運行在
    Yarn 上。

    在 HDFS 上運行 MapReduce 程序

    配置 core-site.xml (核心站點)
    fs.defaultFS

    hdfs://hadoop1_host:9000
    hadoop.tmp.dir
    /home/software/hadoop-2.7.7/data/tmp 配置 hdfs-site.xml (hdfs 站點)
    dfs.replication
    1 這裏設置的副本的數量是指 HDFS 上存儲的文件的副本。

    格式化 NameNode hdfs namenode -format 啓動 namenode hadoop-daemon.sh
    start namenode 啓動 datanode hadoop-daemon.sh start datanode 查看
    namenode 和 datanode 是否啓動成功 jps 在本地創建一個文件 words.txt, 文件內容可以自己隨意添加。
    hello word Big Data test 1 在 hdfs 系統的根目錄下創建一個文件夾 /input。 hdfs dfs
    -mkdir /input 把 words.txt 上傳到 hdfs 系統上的 /input 目錄下 hdfs dfs -put words.txt /input 查看是否上傳成功 hdfs dfs -ls /input 在集羣上運行 wordcount 程序
    hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    /input /output 查看輸出結果 hdfs dfs -cat /output/part-r-00000 在 Yarn 上運行
    MapReduce 程序

    Hadoop2.x 增加了組件 Yarn, 我們也可以把我們的 MapReduce 程序在 Yarn 上執行。 在前面配置的基礎上,配置
    Yarn 就可以了。

    配置 yarn-site.xml
    yarn.nodemanager.aux-services
    mapreduce_shuffle
    yarn.resourcemanager.hostname

    hadoop1_host 配置 /etc/hadoop/mapred-site.xml 複製一份配置

    cp mapred-site.xml.template mapred-site.xml 配置
    /etc/hadoop/mapred-site.xml

    mapreduce.framework.name yarn

    啓動 resourcemanager yarn-daemon.sh start resourcemanager
    啓動 nodemanager yarn-daemon.sh start nodemanager 運行 MapReduce
    程序:wordcount hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    /input /output2 查看執行結果 hdfs dfs -cat /output2/part-r-00000 完全分佈式模式
    (Fully-Distributed Operation)

    本地運行模式和僞分佈運行模式,都是一種單節點運行模式。在實際的生產環境中需要處理的數據量會非常巨大,一個節點不可能完成超大規模數據的計算任務。所以實際生產環境都是使用安全分佈式模式部署的。

    爲了更真實的模擬實際生產環境中分佈式模式的部署情況,我們以三個節點的 Hadoop 分佈式模式集羣部署爲例進行講解。

    虛擬機準備

    準備 3 個虛擬機,虛擬機的 host 和 ip 地址如下:

    host1 192.168.124.1 host2 192.168.124.2 host3 192.168.124.3
    關閉防火牆,配置好三個機器 Java 環境。

    配置好 SSH 無祕鑰登錄

    生成祕鑰 輸入命令 ssh-keygen, 然後連敲 3 次回車。過程不要輸入任何信息。

    生成祕鑰都存儲在:~/.ssh 目錄下

    copy 公鑰到其他設備 ssh-copy-id 其他主機host 測試能否免密登錄 ssh 其他主機host
    需要重複以上操作,將三臺機器都配置好。

    規劃集羣部署和配置

    Yarn 和 Hdfs 需要分散部署到三個虛擬機上。我們按照以下集羣部署規劃,配置 Hadoop 配置文件。

    host1 host2 host3 HDFS NameNode DateNode DateNode SecondaryNameNode
    DateNode YARN NodeManager ResourceManager NodeManager NodeManager 修改
    hadoop-2.7.7/etc/hadoop 文件夾下面的配置。


core-site.xml
<!-- 指定HDFS中NameNode的地址 -->
  <property>
        <name>fs.defaultFS</name>
        <value>hdfs://host1:9000</value>
   </property>

<!-- 指定hadoop運行時產生文件的存儲目錄 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/home/software/hadoop-2.7.7/data/tmp</value>
    </property>
hadoop-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
hdfs-site.xml
<property>
  <name>dfs.replication</name>
  <value>3</value>
</property>
<property>
   <name>dfs.namenode.secondary.http-address</name>
   <value>host2:50090</value>
</property>
slaves
host1
host2
host3
yarn-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
yarn-site.xml
<!-- reducer獲取數據的方式 -->
<property>
         <name>yarn.nodemanager.aux-services</name>
         <value>mapreduce_shuffle</value>
</property>
<!-- 指定YARN的ResourceManager的地址 -->
<property>
     <name>yarn.resourcemanager.hostname</name>
     <value>host1</value>
</property>
mapred-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
mapred-site.xml
<!-- 指定mr運行在yarn上 -->
<property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
</property>
將主節點的 Hadoop 文件分發到另外兩個機器
rsync /home/software host2:/opt/
rsync /home/software host3:/opt/

啓動集羣

  1. 第一次啓動時需要格式化 namenode,在 namenode 上格式化

    /hdfs namenode -format 啓動 hdfs,在 namenode 上啓動 hdfs

    start-dfs.sh 啓動 yarn,在 ResourceManager 所在的機器啓動 yarn。

    start-yarn.sh 集羣啓動以後,就可以使用 Hadoop 集羣處理你的數據了。

總結

這一節,我帶着大家一起學習了三種 Hadoop 運行模式的搭建過程。本地模式 (Standalone)和僞分佈式模式 (Pseudo-Distributed) 主要用與我們測試和學習,實際的工業數據生產中使用的是完全分佈式模式 (Fully-Distributed Operation)。

以上是關於 Hadoop 的集羣部署

23 Apache Hive實戰

世上無難事,只要肯登攀。
—偉人
大家好,我是 RangeYan。

上一小節我帶着大家一起搭建了一個 Hadoop 集羣。這一小節我們一起學習一下 Apache Hive 實戰。

在學習 Hive 的實戰內容之間我們先簡單瞭解一下 Hive。

Hive 是什麼

Hive 是在 Hadoop 分佈式文件系統 (HDFS) 之上開發的 ETL 和數據倉庫工具,有 Facebook 實現並開源。

Hive 提供寫 SQL 的方式對存儲在 Hadoop 集羣裏面的數據進行清洗、加工,生成新的數據並存儲到 Hadoop 集羣當中。

對於大數據開發技術來說,SQL 是一等公民。

基於 SQL 的數據開發方式,讓 Hive 成爲了大數據處理領域最重要的一項技術。在 2020 年這個節點下,Hive 數據開發技術依然是數據開發工程師、數據產品經理、數據分析師、數據挖掘工程必備技能。

希望同學們務必認真學習 Hive 的內容,儘可能全部掌握。

Hive 架構

圖片描述

Hive 主要由三個部分組成:Clients(客戶端)、Serverices(服務)、Storage and compute(存儲和計算)。

Clients(客戶端):Hive 爲與不同類型的應用程序的通信提供了不同的驅動程序。Hive clinets 可以支持 Thrift、JDBC、ODBC 協議與 Hive services 進行通信。

Serverices(服務):Clients 與 Hive 的交互通過 Hive Services 執行。CLI 是命令行界面,充當 DDL(數據定義語言)操作的 Hive 服務。Serverices 核心的模塊是 Driver(驅動程序)。

Hive Services、CLI、Hive web Interface 都通過 Driver(驅動程序)對元數據、文件系統進行計算和處理。

Storage and compute(存儲和計算):Hive 的元數據存儲在元數據數據庫中,元數據數據庫支持 Mysql 等多種類型。Hive 的查詢結果和數據存儲在 Hadoop 中。

Hive 部署

依賴環境

Hive 需要 Hadoop 的存儲、計算環境,需要數據庫存儲元數據信息,存儲元數據的數據庫推薦使用 Mysql 數據庫。

所以在部署 Hive 之前需要部署好 Hadoop 和 Mysql。Hadoop 的集羣部署步驟我們在上一節講到了,Mysql 的部署方式請同學們自行 Google。

下載 Hive 安裝包

推薦一個 Hive 的下載地址:http://mirrors.hust.edu.cn/apache/hive/

選擇 2.3.6 版本的 Hive 並下載 apache-hive-2.3.6-bin.tar.gz 安裝包。

解壓安裝包

tar -zxvf apache-hive-2.3.6-bin.tar.gz
修改配置文件

配置文件所在目錄 apache-hive-2.3.6-bin/conf

使用 vi 新建配置文件 hive-site.xml,並添加配置內容

<configuration>
        <property>
                <name>javax.jdo.option.ConnectionURL</name>
                <value>jdbc:mysql://mysqlhost:3306/hivedb?createDatabaseIfNotExist=true</value>
                <description>JDBC connect string for a JDBC metastore</description>
                <!--  用mysql數據庫的真實host替換“mysqlhost”  -->
        </property>
        <property>
                <name>javax.jdo.option.ConnectionDriverName</name>
                <value>com.mysql.jdbc.Driver</value>
                <description>Driver class name for a JDBC metastore</description>
        </property>
        <property>
                <name>javax.jdo.option.ConnectionUserName</name>
                <value>root</value>
                <description>username to use against metastore database</description>
        </property>
        <property>
                <name>javax.jdo.option.ConnectionPassword</name>
                <value>root</value>
        <description>password to use against metastore database</description>
        </property>
</configuration>
Mysql 驅動包拷貝

將 mysql-connector-java-5.1.40-bin.jar 拷貝到 apache-hive-2.3.6-bin/lib 下面

配置 Hive 環境變量

用 vi 打開.bashrc 文件

vi ~/.bashrc
在.bashrc 文件重保存以下內容

#Hive
export HIVE_HOME=/home/soft/apache-hive-2.3.6-bin #配置hive安裝包目錄
export PATH=PATH:PATH:HIVE_HOME/bin
讓配置生效

source ~/.bashrc
初始化 Mysql 數據庫

schematool -dbType mysql -initSchema
啓動 Hive 客戶端

hive --service cli
Hive 數據結構

Hive 的存儲結構包括數據庫、表、視圖、分區和表數據

database:在 HDFS 中表現爲 ${hive.metastore.warehouse.dir} 目錄下一個文件夾
table:在 HDFS 中表現所屬 database 目錄下一個文件夾
external table:與 table 類似,不過其數據存放位置可以指定任意 HDFS 目錄路徑
partition:在 HDFS 中表現爲 table 目錄下的子目錄
bucket:在 HDFS 中表現爲同一個表目錄或者分區目錄下根據某個字段的值進行 hash 散列之後的多個文件
view:與傳統數據庫類似,只讀,基於基本表創建
Hive 中的表分爲內部表、外部表、分區表和 Bucket 表。

內部表和外部表的區別:

刪除內部表,刪除表元數據和數據

刪除外部表,刪除元數據,不刪除數據

分區表和分桶表的區別:

分區和分桶都是細化數據管理,但是分區表是手動添加區分。

由於 Hive 是讀模式,所以對添加進分區的數據不做模式校驗,分桶表中的數據是按照某些分桶字段進行 hash 散列形成的多個文件,所以數據的準確性也高很多。

Hive 支持的數據類型

類型 描述 示例
boolean true/false TRUE
tinyint 1 字節的有符號整數 -128~127 1Y
smallint 2 個字節的有符號整數,-32768~32767 1S
int 4 個字節的帶符號整數 1
bigint 8 字節帶符號整數 1L
float 4 字節單精度浮點數 1.0
double 8 字節雙精度浮點數 1.0
deicimal 任意精度的帶符號小數 1.0
String 字符串,變長 “a”,’b’
varchar 變長字符串 “a”,’b’
char 固定長度字符串 “a”,’b’
binary 字節數組 無法表示
timestamp 時間戳,納秒精度 122327493795
date 日期 ‘2020-05-09’
array 有序的的同類型的集合 array(1,2)
map key-value,key 必須爲原始類型,value 可以任意類型 map(‘a’,1,’b’,2)
struct 字段集合,類型可以不同 struct(‘1’,1,1.0), named_stract(‘col1’,’1’,’col2’,1,’clo3’,1.0)
Hive 默認的行和列分隔符如下表所示

分隔符 描述
\n 對於文本文件來說,每行是一條記錄,所以 \n 來分割記錄
^A (Ctrl+A) 分割字段,也可以用 \001 來表示
^B (Ctrl+B) 用於分割 Arrary 或者 Struct 中的元素,或者用於 map 中鍵值之間的分割,也可以用 \002 分割。
^C 用於 map 中鍵和值自己分割,也可以用 \003 表示。
Hive DDL

DDL 的英文全稱是 data definition language,用來對數據庫,表結構進行增、刪、改操作。

  1. 創建庫

創建普通的數據庫

create database databaseName1;
創建庫的時候檢查存與否

create database if not exists databaseName1;
創建庫的時候帶註釋

create database if not exists databaseName1 comment ‘hive learn’;
2. 查看庫

查看有哪些數據庫

show databases;
顯示數據庫的詳細屬性信息

desc database extended databaseName1;
查看創建庫的詳細語句

show create database databaseName1;
3. 刪除庫

刪除不含表的數據庫

drop database databaseName1;
刪除含有表的數據庫

drop database if exists databaseName1 cascade;
4. 切換庫

use databaseName1;
5. 創建表

創建表語句相對比較複雜,下面是創建表的語法規則

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

[(col_name data_type [COMMENT col_comment], …)]

[COMMENT table_comment]

[PARTITIONED BY (col_name data_type [COMMENT col_comment], …)]

[CLUSTERED BY (col_name, col_name, …)

[SORTED BY (col_name [ASC|DESC], …)] INTO num_buckets BUCKETS]

[ROW FORMAT row_format]

[STORED AS file_format]

[LOCATION hdfs_path]
上面創建表語句字段的解釋如下

•CREATE TABLE 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用 IF NOT EXIST 選項來忽略這個異常
•EXTERNAL 關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的路徑(LOCATION)
•LIKE 允許用戶複製現有的表結構,但是不復制數據
•COMMENT可以爲表與字段增加描述
•PARTITIONED BY 指定分區
•ROW FORMAT
  DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
    MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
    | SERDE serde_name [WITH SERDEPROPERTIES
    (property_name=property_value, property_name=property_value, …)]
  用戶在建表的時候可以自定義 SerDe 或者使用自帶的 SerDe。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的 SerDe。在建表的時候,
用戶還需要爲表指定列,用戶在指定表的列的同時也會指定自定義的 SerDe,Hive 通過 SerDe 確定表的具體的列的數據。
•STORED AS
  SEQUENCEFILE //序列化文件
  | TEXTFILE //普通的文本文件格式
  | RCFILE  //行列存儲相結合的文件
  | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname //自定義文件格式
  如果文件數據是純文本,可以使用 STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED AS SEQUENCE 。

•LOCATION指定表在HDFS的存儲路徑
創建默認的內部表示例如下:

create table car(
id int,
name string,
price double)
row format delimited fields terminated by “,”;
創建外部表

create external table car_ext(
id int,
name string,
price double)
row format delimited fields terminated by “,”
location “/hive/student”;
6. 查看錶

show tables;
7. 修改表

修改表名

alter table car rename to car_new;
增加一個字段

alter table car add columns (count int);
修改一個字段的定義

alter table car change name name_new string;
添加一個分區

alter table car add partition(name=“benchi”);
8. 刪除表

drop table car;
9. 清空表

truncate table car;
Hive DML

DML 的英文全稱是 data managed language,指的是對數據表裏面的數據進行操作。

  1. 表數據插入

數據從本地導入

load data local inpath ‘/home/data/car.txt’ into table car;
數據從 HDFS 加載

load data local inpath ‘/home/data/car.txt’ into table car;
單條數據插入

insert into table car values(2,“dazhong”,1000);
多條數據插入

insert into table car2 select * from car where id>80;
2. 單模式導出

insert overwrite local directory ‘home/data/test_hive’ select * from car where id=1303;
3. 數據查詢

– SELECT 列名稱 FROM 表名稱
select name from car;
4. 數據更新

– UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值
update cat set name = dazhong2 where id = 1302;
5. 數據刪除

– DELETE FROM 表名稱 WHERE 列名稱 = 值
delete from cat where id = 1302;
6. 數據表連接

內連接 [inner] join

兩個表中關聯鍵相同的記錄纔會查詢出來。

select * from a inner join b on a.id=b.id;
外連接 —— 左外連接
以左表爲主表,右表中有的就會關聯上,右表中沒有關聯上的數據就用 null 補齊。

select * from a left outer join b on a.id=b.id;
外連接 —— 右外連接
以右表爲主表,左表有的則關聯,沒有則 null 補齊

select * from a right outer join b on a.id=b.id;
外連接 —— 全外連接 full outer join
左表和右表中的並集,左表和右表中所有的數據都會關聯上

select * from a full outer join b on a.id=b.id;
半連接 left semi join 左半連接

判斷左表中的關聯建是否在右表中存在 ,若存在,則返回左表的存在的數據的相關字段,若不存在,則不返回。

select * from a left semi join b on a.id=b.id;
7. 數據分組查詢

當查詢語句中有 group by 時 select 的字段後面只能跟兩種形式的數據:聚合函數 和 group by 的字段。

select name,sum(price) from car group by name;
8. 數據排序

order by 排序字段 asc|desc

全局排序,針對所有的 reduecetask 進行全局排序

select * from car order by name desc limit 20;
sort by 局部排序

針對每一個 reducetask 的結果進行排序的,不保證全局排序, 只有一個 reducetask 的時候 sort by = order by

select * from car sort by name desc;
distribute by 分桶查詢的時候的分桶

select * from car distribute by name;
cluster by
distribute by 和 sort by 的字段相同的時候 = cluster by

select * from car cluster by name;
Hive 實戰之旅

經過上面的學習我們具備了使用 hive 的基本知識。下面我們通過一個經典的案例,將完成一次 hive 實戰之旅。

首先啓動 hive cli

hive --service cli
創建一個用戶給電影打分的信息表

CREATE TABLE u_data (
  userid INT,
  movieid INT,
  rating INT,
  unixtime STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;

下載數據文件

curl --remote-name http://files.grouplens.org/datasets/movielens/ml-100k.zip
解壓縮下載後的文件

unzip ml-100k.zip
將解壓後的文件導入到 hive 中

‘/u.data’ 替換成你的數據文件實際路徑。

LOAD DATA LOCAL INPATH ‘/u.data’
OVERWRITE INTO TABLE u_data;
下面可以通過查詢語句分析已經導入的數據。

例如:求所有電影的總分數

select sum(rating) from u_data;
例如:找出平均分數最高的 3 部電影

 select
 		movieid
 from
 (
 select movieid,avg(rating) over(partition by movieid)   as argv_rating  from u_data 
 ) data
 order by argv_rating desc
 limit 3

總結

這一小節我們學習了 Hive 的架構、部署步驟、數據結構以及 hive 開發需要掌握的 DDL、DML 語句。

最後我們通過一個用戶對電影評分的例子,帶着大家完成了一次 Hive 實戰之旅。這次的內容比較多,也非常的重要,務必認真掌握。

24 Apache Spark RDD 實戰

人的差異在於業餘時間。
——愛因斯坦

上一個小節我們學習了 Hive 的部署、開發。這一小節我們一起來學習一下 Spark 的部署、Spark RDD 開發。

Spark 運行模式

Spark 運行模式較多,常見的有以下幾種

Local:單機,jobs 都在這臺機器上運行
Standalone:多臺機器組成一個集羣,然後 jobs 可以分在多臺機器上運行
Spark on Yarn: Spark 程序運行在 Yarn 上
Spark on Mesos: 部署 Spark 集羣在 Mesos 上
Spark on Kubernetes: 部署 Spark 集羣在 Mesos 上
除了以上的部署模式外還有將 Spark 部署到雲計算平臺上,例如:Spark on Amazon EC2

Spark 單機模式部署

在實際工業數據生產環境中 Spark on Yarn 的模式應用最爲廣泛。我在這裏以 Spark 單機模式部署爲例,讓大傢俱備一個 Spark 的學習環境,Spark on Yarn 的部署步驟也並不複雜,感興趣的同學可以上 Spark 官網學習一下。

Java 環境搭建

參照本章第一小節部署好 Java 環境

下載 Spark 2.4.5 版本安裝包

下載鏈接:https://www.apache.org/dyn/closer.lua/spark/spark-2.4.5/spark-2.4.5-bin-hadoop2.7.tgz

解壓縮 Spark 安裝包

tar -zxvf spark-2.4.5-bin-hadoop2.7.tgz
配置 Spark 環境

cp spark-2.4.5-bin-hadoop2.7/conf/spark-env.sh.template spark-env.sh
vim spark-2.4.5-bin-hadoop2.7/conf/spark-env.sh
在文件 spark-env.sh 增加如下內容:

PARK_LOCAL_IP=本機ip
本機 ip 需要替換成你機器的實際 ip 地址。

啓動 Spark

在 spark-2.4.5-bin-hadoop2.7 的 bin 目錄下執行如下命令:

sh spark-shell --master=local
或者

./spark-shell
Spark-shell 是一個交互式的 spark 運行環境,可以用來運行 Spark RDD、DataSet、DataFrame、Spark Streaming (DStreams)、Structured Streaming 程序。

Spark RDD、DataSet、DataFrame 用來處理批量數據,Spark Streaming (DStreams) 用來處理準實時數據。

Structured Streaming 將數據批處理和數據流式處理在 AIP 層面進行了統一。

Spark RDD 常見操作

RDD 支持兩種操作:轉化操作(Transformation)和行動操作(Action)。

轉化操作時返回一個新的 RDD 的操作,比如 map () 和 filter ()。

行動操作則是向驅動器程序返回結果或把結果寫入外部系統的操作,會觸發實際的計算,比如 count () 和 first ()。

轉換 (Transformations)

對一個數據爲 {1, 2, 3, 3} 的 RDD 進行基本的 RDD 轉化操作

函數名 目的 示例 結果
map() 將函數應用於 RDD 中的每個元素,將返回值構成新的 RDD rdd.map(x -> x+1) {2, 3, 4, 4}
flatMap() 將函數應用於 RDD 中的每個元素,將返回的迭代器的所有內容構成新的 RDD。通常用來切分單詞 rdd.flatMap(x -> x.to(3)) {1, 2, 3, 2, 3, 3, 3}
filter() 返回一個由通過傳給 filter () 的函數的元素組成的 RDD rdd.filter(x -> x != 1) {2, 3, 3}
distinct() 去重 rdd.distinct() {1, 2, 3}
sample(withReplacement, fraction, [seed]) 對 RDD 採樣,以及是否替換 rdd.sample(false, 0.5) 非確定的
對數據分別爲 {1, 2, 3} 和 {3, 4, 5} 的 RDD 進行鍼對兩個 RDD 的轉化操作

函數名 目的 示例 結果
union() 生成一個包含兩個 RDD 中所有元素的 RDD rdd.union(other) {1, 2, 3, 3, 4, 5}
intersection() 求兩個 RDD 共同的元素的 RDD rdd.intersection(other) {3}
subtract() 移除另一個 RDD 中的元素 rdd.subtract(other) {1, 2}
cartesian() 於另一個 RDD 的笛卡爾積 rdd.cartesian(other) {(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 3), (3, 4), (3, 5)}
Pair RDD 轉化 (Transformations)

Pair RDD 的轉化操作,以鍵值對 {(1, 2), (3, 4), (3, 6)} 爲例

函數名 目的 示例 結果
reduceByKey(func) 合併具有相同鍵的值 rdd.reduceByKey((x, y) -> x + y) {(1, 2), (3, 10)}
groupByKey() 對具有相同鍵的值進行分組 rdd.groupByKey() {(1, [2]), (3, [4, 6])}
★ combineByKey(createCombiner, mergeValue, mergeCombiners, partitioner) 使用不同返回類型合併具有相同鍵的值 見例 4-12 到例 4-14
mapValues(func) 對 pair RDD 中的每個值應用一個函數而不改變鍵 rdd.mapValues(x -> x + 1) {(1, 3), (3, 5), (3, 7)}
flatMapValues(func) 對 pair RDD 中的每個值應用一個返回迭代器的函數,然後對返回的每個元素都生成一個對應原鍵值對記錄。通常用於符號化 rdd.flatMapValues(x -> (x to 5)) {(1, 2), (1, 3), (1, 4), (1, 5), (3, 4), (3, 5)}
keys() 返回一個僅包含鍵的 RDD rdd.keys() {1, 3, 3}
values() 返回一個僅包含值的 RDD rdd.values() {2, 4, 6}
sortByKey() 返回一個根據鍵排序的 RDD rdd.sortByKey() {(1, 2), (3, 4), (3, 6)}
針對兩個 Pair RDD 的轉化操作,rdd = {(1, 2), (3, 4), (3, 6)} other = {(3, 9)}

函數名 目的 示例 結果
subtractByKey 刪掉 RDD 中鍵與 other RDD 中的鍵相同的元素 rdd.substractByKey(other) {(1, 2)}
join 對兩個 RDD 進行內連接 rdd.join(other) {(3, (4, 9)), (3, (6, 9))}
★ rightOuterJoin 對兩個 RDD 進行連接操作,確保第一個 RDD 的鍵必須存在(右外連接) rdd.rightOuterJoin(other) {(3, (Some(4), 9)), (3, (Some(6), 9))}
★ leftOuterJoin 對兩個 RDD 進行連接操作,確保第二個 RDD 的鍵必須存在(左外連接) rdd.leftOuterJoin(other) {(1, (2, None)), (3, (4, Some(9))), (3, (6, Some(9)))}
cogroup 將兩個 RDD 中擁有相同鍵的數據分組到一起 rdd.cogroup(other) {(1, ([2], [])), (3, ([4, 6], [9]))}
行動 (Actions)

對一個數據爲 {1, 2, 3, 3} 的 RDD 進行基本的 RDD 行動操作

函數名 目的 示例 結果
collect() 返回 RDD 中的所有元素 rdd.collect() {1, 2, 3, 3}
count() RDD 中的元素個數 rdd.count() 4
countByValue() 各元素再 RDD 中出現的次數 rdd.countByValue() {(1, 1), (2, 1), (3, 2)}
take(num) 從 RDD 中返回 num 個元素 rdd.take(2) {1, 2}
top(num) 從 RDD 中返回最前面的 num 個元素 rdd.top(2) {3, 3}
takeOrdered(num)(ordering) 從 RDD 中按照提供的順序返回最前面的 num 個元素 rdd.takeOrdered(2)(myOrdering) {3, 3}
takeSample(withReplacement, num, [seed]) 從 RDD 中返回任意一些元素 rdd.takeSample(false, 1) 非確定的
reduce(func) 並行整合 RDD 中的數據(例如 sum) rdd.reduce((x, y) -> x + y) 9
fold(zeor)(func) 和 reduce () 一樣,但是需要提供初始值 rdd.fold(0)((x, y) -> x + y) 9
★ aggregate(zeroValue)(seqOp, combOp) 和 reduce () 相似,但是通常返回不同類型的函數 rdd.aggergate((0, 0))((x, y) -> (x._1 + y, x._2 + 1), (x, y) -> (x._1 + y._1, x._2 + y._2)) (9, 4)
foreach(func) 對 RDD 中的每個元素使用給定的函數 rdd.foreach(func) 無
Pair RDD 行動操作 (Actions)

Pair RDD 的行動操作,以鍵值對集合 {(1, 2), (3, 4), (3, 6)} 爲例

函數名 目的 示例 結果
countByKey() 對每個鍵對應的元素分別計數 rdd.countByKey() {(1, 1), (3, 2)}
collectAsMap() 將結果以映射表的形式返回,以便查詢 rdd.collectAsMap() Map{(1, 2), (3, 6)}
lookup(key) 返回給定鍵對應的所有值 rdd.lookup(3) [4, 6]
Spark RDD 實戰之旅

WorkCount 例子

我們使用一些轉換來構建(字符串,整數)對的數據集,counts 然後將其保存到文件中。

avaRDD textFile = sc.textFile(“hdfs://…”);
JavaPairRDD<String, Integer> counts = textFile
.flatMap(s -> Arrays.asList(s.split(" ")).iterator())
.mapToPair(word -> new Tuple2<>(word, 1))
.reduceByKey((a, b) -> a + b);
counts.saveAsTextFile(“hdfs://…”);
Pi 估計

Spark 還可以用於計算密集型任務。此代碼通過 “擲飛鏢” 來估計 π。我們在單位正方形((0,0)至(1,1))中選擇隨機點,並查看有多少個落入單位圓。該分數應爲 π/ 4,因此我們使用它來獲取估計值。

List l = new ArrayList<>(NUM_SAMPLES);
for (int i = 0; i < NUM_SAMPLES; i++) {
l.add(i);
}

long count = sc.parallelize(l).filter(i -> {
double x = Math.random();
double y = Math.random();
return xx + yy < 1;
}).count();
System.out.println("Pi is roughly " + 4.0 * count / NUM_SAMPLES);
Java 狀態追蹤

我們在內存中初始化一個數組,並將數組裏面的數據 collect 出來,在任務執行過程中打印任務信息。

SparkSession spark = SparkSession
.builder()
.appName(APP_NAME)
.getOrCreate();
JavaSparkContext jsc = new JavaSparkContext(spark.sparkContext());

// Example of implementing a progress reporter for a simple job.
 JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3, 4, 5), 5).map(
        new IdentityWithDelay<>());
    JavaFutureAction<List<Integer>> jobFuture = rdd.collectAsync();
    while (!jobFuture.isDone()) {
      Thread.sleep(1000);  // 1 second
      List<Integer> jobIds = jobFuture.jobIds();
      if (jobIds.isEmpty()) {
        continue;
      }
      int currentJobId = jobIds.get(jobIds.size() - 1);
      SparkJobInfo jobInfo = jsc.statusTracker().getJobInfo(currentJobId);
      SparkStageInfo stageInfo = jsc.statusTracker().getStageInfo(jobInfo.stageIds()[0]);
      System.out.println(stageInfo.numTasks() + " tasks total: " + stageInfo.numActiveTasks() +
          " active, " + stageInfo.numCompletedTasks() + " complete");
    }

System.out.println("Job results are: " + jobFuture.get());

總結
這一小節學習了 Spark 的運行模式、部署步驟、RDD 的常見操作方法,然後我們通過三個 Spark RDD 實際的例子讓大家感受了 Spark 在數據批處理中的應用。Spark DataFrame、Dataset API 是基於 RDD 的高級 API。

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