1. 程式人生 > >spark on hive原理與環境搭建 spark研習第三季

spark on hive原理與環境搭建 spark研習第三季

SparkSQL前身是Shark,Shark強烈依賴於Hive。Spark原來沒有做SQL多維度資料查詢工具,後來開發了Shark,Shark依賴於Hive的解釋引擎,部分在Spark中執行,還有一部分在Hadoop中執行。所以講SparkSQL必須講Hive。

一、spark on hive原理與搭建

1. hive的本質

1)Hive是分散式資料倉庫,同時又是查詢引擎,所以SparkSQL取代的只是Hives的查詢引擎,在企業實際生產環境下,Hive+SparkSQL是目前最為經典的資料分析組合。

2)Hive本身就是一個簡單單機版本的軟體,主要負責:

A) 把HQL翻譯成Mapper(s)-Reducer-Mapper(s)的程式碼,並且可能產生很多MapReduce的JOB。
B)把生成的MapReduce程式碼及相關資源打包成jar併發布到Hadoop叢集中執行(這一切都是自動的)

3)Hive本身的架構如下所示: 
hive架構

可以通過CLI(命令終端)、JDBC/ODBC、Web GUI訪問Hive。 
JavaEE或.net程式可以通過Hive處理,再把處理的結果展示給使用者。 
也可以直接通過Web頁面操作Hive。 
※ Hive本身只是一個單機版本的的軟體,怎麼訪問HDFS的呢? 
=> 在Hive用Table的方式插入資料、檢索資料等,這就需要知道資料放在HDFS的什麼地方以及什麼地方屬於什麼資料,Metastore就是儲存這些元資料資訊的。Hive通過訪問元資料資訊再去訪問HDFS上的資料。

可以看出HDFS不是一個真實的檔案系統,是虛擬的,是邏輯上的,HDFS只是一套軟體而已,它是管理不同機器上的資料的,所以需要NameNode去管理元資料。DataNode去管理資料。 
Hive通過Metastore和NameNode打交道。

2. Hive安裝和配置實戰

Spark1.6.1中SparkSQL可以指定具體的Hive的版本。 
1) 從apache官網下載hive-1.2.1,並解壓到/home/richard目錄。 
http://mirrors.cnnic.cn/apache/hive/hive-1.2.1/ 
2) 配置.bashrc,追加以下內容,或者/etc/profile:

  1. export HIVE_HOME=/home/richard/hive-1.2.1
  2. export HIVE_CONF_DIR=/$HIVE_HOME/conf
  3. export PATH=$PATH:$HIVE_HOME/bin

3)進入/home/richard/hive-1.2.1/conf目錄,生成hive-env.sh:

  1. cp hive-default.xml.template hive-site.xml

配置:

  1. export HADOOP_HOME=/opt/hadoop-2.6.0
  2. export HIVE_HOME=/opt/hive-1.2.1/
  3. export HIVE_CONF_DIR=/opt/hive-1.2.1/conf

Hive預設情況下放元資料的資料庫是Derby,遺憾的是Derby是單使用者,所以在生產環境下一般會採用支援多使用者的資料庫來進行MetaStore,且進行Master-Slaves主從讀寫分離和備份(一般Master節點負責寫資料,Slaves節點負責讀資料)。最常用的是MySQL。

cp hive-env.sh.template hive-env.sh 
再生成hive-site.xml,並配置如下:

  1. <configuration>
  2. <!-- WARNING!!! This file is auto generated for documentation purposes ONLY! -->
  3. <!-- WARNING!!! Any changes you make to this file will be ignored by Hive. -->
  4. <!-- WARNING!!! You must make your changes in hive-site.xml instead. -->
  5. <!-- Hive Execution Parameters -->
  6. <property>
  7. <name>javax.jdo.option.ConnectionURL</name>
  8. <value>jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true</value>
  9. <description>JDBC connect string for a JDBC metastore</description>
  10. </property>
  11. <property>
  12. <name>javax.jdo.option.ConnectionDriverName</name>
  13. <value>com.mysql.jdbc.Driver</value>
  14. <description>Driver class name for a JDBC metastore</description>
  15. </property>
  16. <property>
  17. <name>javax.jdo.option.ConnectionUserName</name>
  18. <value>root</value>
  19. <description>username to use against metastore database</description>
  20. </property>
  21. <property>
  22. <name>javax.jdo.option.ConnectionPassword</name>
  23. <value>778899..</value>
  24. <description>password to use against metastore database</description>
  25. </property>
  26. <property>
  27. <name>hive.metastore.warehouse.dir</name>
  28. <value>/user/hive/warehouse</value>
  29. <description>location of default database for the warehouse</description>
  30. </property>
  31. </configuration>

