hivemaven編譯
Ⅰ 一招教你使用Hive處理文本數據
我在學習了幾個月的大數據之後,終於接到了老闆派來的活啦!有核心技術在手,感覺走路都輕快了許多呢。這個需求呢實際上非常簡單且明確。
現在老闆需要我對招聘市場不同崗位的核心技能點做一個調研,現在我們手上大概有一些數據,數據是一些招聘相關的數據,在數據中有一個欄位為崗位描述,顧名思義,找過工作的同學都能知道崗位描述是啥意思,尤其是像你們沒學大數據的同學,可能已經翻看了無數工作機會還沒有找到工作吧吼吼,我學習完大數據之後可是立馬找到工作了呢。
崗位描述實際就是一段話,表示這個崗位需要應聘者具備某些能力或者技能來足以勝任這份工作。有了這個數據,我初步的調研方案是這樣的:
針對性的分析這個欄位的數據,把其中所有的關鍵詞給取出來,然後按照每一條數據對應的崗位,根據崗位進行分組計數,那樣的話我就可以得出每一個崗位對應的每一個關鍵詞出現的次數了,然後當然出現次數最多的那幾個關鍵詞就是該崗位的核心技能關鍵詞啦。計劃非常完美。
現在的我滿腦子都是將任務完美完成,然後得到老闆賞識,升職加薪,迎娶白富美的橋段。可是萬事俱備,只欠東風。有一個非常重要的問題就是如何將一堆文本(崗位描述)轉換成一個個的詞?也就是我們常說的分詞,今天我們就來介紹一下如何完美地完成這個任務。干貨時間到。
首先這次任務咱們使用Hive來進行數據處理和分析,通過查詢Hive文檔發現Hive內置函數無法實現分詞,但是Hive提供UDF支持用戶自定義函數來實現更多的功能。開發UDF的過程大致分為(使用java語言):
創建一個用於編寫UDF的Maven項目導入相關大數據依賴,其中最重要的是hive-exec和hadoop-common創建一個類並且繼承自UDF類重寫類中的evaluate()方法,並且在方法中定義邏輯對Maven項目進行打包,將jar包上傳至HDFS中在Hive中添加方法關聯該jar包中的UDF類,之後就可以使用該方法實現想要的功能了需要注意的是,繼承自UDF類,evaluate()方法的輸入是一條數據,輸出也是一條數據,可以想像一下就是在Hive中一條數據進來,經過轉換後返回一條轉換後的數據,這與我們常用的lower()/upper()函數類似。在Hive中,還有其他形式的自定義函數類,比如UDAF、UDTF,其中UDAF是多行輸入返回一行,例如聚合函數sum()/count(),UDTF是一行輸入返回多行,例如爆炸函數explode()。具體詳情同學們自行搜索學習吧。
下面開始編寫分詞的UDF,首先當然是導入相關依賴了,實現分詞的庫有很多,我選擇的是java常用的IK分詞器,依賴的名稱是ikanalyzer。
之後我們可以定義相關的黑名單詞和偏好詞,因為我們要最終得到我們想要的關鍵詞,那麼們最好把一些沒什麼用的詞去掉,例如「我的」,「崗位」,「很好」等等這一系列詞存放成黑名單,因為最後我們不想把得出來的關鍵詞是這種沒有意義的詞。當然偏好詞也有必要,因為分詞工具都是通過一定的語料和演算法來進行分詞的,它有時候也會將一些詞分錯,例如「機器學習」這個詞,可能分詞工具會將它分為「機器」「學習」這兩個詞,但是很明顯對於崗位來說,這明顯就是一個技能詞,所以我們將這種專有名詞設置成偏好詞讓分詞器下次遇到這些詞的時候不要分錯。
將停止詞放入stopword.dic中,將偏好詞放入extword.dic中,每一個詞佔一行即可,然後在IKAnalyzer.cfg.xml中配置這兩個文件的路徑,之後IK分詞器就會自動的載入我們自定義的停止詞和偏好詞了。
接下來編寫主類UDF。
UDF的大致意思就是對傳入的字元串做分詞,分詞後在通過特殊符號「\001」來對每一個詞進行拼接,最終返回一個拼接好的字元串。
根據開發UDF的步驟,將UDF打成jar包並上傳到HDFS,並在Hive中創建方法關聯該jar包。
總之使用Hivesql一通十三招將所有的任務完成,SQL在這就不給大夥兒解釋了,最終我們由原始數據,得到了最終我們想要的數據。
從我們對數據的處理和分析結果來看,演算法崗位(job_tag)對關鍵字(sub)「演算法」、「c++」、「機器學習」這些技術都有相當大的需求,因為在演算法崗位描述中,「演算法」這個詞出現6366次,「c++」出現3706次,「機器學習」出現3385次,都是出現次數最高的幾個關鍵詞。
今天我的分享就到這啦,你學會了嗎?
Ⅱ IDEA下寫hive的udf(踩坑教程)
配置maven的過程網上有很多這里就不寫了。
UDF
用戶自定義函數(user defined function)–針對單條記錄。
創建函數流程
1、自定義一個Java類
2、繼承UDF類
3、重寫evaluate方法 (必須重寫這個方法)
4、打成jar包
6、在hive執行add jar方法
7、在hive執行創建模板函數
8、hql中使用
打包後的文件在你的項目的target當中,上傳那個幾kb的original-int2inetaddressUDF-1.0-SNAPSHOT.jar那個文件,上傳到伺服器上隨便一個目錄
add jar 你的文件路徑 /original-int2inetaddressUDF-1.0-SNAPSHOT.jar;
create temporary function myudf as "UDFDemo.int2inetaddress";
select myudf(XXX) from xxxx
可以參考這里的視頻:
http://www.cnblogs.com/simuhunluo/p/7756250.html
Ⅲ 怎樣只編譯hive的一個component
windows自帶的記事本只能做編輯源代碼使用,要編譯需要有編譯器才行,找些其他的集成化軟體,編輯編譯連接調試集成一體的,如vc6.0,wintc等
Ⅳ Hive入門概述
1.1 什麼是Hive
Hive:由Facebook開源用於解決海量結構化日誌的數據統計。
Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張表,並提供類SQL查詢功能。本質是:將HQL轉化成MapRece程序
Hive處理的數據存儲在HDFS
Hive分析數據底層的實現是MapRece
執行程序運行在Yarn上
1.2 Hive的優缺點
1.2.1 優點
操作介面採用類SQL語法,提供快速開發的能力(簡單、容易上手)。
避免了去寫MapRece,減少開發人員的學習成本。
Hive的執行延遲比較高,因此Hive常用於數據分析,對實時性要求不高的場合。
Hive優勢在於處理大數據,對於處理小數據沒有優勢,因為Hive的執行延遲比較高。
Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。
1.2.2 缺點
1.Hive的HQL表達能力有限
(1)迭代式演算法無法表達
(2)數據挖掘方面不擅長
2.Hive的效率比較低
(1)Hive自動生成的MapRece作業,通常情況下不夠智能化
(2)Hive調優比較困難,粒度較粗
1.3 Hive架構原理
1.用戶介面:Client
CLI(hive shell)、JDBC/ODBC(java訪問hive)、WEBUI(瀏覽器訪問hive)
2.元數據:Metastore
元數據包括:表名、表所屬的資料庫(默認是default)、表的擁有者、列/分區欄位、表的類型(是否是外部表)、表的數據所在目錄等;
默認存儲在自帶的derby資料庫中,推薦使用MySQL替代derby存儲Metastore
3.Hadoop
使用HDFS進行存儲,使用MapRece進行計算。
4.驅動器:Driver
(1)解析器(SQL Parser):將SQL字元串轉換成抽象語法樹AST,這一步一般都用第三方工具庫完成,比如antlr;對AST進行語法分析,比如表是否存在、欄位是否存在、SQL語義是否有誤。
(2)編譯器(Physical Plan):將AST編譯生成邏輯執行計劃。
(3)優化器(Query Optimizer):對邏輯執行計劃進行優化。
(4)執行器(Execution):把邏輯執行計劃轉換成可以運行的物理計劃。對於Hive來說,就是MR/Spark。
Hive通過給用戶提供的一系列交互介面,接收到用戶的指令(SQL),使用自己的Driver,結合元數據(MetaStore),將這些指令翻譯成MapRece,提交到Hadoop中執行,最後,將執行返回的結果輸出到用戶交互介面。
1.4 Hive和資料庫比較
由於 Hive 採用了類似SQL 的查詢語言 HQL(Hive Query Language),因此很容易將 Hive 理解為資料庫。其實從結構上來看,Hive 和資料庫除了擁有類似的查詢語言,再無類似之處。本文將從多個方面來闡述 Hive 和資料庫的差異。資料庫可以用在 Online 的應用中,但是Hive 是為數據倉庫而設計的,清楚這一點,有助於從應用角度理解 Hive 的特性。
1.4.1 查詢語言
由於SQL被廣泛的應用在數據倉庫中,因此,專門針對Hive的特性設計了類SQL的查詢語言HQL。熟悉SQL開發的開發者可以很方便的使用Hive進行開發。
1.4.2 數據存儲位置
Hive 是建立在 Hadoop 之上的,所有 Hive 的數據都是存儲在 HDFS 中的。而資料庫則可以將數據保存在塊設備或者本地文件系統中。
1.4.3 數據更新
由於Hive是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive中不建議對數據的改寫,所有的數據都是在載入的時候確定好的。而資料庫中的數據通常是需要經常進行修改的,因此可以使用 INSERT INTO … VALUES 添加數據,使用 UPDATE … SET修改數據。
1.4.4 索引
Hive在載入數據的過程中不會對數據進行任何處理,甚至不會對數據進行掃描,因此也沒有對數據中的某些Key建立索引。Hive要訪問數據中滿足條件的特定值時,需要暴力掃描整個數據,因此訪問延遲較高。由於 MapRece 的引入, Hive 可以並行訪問數據,因此即使沒有索引,對於大數據量的訪問,Hive 仍然可以體現出優勢。資料庫中,通常會針對一個或者幾個列建立索引,因此對於少量的特定條件的數據的訪問,資料庫可以有很高的效率,較低的延遲。由於數據的訪問延遲較高,決定了 Hive 不適合在線數據查詢。
1.4.5 執行
Hive中大多數查詢的執行是通過 Hadoop 提供的 MapRece 來實現的。而資料庫通常有自己的執行引擎。
1.4.6 執行延遲
Hive 在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致 Hive 執行延遲高的因素是 MapRece框架。由於MapRece 本身具有較高的延遲,因此在利用MapRece 執行Hive查詢時,也會有較高的延遲。相對的,資料庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過資料庫的處理能力的時候,Hive的並行計算顯然能體現出優勢。
1.4.7 可擴展性
由於Hive是建立在Hadoop之上的,因此Hive的可擴展性是和Hadoop的可擴展性是一致的(世界上最大的Hadoop 集群在 Yahoo!,2009年的規模在4000 台節點左右)。而資料庫由於 ACID 語義的嚴格限制,擴展行非常有限。目前最先進的並行資料庫 Oracle 在理論上的擴展能力也只有100台左右。
1.4.8 數據規模
由於Hive建立在集群上並可以利用MapRece進行並行計算,因此可以支持很大規模的數據;對應的,資料庫可以支持的數據規模較小。
Ⅳ 我想學習hive,請問安裝hive之前,必須安裝centos、hadoop、java這些嗎
安裝需要
java 1.6,java 1.7或更高版本。
Hadoop 2.x或更高, 1.x. Hive 0.13 版本也支持 0.20.x, 0.23.x
linux,mac,windows操作系統。以下內容適用於linux系統。
安裝打包好的hive
需要先到apache下載已打包好的hive鏡像,然後解壓開該文件
$ tar -xzvf hive-x.y.z.tar.gz
設置hive環境變數
$ cd hive-x.y.z$ export HIVE_HOME={{pwd}}
設置hive運行路徑
$ export PATH=$HIVE_HOME/bin:$PATH
編譯Hive源碼
下載hive源碼
此處使用maven編譯,需要下載安裝maven。
以Hive 0.13版為例
編譯hive 0.13源碼基於hadoop 0.23或更高版本
$cdhive$mvncleaninstall-Phadoop-2,dist$cdpackaging/target/apache-hive-{version}-SNAPSHOT-bin/apache-hive-{version}-SNAPSHOT-bin$lsLICENSENOTICEREADME.txtRELEASE_NOTES.txtbin/(alltheshellscripts)lib/(requiredjarfiles)conf/(configurationfiles)examples/(sampleinputandqueryfiles)hcatalog/(hcataloginstallation)scripts/(upgradescriptsforhive-metastore)
編譯hive 基於hadoop 0.20
$cdhive$antcleanpackage$cdbuild/dist#lsLICENSENOTICEREADME.txtRELEASE_NOTES.txtbin/(alltheshellscripts)lib/(requiredjarfiles)conf/(configurationfiles)examples/(sampleinputandqueryfiles)hcatalog/(hcataloginstallation)scripts/(upgradescriptsforhive-metastore)
運行hive
Hive運行依賴於hadoop,在運行hadoop之前必需先配置好hadoopHome。
export HADOOP_HOME=<hadoop-install-dir>
在hdfs上為hive創建\tmp目錄和/user/hive/warehouse(akahive.metastore.warehouse.dir) 目錄,然後你才可以運行hive。
在運行hive之前設置HiveHome。
$ export HIVE_HOME=<hive-install-dir>
在命令行窗口啟動hive
$ $HIVE_HOME/bin/hive
若執行成功,將看到類似內容如圖所示
Ⅵ spark sql怎麼處理hive的null
前面已經有篇文章介紹如何編譯包含hive的spark-assembly.jar了,不清楚的可以翻看一下前面的文章。
cloudera manager裝好的spark,直接執行spark-shell進入命令行後,寫入如下語句:
val hiveContext = new org.apache.spark.sql.hive.HiveContext(sc)
你會發現沒法執行通過,因為cm裝的原生的spark是不支持spark hql的,我們需要手動進行一些調整:
第一步,將編譯好的包含hive的JAR包上傳到hdfs上配置的默認的spark的sharelib目錄:/user/spark/share/lib
第二步:在你要運行spark-shell腳本的節點上的/opt/cloudera/parcels/CDH-
5.3.0-1.cdh5.3.0.p0.30/lib/spark/lib/目錄下面,下載這個jar到這個目錄:hadoop fs -get
hdfs://n1:8020/user/spark/share/lib/spark-assembly-with-hive-maven.jar(具
體路徑替換成你自己的)。然後這個目錄下面原來會有個軟鏈接spark-assembly.jar指向的是spark-assembly-1.2.0-
cdh5.3.0-hadoop2.5.0-cdh5.3.0.jar,我們把這個軟鏈接刪除掉重新創建一個同名的軟鏈接:ln -s
spark-assembly-with-hive-maven.jar
spark-assembly.jar,指向我們剛下載下來的那個JAR包,這個JAR包會在啟動spark-shell腳本時裝載到driver
program的classpath中去的,sparkContext也是在driver中創建出來的,所以需要將我們編譯的JAR包替換掉原來的
spark-assembly.jar包,這樣在啟動spark-shell的時候,包含hive的spark-assembly就被裝載到
classpath中去了。
Ⅶ 程序中的Hive具體是干什麼用的呢
Hive是基於Hadoop平台的數倉工具,具有海量數據存儲、水平可擴展、離線批量處理的優點,解決了傳統關系型數倉不能支持海量數據存儲、水平可擴展性差等問題,但是由於Hive數據存儲和數據處理是依賴於HDFS和MapRece,因此在Hive進行數據離線批量處理時,需將查詢語言先轉換成MR任務,由MR批量處理返回結果,所以Hive沒法滿足數據實時查詢分析的需求。
Hive是由FaceBook研發並開源,當時FaceBook使用Oracle作為數倉,由於數據量越來越大,Oracle數倉性能越來越差,沒法實現海量數據的離線批量分析,因此基於Hadoop研發Hive,並開源給Apacha。
由於Hive不能實現數據實時查詢交互,Hbase可提供實時在線查詢能力,因此Hive和Hbase形成了良性互補。Hbase因為其海量數據存儲、水平擴展、批量數據處理等優點,也得到了廣泛應用。
Pig與HIVE工具類似,都可以用類sql語言對數據進行處理。但是他們應用場景有區別,Pig用於數據倉庫數據的ETL,HIVE用於數倉數據分析。
從架構圖當中,可看出Hive並沒有完成數據的存儲和處理,它是由HDFS完成數據存儲,MR完成數據處理,其只是提供了用戶查詢語言的能力。Hive支持類sql語言,這種SQL稱為Hivesql。用戶可用Hivesql語言查詢,其驅動可將Hivesql語言轉換成MR任務,完成數據處理。
【Hive的訪問介面】
CLI:是hive提供的命令行工具
HWI:是Hive的web訪問介面
JDBC/ODBC:是兩種的標準的應用程序編程訪問介面
Thrift Server:提供異構語言,進行遠程RPC調用Hive的能力。
因此Hiv具備豐富的訪問介面能力,幾乎能滿足各種開發應用場景需求。
【Driver】
是HIVE比較核心的驅動模塊,包含編譯器、優化器、執行器,職責為把用戶輸入的Hivesql轉換成MR數據處理任務
【Metastore】
是HIVE的元數據存儲模塊,數據的訪問和查找,必須要先訪問元數據。Hive中的元數據一般使用單獨的關系型資料庫存儲,常用的是Mysql,為了確保高可用,Mysql元資料庫還需主備部署。
架構圖上面Karmasphere、Hue、Qubole也是訪問HIVE的工具,其中Qubole可遠程訪問HIVE,相當於HIVE作為一種公有雲服務,用戶可通過互聯網訪問Hive服務。
Hive在使用過程中出現了一些不穩定問題,由此發展出了Hive HA機制,
Ⅷ java選的jdk11為什麼變成了17
Java11升級Java17備忘錄
下塘燒餅
白頭不厭窮編碼,隻影孤燈兩卷書。
來自專欄一隻老程序猿
一、概述
Java17是目前Java最新的LTS版本,SpringBoot從2.5.5開始正式支持Java17,並且計劃從3.0版本開始,Java版本要求最低是Java17。
為了順應Java及其生態的發展,最近對一套JavaWeb開發框架做了版本升級,主要是Java版本和Springboot版本的升級,包括:
Java版本從openJDK11升級到openJDK17
springboot版本從2.1.11升級到2.7.4
本次升級相比從Java8升級到Java11要簡單很多,基本沒遇到什麼問題。
Java8到Java11之間有Java9這個變化很大的攔路虎,包括但不限於:移除了一些以前集成在jdk的lib中的依賴包,引入模塊化導致某些內部API不可用,類載入機制變化導致一些第三方依賴包版本不兼容,等等。
而從Java11到Java17,中間並沒有Java9那樣巨大的變化,只有Java16和Java17中有一些增強Java內部封裝的新特性,可能會導致底層類庫依賴包的老版本不能兼容Java17。
關於Java8升級Java11的工作,可以參考我以前的文章:
java - Java8升級Java11備忘錄_個人文章 - SegmentFault 思否
另外,本篇文章主要講如何從Java11升級到Java17,以及升級過程中遇到的一些問題。如果想看Java11到Java17有哪些新特性,可以參考我以前的另一片文章:
下塘燒餅:java17相對java11的新特性
二、升級工作內容
升級工作內容大致如下:
2.1 安裝openJDK17及其對應的IDEA
這里選擇的是eclipse的Adoptium社區版本:
OpenJDK17U-jdk_x64_linux_hotspot_17.0.3_7.tar.gz
下載地址:
https://adoptium.net/zh-CN/temurin/archive
更多版本與下載地址請參考文章:
下塘燒餅:java17相對java11的新特性
安裝很簡單,解壓縮到指定目錄即可。
只是開發的話,JAVA_HOME與PATH等環境變數不是一定要設置的,比如我這里的環境有多個JDK版本,只要在IDE中添加新的JDK即可。
IDEA的話,使用2021.2.4以上版本即可支持Java17,在其sdk中加入剛剛安裝好的JDK目錄:
用IDEA任意打開一個java工程,在其Project Structrue -> Platform settings -> SDKs中添加JDK17目錄。
2.2 配置本地Maven
在本地Maven的配置文件中添加新的JDK17的profile,比如我這里的配置文件是/opt/apache-maven-3.5.0/conf/settings.xml,打開並在其中添加:
<profiles> ... <profile> <id>openJDK17</id> <activation> <jdk>17</jdk> </activation> <properties> <JAVA_HOME>/usr/java/jdk-17.0.3+7/</JAVA_HOME> <JAVA_VERSION>17</JAVA_VERSION> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <maven.compiler.compilerVersion>17</maven.compiler.compilerVersion> </properties> <repositories> <repository> <id>XXX-Repository</id> <name>XXX Maven Repository</name> <url>http://maven.xxx/content/groups/public/</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>XXX-Repository</id> <name>XXX Maven Repository</name> <url>http://maven.xxx/content/groups/public/</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles>
JAVA_HOME是本地JDK安裝目錄。
repository與pluginRepository用來配置maven倉庫地址,之後在IDE中啟用這里配置的profile。這樣maven拉取jar包時,會優先從這里配置的maven倉庫拉取,拉取不到時再去中央倉庫拉。
配置好settings.xml後,在各個java工程中啟用新的profile:
首先在File -> Settings -> Maven中確定maven及其配置文件目錄:
然後在IDEA的maven插件中選擇jdk17的profile:
2.3 修改父工程的pom版本控制
升級對象是一套JavaWeb開發框架,有自己的父工程來控制依賴包的版本,在決定升級Java版本與Springboot版本後,父工程的pom文件中的相關依賴包版本需要更新。
首先是父工程自己的版本需要升級,這樣仍然依賴老版本父工程的java工程就不會升級相關版本,只有依賴了新版本父工程的java工程才會升級相關版本。
<artifactId>parent-xxx</artifactId> <version>2.0.0</version>
這里假定老版本是1.x.x,新版本是2.0.0。
實際上父工程的pom是在升級過程中不斷修改的,為了不影響使用該父工程的項目開發,你需要與相關開發人員約定好在升級完成後再嘗試使用新版本的父工程。
然後修改基本屬性與spring相關依賴包的版本,篇幅原因這里只給出版本發生變化的依賴包的修改後版本號,dependency配置略過:
<properties> <!-- 基本屬性 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>17</java.version> <!-- spring相關版本 --> <spring-boot.version>2.7.4</spring-boot.version> <spring-boot-admin.version>2.7.4</spring-boot-admin.version> <spring-cloud.version>2021.0.4</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version> <mybatis-spring-boot-starter.version>2.2.2</mybatis-spring-boot-starter.version> <pagehelper-spring-boot-starter.version>1.4.5</pagehelper-spring-boot-starter.version> <!-- 插件版本 --> <spring-boot-maven-plugin.version>2.7.4</spring-boot-maven-plugin.version> <mybatis-generator-maven-plugin.version>1.4.1</mybatis-generator-maven-plugin.version> <!-- 其他依賴包版本 --> <lombok.version>1.18.24</lombok.version> </properties>
升級後的測試並不充分,這里列出的發生版本變化的依賴包可能並不全面。
如果在編譯或運行時發現有某個依賴包報錯,說某個jdk的mole因為沒有導出而無法訪問的錯誤: cannot access class xxx (in mole jdk.xxx) because mole jdk.xxx does not export xxx to xxx,那麼就基本可以確定這個依賴包版本較老不兼容Java17。
解決方法很簡單,在當前這個時間點,基本上所有的第三方依賴包都已經有兼容Java17的較新的版本,直接去maven中央倉庫找一個新版本下載,就能解決問題。
比如上面的lombok版本升級到了1.18.24,就是為了解決編譯時發生的上述不兼容的錯誤。
另外,如果父工程中還約定了很多自用的通用工程的版本,那麼這里需要確保這些通用工程的版本范圍在新老版本中的定義沒有沖突。
例如老版本的父工程中定義了一些通用工程的版本:
<lib-xxx.version>[1.0.0-RELEASE,2.0.0-RELEASE)</lib-xxx.version>
這里的lib-xxx是這套JavaWeb開發框架中的一個通用庫,在老版本的父工程中約定它的版本范圍是[1.0.0-RELEASE,2.0.0-RELEASE),即從1.0.0-RELEASE(包含)到2.0.0-RELEASE(不包含)。那麼新版本的父工程,對它的版本范圍約定就是[2.0.0-RELEASE,3.0.0-RELEASE)。
這樣約定的目的是,如果有一些java工程仍然要使用老版本的父工程(假定由於種種原因,只能用Java11與Springboot2.1.x 。。。),那麼它就不會依賴2.0.0-RELEASE及其以上版本的lib-xxx;而一旦依賴了新版本的父工程,就只會依賴2.0.0-RELEASE及其以上版本的lib-xxx。
最後要注意,如果在老版本(這里就是Java11和Springboot2.1.11)上還有新的應用或需求變更要開發,那麼需要在代碼管理庫中切出一個新的分支來做升級的工作,並約定好各自的版本范圍,比如採用不同的主版本號。
2.4 單個Java工程的版本升級
在前面的2.1到2.3准備工作完成之後,就可以對java應用工程做版本升級了。
首先打開一個java工程,確認maven的目錄與配置文件是否正確,並將maven插件的profile選擇到jdk17,這一步已在步驟2.2中示意。
然後修改工程依賴的父工程版本為2.3中修改後的父工程版本。
<parent> <groupId>xxx</groupId> <artifactId>parent-xxx</artifactId> <version>2.0.0</version> </parent>
然後先使用maven插件刷新pom依賴,順利的話,可以在maven插件中看到新的依賴包版本:
pom依賴刷新之後,再來修改工程的idea配置中的java版本,打開Project Structrue,依次修改或確認java版本:
然後我們就可以對工程進行編譯,檢查有沒有編譯錯誤或警告。
考慮到devops的需要,你可能需要一個maven編譯腳本,要注意java版本,如下所示:
#!/bin/bash export JAVA_HOME=/usr/java/jdk-17.0.3+7 mvn -version mvn clean install package
注意這里指定了JAVA_HOME,maven編譯時會用到這個環境變數,因此指定為JDK17的安裝目錄。本地環境安裝有多個JDK版本時要特別注意這一點。
如果是springboot工程,編譯成功之後就可以啟動服務:
#!/bin/bash JAVA_HOME=/usr/java/jdk-17.0.3+7 JAR_PATH=$(find target -name "*.jar") ${JAVA_HOME}/bin/java -jar "${JAR_PATH}"
2.5 編譯與運行時遇到的問題
在編譯工程以及啟動springboot服務時,可能會遇到以下問題。
2.5.1 JDK模塊內API未導出問題
前面說過,Java16和Java17中有一些增強Java內部封裝的新特性,該特性加強了對一些以前暴露出來但其實很不安全的關鍵API的封裝,即你不再能從外部訪問這些內部API。而java的生態圈中有很多底層的類庫比如lombok在以前的版本中會調用到這些內部API。那麼在Java17以後將不再能調用它們,所以會有不兼容的問題。
這種問題的典型錯誤信息:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project api-brood-base: Fatal error compiling: java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed mole @0x5740ff5e) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in mole jdk.compiler) because mole jdk.compiler does not export com.sun.tools.javac.processing to unnamed mole @0x5740ff5e -> [Help 1]
這里的關鍵信息就是cannot access class xxx (in mole jdk.xxx) because mole jdk.xxx does not export xxx to xxx,一旦看到這句錯誤信息,就知道這是由於JDK加強了內部API的封裝所導致的不兼容問題。
解決起來很簡單,找個新版本就行了。以lombok為例,升級到版本1.18.24即可。
其他類庫的包也有可能出現類似的問題,解決方法一樣,換用更新的兼容Java17的版本即可。
2.5.2 redisTemplate版本不兼容
如果使用了spring的redisTemplate,那麼有可能出現版本不兼容,包括:
redisTemplate.delete方法編譯錯誤,方法參數的泛型發生了變化。
// 版本升級前編譯OK,升級後編譯錯誤 redisTemplate.delete(CollectionUtils.arrayToList(key)); // 版本升級後修改如下 redisTemplate.delete(Arrays.asList(key));
GenericObjectPoolConfig的setMaxWaitMillis被廢棄不再推薦使用,用setMaxWait代替:
GenericObjectPoolConfig<?> genericObjectPoolConfig = new GenericObjectPoolConfig<>(); ... // genericObjectPoolConfig.setMaxWaitMillis(redisProps.getPool().getMaxWait()); genericObjectPoolConfig.setMaxWait(Duration.ofMillis(redisProps.getPool().getMaxWait()));
2.5.3 jackson版本不兼容
spring默認使用的json工具類庫jackson,它的ObjectMapper的enableDefaultTyping被廢棄不再推薦使用,使用activateDefaultTyping代替
具體代碼如下所示:
ObjectMapper om = new ObjectMapper(); // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
2.5.4 循環依賴問題
springboot的新版本默認不再支持bean的循環依賴,因此項目中有循環依賴的bean的話,會報錯,例如:
The dependencies of some of the beans in the application context form a cycle: xxxxxxxxx ┌─────┐ | xxxService1 (field private com.gcsoft.brood.sentry.service.XxxService2 com.gcsoft.brood.sentry.service.xxxService1.xxxService2) ↑ ↓ | xxxService2 (field private com.gcsoft.brood.sentry.service.XxxService1 com.gcsoft.brood.sentry.service.XxxService2.xxxService1) └─────┘ Action: Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
最好的對應方式是消去bean之間的循環依賴,否則就需要顯式聲明允許bean的循環依賴,在application.yml中加入屬性:
spring: main: allow-circular-references: true
2.5.5 缺少spring.config.import配置
如果在pom工程中依賴了springcloud的相關jar,但並沒有使用springcloud相關的config配置,那麼在啟動springboot服務時可能會失敗:
No spring.config.import property has been defined Action: Add a spring.config.import=configserver: property to your configuration. If configuration is not required add spring.config.import=optional:configserver: instead. To disable this check, set spring.cloud.config.enabled=false or spring.cloud.config.import-check.enabled=false.
按照提示,在application.yml中加入屬性:
spring: cloud: config: enabled: false
2.5.6 jetty版本沖突
springboot版本升級後,內嵌的jetty版本也升級了。由於某些第三方jar使用了低版本的jetty的某些包,即使springboot沒有使用jetty,也依然會在運行時發生jetty的不兼容問題:
java.lang.ClassNotFoundException: org.eclipse.jetty.server.RequestLog$Writer
這里可以選擇升級第三方jar。
或者直接去除第三方jar對jetty的依賴:
<dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-jdbc</artifactId> <version>${hive.version}-${cdh.version}</version> <exclusions> <exclusion> <artifactId>jetty-all</artifactId> <groupId>org.eclipse.jetty.aggregate</groupId> </exclusion> </exclusions> </dependency>
2.6 docker鏡像
在各個工程完成升級,編譯成功,並簡單運行OK之後,開始做docker鏡像的升級工作。
畢竟現在都在雲端跑服務了。。。
這里從Docker Hub上找了與開發使用的openJDK版本一致的docker鏡像,也是由eclipse的Adoptium社區提供的。
其實沒有必要,其他openJDK17版本的docker鏡像也是一樣的,單純的強迫症而已。。。
docker pull eclipse-temurin:17.0.3_7-jdk-alpine
對應docker hub地址:
Docker Hub
在這個openJDK17鏡像的基礎上,修改了時區與語言等信息,安裝了bash與telnet,DockerFile如下:
# 指定基礎鏡像,在其上進行定製(這里是 eclipse-temurin:17.0.3_7-jdk-alpine 的鏡像) FROM eclipse-temurin:17.0.3_7-jdk-alpine # 定製環境變數 ENV TIME_ZONE=Asia/Shanghai \ LANG=en_US.UTF-8 \ LANGUAGE=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 # RUN在build鏡像時執行,每RUN一次就會構成一層新的鏡像。 # 因此有多個命令要執行時,用"&&"連接寫在一起。 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.e.cn/g' /etc/apk/repositories \ && apk add --no-cache tzdata \ && echo "${TIME_ZONE}" > /etc/timezone \ && ln -sf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime \ && apk add --no-cache bash bash-doc bash-completion busybox-extras
原始的eclipse-temurin:17.0.3_7-jdk-alpine有335M,添加了tzdata,bash,busybox-extras(telnet)之後,大小是340.8M。。。完整的JDK鏡像就是這么大。。。如果生產環境不需要JDK,那麼可以用JRE作成的鏡像,會小不少,但是缺失了很多JDK工具。
用這個DockerFile做成一個新的openJDK17鏡像,命名為xxx/base-openjdk17:jdk-17.0.3_001,而各個springboot工程的DockerFile如下所示:
# 指定基礎鏡像 FROM xxx/base-openjdk17:jdk-17.0.3_001 # JDK11開始支持: -XX:+UseContainerSupport 使JVM能夠感知容器資源, -XX:InitialRAMPercentage 初期容器內存佔比, -XX:MaxRAMPercentage 最大容器內存佔比 ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:InitialRAMPercentage=50 -XX:MaxRAMPercentage=80" # 復制上下文目錄下的target/*.jar 到容器里 ADD target/*.jar app.jar # 指定容器啟動程序及參數 <ENTRYPOINT> "<CMD>" ENTRYPOINT java ${JAVA_OPTS} -jar /app.jar
該DockerFile位於springboot工程根目錄下。
打進了springboot fat jar的鏡像會變得更大,一般都會有400M以上。。。
三、小結
總的來說,Java11到Java17的升級比較順利,只有少數依賴包對應版本需要升級。另外就是springboot的升級可能導致需要添加少量配置,比如顯式允許bean的循環依賴
Ⅸ hive 使用tez
1,編譯tez 見 https://www.jianshu.com/p/b2569796dd27
2,將 編譯後的tez-0.9.2.tar.gz 上傳到hdfs上. tez-site.xml中會使用到.見tez.lib.uris屬性.
3,在 $HADOOP_HOME/etc/hadoop 下新建 tez-site.xml.內容如下
4,設置 hive. 修改hive-site.xml文件
5,設置客戶端的tez. 將 tez-0.9.2.tar.gz 解壓到本地 /usr/tez下.
6,重啟服務
會有一下一些錯誤.
錯誤1 :cause: org.apache.hadoop.service.ServiceStateException: java.lang.NoClassDefFoundError: com/google/common/net/UrlEscapers
解決: 我是將$HIVE_HOME/lib中的guava-14.0.1.jar 升級到guava-19.0.jar. 這個問題解決.但是日誌中還是有些錯誤,不影響結果的產出.
錯誤2:
使用hive cli 的方式可以正常提交sql.並且在yarn上可以看到作業的運行情況.
但是使用 ** beeline -u jdbc: hive2://localhost:10000 ** .在yarn上看不到作業運行,並且報錯. 錯誤日誌只能在hive ui上查看.
Ⅹ 如何在Java中執行Hive命令或HiveQL
Java在1.5過後提供了ProcessBuilder根據運行時環境啟動一個Process調用執行運行時環境下的命令或應用程序(1.5以前使用Runtime),關於ProcessBuilder請參考Java相關文檔。調用代碼如下:
String sql="show tables; select * from test_tb limit 10";
List<String> command = new ArrayList<String>();
command.add("hive");
command.add("-e");
command.add(sql);
List<String> results = new ArrayList<String>();
ProcessBuilder hiveProcessBuilder = new ProcessBuilder(command);
hiveProcess = hiveProcessBuilder.start();
BufferedReader br = new BufferedReader(new InputStreamReader(
hiveProcess.getInputStream()));
String data = null;
while ((data = br.readLine()) != null) {
results.add(data);
}
其中command可以是其它Hive命令,不一定是HiveQL。