Hive中的DataBase和表其實就是HDFS上的目錄和簡單的文字檔案。簡單的文字檔案中有幾列資料,每列資料的型別無法直接從文字檔案中得知。但當資料放入Hive中,Hive就把元資料放入Mysql中了,這樣就可以基於資料的表進行查詢了。

hive開啟錯誤參考:

  1. 主要是按照《DT-大資料 hive1.2.1mysql作為元資料庫搭建》文件

另外還需要下載驅動包(mysql-connector-java-5.1.35.tar.gz)將.jar檔案放到這個目錄下:

  1. cd /usr/local/hive/apache-hive-1.2.1/lib/

啟動hive報錯

  1. Logging initialized using configuration in jar:file:/opt/hive-1.2.1/lib/hive-common-1.2.1.jar!/hive-log4j.properties
  2. Exceptionin thread "main" java.lang.RuntimeException: java.lang.RuntimeException:Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
  3. Causedby: java.lang.RuntimeException:Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
  4. Causedby: java.lang.reflect.InvocationTargetException
  5. Causedby: javax.jdo.JDOFatalDataStoreException:Unable to open a test connection to the given database. JDBC url = jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true, username = hive. Terminating connection pool (set lazyInit to true if you expect to start your database after
  6. ...
  1. [email protected]:/opt# netstat -tnlp | grep 3306
  2. tcp 00127.0.0.1:33060.0.0.0:* LISTEN 5090/mysqld
  3. //mysql的監聽IP應該是0.0.0.0
  4. //在vi /etc/mysql/my.cnf 中修改
  5. killall mysqld 後守護程序還會啟動mysql,等於重啟

另外報錯:

  1. SLF4J:See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
  2. SLF4J:Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
  3. [ERROR]Terminal initialization failed; falling back to unsupported

原因是hadoop目錄下存在老版本jline: 
/hadoop-2.5.2/share/hadoop/yarn/lib: 
-rw-r--r-- 1 root root 87325 Mar 10 18:10 jline-0.9.94.jar

解決方法是:

  1. hive下的新版本jlineJAR包拷貝到hadoop下:
  2. cp /hive/apache-hive-1.1.0-bin/lib/jline-2.12.jar ./

5) Hive的表有兩種基本型別:一種是內部表(這種表資料屬於Hive本身,即如果原來的資料在HDFS的其他地方,此時資料會通過HDFS移動到Hive所在目錄,如果刪除Hive中的該表的話資料和元資料均會被刪除),一種是外部表(這種表資料不屬於Hive資料倉庫,元資料中會表達具體資料在哪裡,使用時和內部表的使用一樣,只是如果通過Hive去刪除的話,刪除的只是元資料,並沒有刪除資料本身)

6)Hive擴充套件(Hive的資料儲存-轉載)

Hive是基於Hadoop分散式檔案系統的,它的資料儲存在Hadoop分散式檔案系統中。Hive本身是沒有專門的資料儲存格式,也沒有為資料建立索引,只需要在建立表的時候告訴Hive資料中的列分隔符和行分隔符,Hive就可以解析資料。所以往Hive表裡面匯入資料只是簡單的將資料移動到表所在的目錄中(如果資料是在HDFS上;但如果資料是在本地檔案系統中,那麼是將資料複製到表所在的目錄中)。

Hive中主要包含以下幾種資料模型:Table(表),External Table(外部表),Partition(分割槽),Bucket(桶)(本部落格會專門寫幾篇博文來介紹分割槽和桶)。

1、表:Hive中的表和關係型資料庫中的表在概念上很類似,每個表在HDFS中都有相應的目錄用來儲存表的資料,這個目錄可以通過${HIVE_HOME}/conf/hive-site.xml配置檔案中的 hive.metastore.warehouse.dir屬性來配置,這個屬性預設的值是/user/hive/warehouse(這個目錄在 HDFS上),我們可以根據實際的情況來修改這個配置。如果我有一個表wyp,那麼在HDFS中會建立/user/hive/warehouse/wyp 目錄(這裡假定hive.metastore.warehouse.dir配置為/user/hive/warehouse);wyp表所有的資料都存放在這個目錄中。這個例外是外部表。

2、外部表:外部表指向已經在HDFS中存在的資料,可以建立Partition。它和內部表在元資料的組織上是相同的,而實際資料的儲存則有較大的差異。內部表的建立過程和資料載入過程這兩個過程可以分別獨立完成,也可以在同一個語句中完成,在載入資料的過程中,實際資料會被移動到資料倉庫目錄中;之後對資料對訪問將會直接在資料倉庫目錄中完成。刪除表時,表中的資料和元資料將會被同時刪除。而外部表只有一個過程,載入資料和建立表同時完成(CREATE EXTERNAL TABLE ……LOCATION),實際資料是儲存在LOCATION後面指定的 HDFS 路徑中,並不會移動到資料倉庫目錄中。當刪除一個External Table時,僅刪除該連結。

3、分割槽:在Hive中,表的每一個分割槽對應表下的相應目錄,所有分割槽的資料都是儲存在對應的目錄中。比如wyp 表有dt和city兩個分割槽,則對應dt=20131218,city=BJ對應表的目錄為/user/hive/warehouse /dt=20131218/city=BJ,所有屬於這個分割槽的資料都存放在這個目錄中。

4、桶:對指定的列計算其hash,根據hash值切分資料,目的是為了並行,每一個桶對應一個檔案(注意和分割槽的區別)。比如將wyp表id列分散至16個桶中,首先對id列的值計算hash,對應hash值為0和16的資料儲存的HDFS目錄為:/user /hive/warehouse/wyp/part-00000;而hash值為2的資料儲存的HDFS 目錄為:/user/hive/warehouse/wyp/part-00002。如果想應用很多的Map任務這樣是不錯的選擇。 
Hive資料抽象結構圖

3. 使用Hive分析搜尋資料

啟動HDFS/Yarn。注意如果要使用Hive進行查詢就需要啟動Yarn。 
啟動Hive。 
通過show databases;可以檢視資料庫。預設database只有default。 
選取搜狗實驗的三個資料來源:http://download.labs.sogou.com/dl/q.html

  1. hadoop dfs -mkdir /library/sogou
  2. hadoop dfs -put ./SogouQ1.txt /library/sogou
  3. hadoop dfs -put ./SogouQ2.txt /library/sogou
  4. hadoop dfs -put ./SogouQ3.txt /library/sogou
  1. create table SogouQ3(ID STRING, WEBSESSION STRING, WORD STRING, S_SEQ INT, C_SEQ INT, WEBSITE STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n';//建表
  2. LOAD DATA INPATH '/library/sogou/SogouQ3.txt' OVERWRITE INTO TABLE SogouQ3;//載入資料

查詢搜尋排名第一,點選排名為第一的結果: 
select count(*) from sogouq1 where S_SEQ=1 and C_SEQ=1;

搜尋日誌中,關注排名前五的內容,並且給出分別為多少次: 
select WORD, count(WORD) as COUNTWord from SogouQ1 group by WORD order by COUNTWord desc limit 5

查詢例子mysql

mysql -u root -p

  1. creeate database hive;
  2. use hive;
  3. create table person(name String,age int);
  4. insert into person values(‘richard’,’34’);
  5. select*from person;即可查詢。

到此不需要啟動spark,只需要啟動HDFS。

4. Spark SQL on Hive配置及實戰

1)spark on hive 配置

  1. 切換到spar的conf目錄下使用vi hive-site.xml建立hive-site.xml.並填寫如下內容
  1. <configuration>
  2. <property>
  3. <name>hive.metastore.uris</name>
  4. <value>thrift://master:9083</value>
  5. <description>thrift URI for the remote metastore.Used by metastore client to connect to remote metastore. </description>
  6. </property>
  7. </configuration>

因為用sparksql操作hive實際上是把hive 當做資料倉庫。資料倉庫肯定有元資料和資料本身。要訪問真正的資料就要訪問他的元資料。所以只需要配置hive.metastore.uris即可。(不需在每臺機器上配置)

2)啟動叢集

  1. 啟動dfs 服務start-dfs.sh
  2. 啟動hive 資料倉庫服務 hive --service metastore >metastore.log 2>& 1&
  3. 啟動spark服務start-all.sh
  4. 啟動sparkshell ./spark-shell –master spark://master:7077

3)案例實戰

  1. Spark on hive 實戰在spark-shell 模式下
  1. val hiveContext=new org.apache.spark.sql.hive.HiveContext(sc)
  2. hiveContext.sql("use hive")//使用hive 資料庫
  3. hiveContext.sql("show tables").collect.foreach(println)// 查詢資料庫中的表
  4. hiveContext.sql("select count(*) from sogouq1").collect.foreach(println)//(注意此時使用的是spark的引擎)
  5. hiveContext.sql(“select count(*)from sogouq2 where website like '%baidu%'”).collect.foreach(println)
  6. hiveContext.sql(“select count