第三章 Hadoop核心組件應(yīng)用案例_第1頁
第三章 Hadoop核心組件應(yīng)用案例_第2頁
第三章 Hadoop核心組件應(yīng)用案例_第3頁
第三章 Hadoop核心組件應(yīng)用案例_第4頁
第三章 Hadoop核心組件應(yīng)用案例_第5頁
已閱讀5頁,還剩63頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

HadoopJavaAPI讀取序列化日志文件主講:李強(qiáng)任務(wù)描述現(xiàn)有一份2020年用戶登錄某網(wǎng)站的序列化文件,本小節(jié)將使用HadoopJavaAPI的方式讀取序列化文件,并將讀取的數(shù)據(jù)保存到本地文件系統(tǒng)中,查看文件內(nèi)容是否是1月和2月的用戶登錄信息。任務(wù)分析本小節(jié)將進(jìn)行如下操作,完成序列化文件的讀取。(1)在Windows系統(tǒng)中配置Java開發(fā)環(huán)境,即安裝JDK、設(shè)置環(huán)境變量。(2)下載與安裝IntelliJIDEA。(3)創(chuàng)建Java工程。(4)讀取序列化文件并保存到本地。3.1.1配置開發(fā)環(huán)境1.安裝JDK8Java提供了標(biāo)準(zhǔn)的軟件開發(fā)工具箱JavaDevelopmentKit(JDK)。利用JDK可以開發(fā)Java桌面應(yīng)用程序和低端的服務(wù)器應(yīng)用程序,目前較為常用的版本為JDK1.8。安裝jdk-8u301-windows-x64.exe,具體步驟如下。(1)打開jdk-8u301-windows-x64.exe,點(diǎn)擊“下一步”,如圖3-1所示。圖3-1打開JDK安裝包1.安裝JDK8(2)在JDK“定制安裝”對(duì)話框中選擇安裝位置,然后點(diǎn)擊“下一步”,如圖3-2所示。圖3-2選擇JDK安裝位置1.安裝JDK8(3)完成JDK安裝后,安裝程序?qū)⑻崾綣ava運(yùn)行環(huán)境(JRE)的安裝,在“目標(biāo)文件夾”對(duì)話框中點(diǎn)擊“更改”按鈕修改JRE的安裝位置,然后點(diǎn)擊“下一步”,如圖3-3所示。圖3-3選擇JRE安裝位置1.安裝JDK8提示“已成功安裝”即可點(diǎn)擊“關(guān)閉”按鈕,如圖3-4所示。圖3-4完成JDK安裝2.設(shè)置環(huán)境變量環(huán)境變量是指在操作系統(tǒng)中用來指定操作系統(tǒng)運(yùn)行環(huán)境的一些參數(shù),包含了一個(gè)或者多個(gè)應(yīng)用程序所將使用到的信息。例如,Windows和DOS操作系統(tǒng)中的path環(huán)境變量,當(dāng)要求系統(tǒng)運(yùn)行一個(gè)程序而沒有告知程序所在的完整路徑時(shí),系統(tǒng)除了在當(dāng)前目錄下尋找此程序外,還應(yīng)到path中指定的路徑尋找。用戶通過設(shè)置環(huán)境變量,可以更好地運(yùn)行進(jìn)程。在Windows系統(tǒng)中設(shè)置環(huán)境變量,具體步驟如下。(1)右鍵單擊桌面的“此電腦”圖標(biāo),選擇“屬性”,如圖3-5所示。(2)在“設(shè)置”界面中找到相關(guān)設(shè)置的“高級(jí)系統(tǒng)設(shè)置”,如圖3-6所示。圖3-5打開此電腦屬性圖3-6高級(jí)系統(tǒng)設(shè)置2.設(shè)置環(huán)境變量(3)在彈出的“系統(tǒng)屬性”對(duì)話框中,單擊“環(huán)境變量”按鈕,在彈出的“環(huán)境變量”對(duì)下方“系統(tǒng)變量”話框中單擊新建,在“變量名”一欄中輸入“JAVA_HOME”,在“變量值”一欄中輸入JDK的安裝路徑,如圖3-7所示。圖3-7配置系統(tǒng)變量JAVA_HOME2.設(shè)置環(huán)境變量(4)在“系統(tǒng)變量”中找到變量“Path”并雙擊進(jìn)行編輯,點(diǎn)擊“新建”按鈕,輸入“%JAVA_HOME%\bin”,點(diǎn)擊確定,如圖3-8所示。圖3-8編輯系統(tǒng)環(huán)境Path2.設(shè)置環(huán)境變量(5)在命令提示符中輸入javac,返回信息不提示報(bào)錯(cuò),說明環(huán)境變量配置正確,如圖3-9所示。圖3-9javac驗(yàn)證配置2.設(shè)置環(huán)境變量(6)參考第3步,新建一個(gè)系統(tǒng)變量,在“變量名”一欄中輸入“HADOOP_HOME”,在“變量值”一欄中輸入Hadoop3.1.4安裝包解壓后的路徑,如圖3-10所示。(7)參考第4步,在“系統(tǒng)變量”的變量“Path”中新添一項(xiàng)變量,內(nèi)容為“%HADOOP_HOME%\bin”,點(diǎn)擊確定。圖3-10配置系統(tǒng)變量HADOOP_HOME3.1.2創(chuàng)建Maven工程創(chuàng)建Maven工程在官網(wǎng)下載IntelliJIDEA安裝包,安裝包名稱為“ideaIC-2018.3.6.exe”,本書使用的IDEA版本為社區(qū)版,即Community版,社區(qū)版是免費(fèi)開源的。下載后,請(qǐng)按照軟件指示進(jìn)行安裝。在IDEA中創(chuàng)建Maven工程流程如下。(1)啟動(dòng)IDEA,單擊“CreateNewProjects”,在“NewProject”對(duì)話框中選擇“Maven”,將“ProjectSDK”設(shè)置為3.1.1所配置的JDK8,如圖3-11所示,點(diǎn)擊“Next”。圖3-11創(chuàng)建Maven項(xiàng)目創(chuàng)建Maven工程(2)在彈出的頁面中,輸入項(xiàng)目名稱為“Hadoop_Java_API”,如圖3-12所示,完成后單擊“Finish”按鈕。(3)創(chuàng)建完成的Maven工程的菜單面板,如圖3-13所示。圖3-12對(duì)項(xiàng)目進(jìn)行命名圖3-13工程的菜單面板3.1.3讀取序列化文件讀取序列化文件在pom.xml文件里“</properties>”與“</project>”之間添加Hadoop依賴,內(nèi)容如表3-1所示。表3-1添加Hadoop依賴<dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>3.1.4</version></dependency>...省略...<dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-core</artifactId><version>3.1.4</version></dependency></dependencies>讀取序列化文件添加完成后,在pom.xml文件界面任意處單擊右鍵,選擇“Maven”→“Reloadproject”,如圖3-14所示,或單擊界面右上角

,加載依賴。圖3-14加載依賴讀取序列化文件單擊右鍵如圖3-13所示的“java”,選擇“New”,單擊“Package”,如圖3-15所示,在彈出的頁面中輸入“demo”,單擊Enter鍵,完成名為“demo”的Package的創(chuàng)建,如圖3-16所示。圖3-15新建Package圖3-16為包命名讀取序列化文件單擊右鍵“demo”,選擇“New”,單擊“JavaClass”,如圖3-17所示,在彈出的窗口輸入“ReadSequenceFile”,單擊Enter鍵,完成Java文件的創(chuàng)建,如圖3-18所示。圖3-17新建JavaClass圖3-18為Java文件命名讀取序列化文件HadoopJavaAPI提供了讀取HDFS上的文件的方法,也可以讀取序列化文件,不同于普通文件的讀取方法,讀取序列化文件需要獲取到SequenceFile.Reader對(duì)象。讀取序列化文件,將讀取的數(shù)據(jù)寫入到本地文件系統(tǒng)的janfeb.txt文件中,代碼如代碼3-1所示。代碼3-1讀取序列化文件publicclassReadSequenceFile{publicstaticvoidmain(String[]args)throwsIOException{//獲取配置Configurationconf=newConfiguration();conf.set("fs.defaultFS","master:8020");//獲取文件系統(tǒng)FileSystemfs=FileSystem.get(conf);//獲取SequenceFile.Reader對(duì)象SequenceFile.Readerreader=newSequenceFile.Reader(fs,newPath("/data/sFile"),conf);

//獲取序列化文件中使用的鍵值類型Textkey=newText();Textvalue=newText();BufferedWriterout=newBufferedWriter(newOutputStreamWriter(newFileOutputStream("D:\\data\\janfeb.txt",true)));while(reader.next(key,value)){out.write(key.toString()+"\t"+value.toString()+"\r\n");}out.close();reader.close();}}讀取序列化文件執(zhí)行命令“hdfsdfs-put/opt/sFile/data”將Linux系統(tǒng)目錄/opt下的序列化文件sFile上傳至HDFS系統(tǒng)data目錄下,然后在ReadSequenceFile.java頁面單擊右鍵,選擇“Run'ReadSequenceFile.main()'”運(yùn)行ReadSequenceFile.java程序,如圖3-19所示。運(yùn)行完成后,查看D:\\data\\janfeb.txt文件,序列化文件讀取結(jié)果,如圖3-20所示。讀取序列化文件的結(jié)果文件查看janfeb.txt的文件內(nèi)容,可以發(fā)現(xiàn)文件中的數(shù)據(jù)都是1月和2月的數(shù)據(jù),這說明該序列化文件確實(shí)是1月和2月的用戶登錄信息數(shù)據(jù)。圖3-19運(yùn)行程序圖3-20

序列化文件讀取結(jié)果謝謝電影網(wǎng)站用戶性別測試主講:李強(qiáng)任務(wù)描述M網(wǎng)站是一個(gè)深受用戶歡迎的電影社區(qū)網(wǎng)站,它提供大量的電影介紹及評(píng)論,包括上映影片的影訊查詢及購票服務(wù)。用戶可以記錄想看、在看和看過的電影,順便打分、寫影評(píng)。為了提高用戶的使用體驗(yàn)與滿意度,網(wǎng)站計(jì)劃為廣大用戶提供更精準(zhǔn)更個(gè)性化的電影推薦服務(wù)??赡軙?huì)使用以下用戶信息數(shù)據(jù),如表3-2所示,有部分記錄的性別數(shù)據(jù)是缺失的。眾所周知,性別是用戶的一個(gè)非常重要的特征,也是建立推薦模型的一個(gè)重要維度指標(biāo)。那么獲得用戶信息中缺失的性別數(shù)據(jù),就是目前要解決的首要任務(wù)。本小節(jié)也將圍繞這一主題展開,嘗試以預(yù)測的方式來獲得用戶的性別信息。表3-2M電影網(wǎng)站用戶信息UserIDGenderAgeOccupationZip-code1F110480672M5616700723

2515551174

357024605M2520554556F509551177M35106810任務(wù)分析如圖3-21所示的數(shù)據(jù),是對(duì)每個(gè)用戶的性別信息及該用戶看過的電影類型的統(tǒng)計(jì)情況。其中UserID代表的是用戶ID,Gender代表的是用戶性別,其中1代表的是女性,0代表的是男性。Age代表的是用戶的年齡,Occupation代表的是用戶的職業(yè),Zip-code代表的是用戶的地區(qū)編碼。Action到Western代表的是電影的不同類型。例如,某條記錄中Action字段的值是4,則說明該用戶看過4部動(dòng)作片的電影。圖3-21用戶觀看過的電影類型統(tǒng)計(jì)數(shù)據(jù)任務(wù)分析本小節(jié)將使用MapReduce編程技術(shù),利用KNN算法對(duì)已知性別用戶觀看的電影類型統(tǒng)計(jì)數(shù)據(jù)建立聚類器,并且對(duì)這個(gè)聚類器的聚類結(jié)果進(jìn)行評(píng)價(jià),選出聚類性能最好的一個(gè)聚類器用于對(duì)未知性別的用戶進(jìn)行聚類。因?yàn)橛脩粼谠L問網(wǎng)站的電影時(shí)產(chǎn)生了大量的歷史瀏覽數(shù)據(jù),從用戶瀏覽過的電影類型記錄來預(yù)測該用戶的性別,這可以作為一個(gè)解決思路來進(jìn)行嘗試,大致的實(shí)現(xiàn)步驟可以是這樣的。(1)對(duì)用戶看過的所有電影類型進(jìn)行統(tǒng)計(jì),再通過已知性別用戶觀看電影的類型統(tǒng)計(jì)數(shù)據(jù)建立一個(gè)聚類器。(2)向聚類器輸入未知性別用戶觀看電影的類型統(tǒng)計(jì)數(shù)據(jù),獲得該用戶的性別聚類。3.2.1獲取數(shù)據(jù)獲取數(shù)據(jù)本小節(jié)為讀者提供四份與用戶信息相關(guān)的文件,分別為用戶對(duì)電影的評(píng)分?jǐn)?shù)據(jù)ratings.dat,已知性別的用戶信息數(shù)據(jù)users.dat,電影信息數(shù)據(jù)movies.dat以及數(shù)據(jù)相關(guān)字段的解釋文件README,其中README文件僅作為了解數(shù)據(jù)作用,此處不做展示。部分用戶對(duì)電影的評(píng)分?jǐn)?shù)據(jù)ratings.dat包含4個(gè)字段,即UserID(用戶ID),MovieID(電影ID),Rating(評(píng)分)及Timestamp(時(shí)間戳)。其中UserID的范圍是1到6040,MovieIDS的范圍是1到3952,Rating采用五分好評(píng)制度,即最高分為5分,最低分為1分。部分已知性別的用戶信息數(shù)據(jù)users.dat數(shù)據(jù)包含5個(gè)字段,分別為UserID(用戶ID),Gender(性別),Age(年齡),Occupation(職業(yè))以及Zip-code(編碼)。其中Occupation字段代表的是21種不同的職業(yè)類型,Age字段記錄的也并不是用戶的實(shí)際年齡,而是一個(gè)年齡段,比如1代表的是18歲以下,具體的解釋請(qǐng)參考README。部分電影信息數(shù)據(jù)movies.dat字段包含MovieID(電影ID),Title(電影名稱),Genres(電影類型)三個(gè)字段。其中Title字段不僅記錄電影的名稱,還記錄了電影的上映時(shí)間。數(shù)據(jù)中總共記錄了18種電影類型,包括喜劇片,動(dòng)作片,警匪片,愛情片等,具體的電影類型種類請(qǐng)參見README。3.2.2數(shù)據(jù)變換數(shù)據(jù)變換參考任務(wù)3.1,創(chuàng)建名為“Movie_knn”的Maven工程,在pom.xml文件里“</properties>”與“</project>”之間添加Hadoop依賴,內(nèi)容如表3-1所示。在src/main文件夾單擊右鍵選擇“New”→“Directory”,如圖3-22所示,創(chuàng)建一個(gè)名為“datajoin”的文件夾。圖3-22創(chuàng)建文件夾數(shù)據(jù)變換創(chuàng)建完文件夾后,對(duì)著“datajoin”單擊右鍵選擇“MarkDirectoryas”→“SourcesRoot”,如圖3-23所示,激活“datajoin”文件夾,使其以及子文件夾下的文件成為IDEA可編譯的原文件,激活后文件夾呈藍(lán)色,然后參考3.1.4小節(jié),創(chuàng)建名為“demo01”的Package。圖3-23激活文件夾數(shù)據(jù)變換數(shù)據(jù)變換是指將數(shù)據(jù)從一種表現(xiàn)形式變?yōu)榱硪环N表現(xiàn)形式的過程,數(shù)據(jù)變換主要是找到數(shù)據(jù)的特征表示。將網(wǎng)站用戶的用戶信息數(shù)據(jù)及觀影記錄數(shù)據(jù)轉(zhuǎn)換得到用戶觀看電影的類型統(tǒng)計(jì)數(shù)據(jù)的思路如下。(1)根據(jù)UserID字段連接ratings.dat數(shù)據(jù)和users.dat數(shù)據(jù),連接結(jié)果得到一份包含UserID(用戶ID),Gender(性別),Age(年齡),Occupation(職業(yè)),Zip-code(編碼),MovieID(電影ID)的數(shù)據(jù),連接的MapReduce代碼如代碼3-1所示。代碼3-1連接ratings.dat數(shù)據(jù)和users.dat數(shù)據(jù)的三個(gè)Java代碼的重要部分publicclassJarUtil{publicstaticStringjar(Class<?>cls){//驗(yàn)證okStringoutputJar=cls.getName()+".jar";Stringinput=cls.getClassLoader().getResource("").getFile();input=input.substring(0,input.length()-1);input=input.substring(0,input.lastIndexOf("/")+1);input=input+"bin/";jar(input,outputJar);returnoutputJar;}....省略....數(shù)據(jù)變換編寫好3個(gè)代碼后,單擊頁面上方菜單“File”選項(xiàng),選擇“ProjectStructure…”,在跳出的“ProjectStructure”窗口選擇“Artifacts”→“+”→“JAR”→“Frommoduleswithdependencies…”,如圖3-24所示,創(chuàng)建Jar包。圖3-24創(chuàng)建Jar包數(shù)據(jù)變換在彈出的對(duì)話框的“MainClass”選區(qū)中選擇RatingsAndUsers文件,單擊“OK”。為方便區(qū)分,將“Name”修改為“demo01”,如圖3-25所示,單擊“Apply”“OK”,完成Jar的添加。圖3-25修改“Name”數(shù)據(jù)變換在IDEA主界面選擇“Build”→“BuildArtifacts…”,如圖3-26所示,在彈出的窗口中選擇“demo01”→“Build”,如圖3-27所示,進(jìn)行編譯Jar文件。圖3-27編譯Jar文件2圖3-26編譯Jar文件1數(shù)據(jù)變換為方便區(qū)分,對(duì)生成的“Movie_knn.jar”文件單擊右鍵選擇“Refactor”→“Rename…”,如圖3-28所示,重命名為“demo01.jar”,如圖3-29所示,然后單擊“Refactor”。圖3-29重命名2圖3-28重命名1數(shù)據(jù)變換參考項(xiàng)目1將Jar包上傳到Linux的/opt目錄下,在HDFS上新建文件夾/movie,將ratings.dat,users.dat上傳到/movie下,程序運(yùn)行結(jié)果保存在/movie/ratings_users目錄下。在集群終端的命令行執(zhí)行如代碼3-2所示的命令。代碼3-2連接ratings.dat數(shù)據(jù)和users.dat數(shù)據(jù)的程序運(yùn)行命令hadoopjar/opt/demo01.jardemo01.RatingsAndUsers/movie/users.dat/movie/ratings.dat/movie/ratings_users程序運(yùn)行成功后登陸HDFSWebUI,選擇“Utilitles…”→“Browsethefilesystem”,查看/movie/ratings_users/part-m-00000文件,單擊“Headthefile”查看文件內(nèi)容,如圖3-30所示。圖3-30ratings.dat數(shù)據(jù)和users.dat數(shù)據(jù)的連接結(jié)果數(shù)據(jù)變換(2)根據(jù)MovieID連接movies.dat數(shù)據(jù)和/movie/ratings_users/part-m-00000上的數(shù)據(jù),連接結(jié)果得到一份包含UserID(用戶ID),Gender(性別),Age(年齡),Occupation(職業(yè)),Zip-code(編碼),MovieID(電影ID),Genres(電影類型)。在datajoin文件夾下創(chuàng)建“demo02”的Package,連接MapReduce程序代碼如代碼3-3所示。代碼3-3連接movies.dat數(shù)據(jù)與ratings_users數(shù)據(jù)的程序代碼重要部分publicclassUsersMoviesMapperextendsMapper<LongWritable,Text,Text,NullWritable>{privateHashMap<String,String>movie_info=newHashMap<String,String>();privateStringsplitter="";privateStringmovie_secondPart="";@Overrideprotectedvoidsetup(Mapper<LongWritable,Text,Text,NullWritable>.Contextcontext)throwsIOException,InterruptedException{Path[]DistributePaths=DistributedCache.getLocalCacheFiles(context.getConfiguration());splitter=context.getConfiguration().get("SPLITTER");Stringline="";BufferedReaderbr=null;....省略....數(shù)據(jù)變換參考第1步的操作,將demo02.jar包上傳至Linux的opt目錄下,將movies.dat數(shù)據(jù)上傳到HDFS的/movie目錄下,運(yùn)行結(jié)果保存在/movie/users_movies。在集群終端的命令行運(yùn)行如代碼3-4所示的命令。代碼3-4連接movies.dat數(shù)據(jù)與ratings_users數(shù)據(jù)的程序運(yùn)行命令hadoopjar/opt/demo02.jardemo02.UsersAndMovies/movie/movies.dat/movie/ratings_users/part-m-00000/movie/users_movies參考第1步的操作,查看/movie/users_movies/part-m-00000文件內(nèi)容,如圖3-31所示。圖3-31movies.dat數(shù)據(jù)與ratings_users數(shù)據(jù)連接結(jié)果數(shù)據(jù)變換(3)對(duì)每個(gè)用戶看過的電影類型進(jìn)行統(tǒng)計(jì),例如,假設(shè)圖3-31所示的數(shù)據(jù)就是UserID為1的用戶看過的所有電影,那么通過統(tǒng)計(jì)可以得到該用戶看過2部Action類電影,2部Adventure類電影,2部Animation類電影,2部Children’s類電影,3部Comedy類電影,4部Drama類電影,2部Musical類電影,2部Romance類電影,其他類型的電影都沒有看過,即為0,因此可以得到該用戶的一個(gè)特征向量,如表3-3所示。表3-3對(duì)某用戶看過的電影類型統(tǒng)計(jì)得到的特征向量數(shù)據(jù)1,F,1,10,48067,2,2,2,2,3,0,0,4,0,0,0,2,0,2,0,0,0,0數(shù)據(jù)變換對(duì)每個(gè)用戶看過電影類型進(jìn)行統(tǒng)計(jì),得到一個(gè)特征向量矩陣,可通過MapReduce編程實(shí)現(xiàn)。在Map階段,對(duì)Gender(性別)做一步轉(zhuǎn)換,如果是女性(F)則用1標(biāo)記,如果是男性(M)則用0標(biāo)記,Map輸出的鍵是UserID(用戶ID),Gender(性別),Age(年齡),Occupation(職業(yè))和Zip-code(編碼),輸出的值是Genres(電影類型)。Map端的實(shí)現(xiàn)流程如圖3-32所示。表3-3對(duì)某用戶看過的電影類型統(tǒng)計(jì)得到的特征向量數(shù)據(jù)數(shù)據(jù)變換在Reduce階段,reduce函數(shù)首先為每個(gè)用戶初始化一個(gè)HashMap集合,集合中有18個(gè)鍵值對(duì),鍵分別為18種電影類型,每個(gè)鍵對(duì)應(yīng)的值為0。Map端輸出的鍵值對(duì)中相同鍵的值被整合到一個(gè)列表中,reduce函數(shù)針對(duì)相同的鍵,遍歷其值列表,對(duì)列表中每個(gè)元素根據(jù)分隔符“|”進(jìn)行分割,遍歷分割結(jié)果,如果HashMap集合中的鍵包含分割結(jié)果中的元素,則該鍵對(duì)應(yīng)的值加1。最后將HashMap所有鍵對(duì)應(yīng)的值及Reduce輸入的鍵用逗號(hào)分隔符合并成一個(gè)字符串作為Reduce輸出的鍵,Reduce輸出的值則為空。Reduce端的實(shí)現(xiàn)流程如圖3-33所示。圖3-33Reduce端的實(shí)現(xiàn)流程數(shù)據(jù)變換Mapper類及Reducer類的實(shí)現(xiàn)代碼如代碼3-5所示。代碼3-5對(duì)每個(gè)用戶看過電影類型進(jìn)行統(tǒng)計(jì)的Mapper類及Reducer代碼重要部分packagedemo03;publicclassMoviesGenresMapperextendsMapper<LongWritable,Text,UserAndGender,Text>{ privateUserAndGenderuser_gender=newUserAndGender(); privateStringsplitter=""; privateTextgenres=newText(); @Override protectedvoidsetup(Mapper<LongWritable,Text,UserAndGender,Text>.Contextcontext) throwsIOException,InterruptedException{ splitter=context.getConfiguration().get("SPLITTER"); } @Override protectedvoidmap(LongWritablekey,Textvalue,Mapper<LongWritable,Text,UserAndGender,Text>.Contextcontext) throwsIOException,InterruptedException{ String[]val=value.toString().split(splitter); user_gender.setUserID(val[0]);.......省略......數(shù)據(jù)變換Driver類實(shí)現(xiàn)代碼如代碼3-6所示。代碼3-6對(duì)每個(gè)用戶看過電影類型進(jìn)行統(tǒng)計(jì)的Driver類代碼的重要部分packagedemo03;publicclassUserAndGenderimplementsWritableComparable<UserAndGender>{privateStringuserID;privateintgender;privateintage;privateStringoccupation;privateStringzip_code;publicintgetAge(){returnage;}publicvoidsetAge(intage){this.age=age;}.......省略......數(shù)據(jù)變換同樣將代碼3-5和代碼3-6打包成demo03.jar,將其上傳至Linux的opt目錄下。在集群終端的命令行運(yùn)行如代碼3-7所示的命令。代碼3-7對(duì)每個(gè)用戶看過電影類型進(jìn)行統(tǒng)計(jì)的程序運(yùn)行命令hadoopjar/opt/demo03.jardemo03.MoviesGenres/movie/users_movies/part-m-00000/movie/gender_genre::查看/movie/gender_genre/part-m-00000文件內(nèi)容,統(tǒng)計(jì)結(jié)果如圖3-34所示。圖3-34對(duì)每個(gè)用戶看過電影類型進(jìn)行統(tǒng)計(jì)的結(jié)果3.2.3數(shù)據(jù)清洗數(shù)據(jù)清洗數(shù)據(jù)清洗是數(shù)據(jù)預(yù)處理的一個(gè)重要步驟,3.2.2變換得到的數(shù)據(jù)中可能含有噪聲數(shù)據(jù),例如缺失值或者異常值,這類數(shù)據(jù)將會(huì)影響聚類器的建立,因此需要對(duì)這類數(shù)據(jù)進(jìn)行處理。一般情況下,數(shù)據(jù)中的缺失值可能是表示成空(即沒有值)、“NULL”“null”或“NAN”。而異常值則需要根據(jù)實(shí)際情況判斷,如3.2.2集成的數(shù)據(jù)的有些屬性列代表用戶看過的某種類型的電影的部數(shù),那么該值應(yīng)該大于或等于0,如果該值是小于0的則是屬于異常值。處理缺失值的方法可分為2類:刪除記錄和數(shù)據(jù)插補(bǔ)。本節(jié)采用數(shù)據(jù)插補(bǔ)的方式處理缺失值,由于屬性列的數(shù)據(jù)都是數(shù)值型數(shù)據(jù),所以用常量0替換缺失值。而異常值的處理方法有如下3種。(1)刪除含有異常值的記錄。(2)視為缺失值。(3)平均值修正:即用前后兩個(gè)觀測值的平均值修正異常值。對(duì)于異常值,本節(jié)將其視為缺失值,同處理缺失值的方法一樣,用常量0替換異常值。數(shù)據(jù)清洗將缺失值和異常值替換成0可以用MapReduce編程實(shí)現(xiàn),其思路非常簡單,針對(duì)3.2.2集成的數(shù)據(jù),在Mapper類中自定義計(jì)數(shù)器用于記錄數(shù)據(jù)中缺失值和異常值的記錄數(shù),在map函數(shù)讀取數(shù)據(jù),判斷讀取進(jìn)來的數(shù)據(jù)是否含有缺失值,若有則將該值替換成0,同時(shí)缺失值計(jì)數(shù)器加1,再判斷數(shù)據(jù)中是否有異常值,若有異常值則將該值替換成0并且異常值計(jì)數(shù)器加1。具體的實(shí)現(xiàn)代碼如代碼3-8所示。代碼3-8處理缺失值及異常值代碼重要部分packagepro_demo;publicclassDataProcessingMapperextendsMapper<LongWritable,Text,Text,NullWritable>{ privateStringsplitter=""; enumDataProcessingCounter{ NullData, AbnormalData } @Override protectedvoidsetup(Mapper<LongWritable,Text,Text,NullWritable>.Contextcontext) throwsIOException,InterruptedException{ splitter=context.getConfiguration().get("SPLITTER"); }.......省略......數(shù)據(jù)清洗打包成pro_demo.jar并上傳至Linux系統(tǒng)/opt目錄下。在集群終端的命令行運(yùn)行如代碼3-9所示的命令。代碼3-9數(shù)據(jù)清洗的程序運(yùn)行命令hadoopjar/opt/pro_demo.jarpro_demo.DataProcessing/movie/gender_genre/part-m-00000/movie/processing_out,運(yùn)行日志如圖3-35所示,其中部分日志省略,從圖中可以看出,記錄缺失值的計(jì)數(shù)器NullData的記錄結(jié)果為0,記錄異常值的計(jì)數(shù)器AbnormalData的記錄結(jié)果也為0,說明3.2.2集成的數(shù)據(jù)中沒有缺失值和異常值。圖3-35處理缺失值和異常值的MapReduce任務(wù)運(yùn)行日志3.2.4劃分?jǐn)?shù)據(jù)集劃分?jǐn)?shù)據(jù)集一般來說,聚類算法有3個(gè)過程:第一步是通過歸納分析訓(xùn)練樣本集來建立聚類器,第二步是用驗(yàn)證數(shù)據(jù)集來選擇最優(yōu)的模型參數(shù),第三步是用已知類別的測試樣本集評(píng)估聚類器的準(zhǔn)確性,如果準(zhǔn)確率是可以接受的,則使用該模型對(duì)未知類標(biāo)號(hào)的待測樣本集進(jìn)行預(yù)測。因此聚類算法需要把數(shù)據(jù)分成訓(xùn)練數(shù)據(jù),驗(yàn)證數(shù)據(jù)集和測試數(shù)據(jù)集。在建立M電影用戶聚類器之前,將預(yù)處理之后的數(shù)據(jù)劃分成訓(xùn)練數(shù)據(jù)集,驗(yàn)證數(shù)據(jù)集和測試數(shù)據(jù)集。采用8:1:1的比例隨機(jī)劃分?jǐn)?shù)據(jù)集,其中訓(xùn)練數(shù)據(jù)集占80%,驗(yàn)證數(shù)據(jù)集和測試數(shù)據(jù)集各占10%。劃分?jǐn)?shù)據(jù)集可以使用HadoopJavaAPI進(jìn)行處理,定義讀取原數(shù)據(jù)集并計(jì)算原始數(shù)據(jù)集記錄數(shù)的方法getSize(FileSystemfs,Pathpath),其中參數(shù)path是原數(shù)據(jù)集預(yù)處理之后的存放路徑。將原始數(shù)據(jù)看成一個(gè)列表,列表中的元素是每一條數(shù)據(jù),定義隨機(jī)獲取80%原始數(shù)據(jù)的數(shù)據(jù)下標(biāo)的方法trainIndex,該方法返回一個(gè)Set集合,例如,假如訓(xùn)練數(shù)據(jù)集得到的數(shù)據(jù)是原始數(shù)據(jù)的第1,第3,第5條數(shù)據(jù),則trainIndex方法的得到的Set集合的元素就為<1,3,5>。再定義隨機(jī)獲取10%原始數(shù)據(jù)的數(shù)據(jù)下標(biāo)的方法validateIndex,該方法同樣返回一個(gè)Set集合。trainIndex方法得到的集合與validateIndex得到的集合中的元素是不重復(fù)的。劃分?jǐn)?shù)據(jù)集創(chuàng)建SplitData.java文件,以上所述三個(gè)方法的具體實(shí)現(xiàn)代碼如代碼3-10所示。代碼3-10讀取HDFS的數(shù)據(jù)并統(tǒng)計(jì)記錄數(shù)的方法/***讀取原始數(shù)據(jù)并統(tǒng)計(jì)數(shù)據(jù)的記錄數(shù)*@paramfs*@parampath*@return*@throwsException*/publicstaticintgetSize(FileSystemfs,Pathpath)throwsException{ intcount=0; FSDataInputStreamis=fs.open(path); BufferedReaderbr=newBufferedReader(newInputStreamReader(is)); Stringline=""; while((line=br.readLine())!=null){ count++; } }.......省略......

劃分?jǐn)?shù)據(jù)集設(shè)置訓(xùn)練數(shù)據(jù)集的存儲(chǔ)路徑為/movie/trainData,驗(yàn)證數(shù)據(jù)集的存儲(chǔ)路徑為/movie/validateData,測試數(shù)據(jù)集的存儲(chǔ)路徑為/movie/testData,在main函數(shù)里面讀取原始數(shù)據(jù),將讀取到的數(shù)據(jù)分別寫入到/movie/trainData,/movie/validateData及/movie/testData。實(shí)現(xiàn)代碼如代碼3-11所示。代碼3-10讀取HDFS的數(shù)據(jù)并統(tǒng)計(jì)記錄數(shù)的方法publicstaticvoidmain(String[]args)throwsException{ Configurationconf=newConfiguration(); conf.set("fs.defaultFS","master:8020"); FileSystemfs=FileSystem.get(conf); //獲取預(yù)處理之后的電影數(shù)據(jù)路徑 Pathmoviedata=newPath("/movie/processing_out/part-m-00000"); //得到電影數(shù)據(jù)大小 intdatasize=getSize(fs,moviedata); //得到train數(shù)據(jù)對(duì)應(yīng)原始數(shù)據(jù)下標(biāo) Set<Integer>train_index=trainIndex(datasize); //得到validate數(shù)據(jù)對(duì)應(yīng)原始數(shù)據(jù)的下標(biāo) Set<Integer>validate_index=validateIndex(datasize,train_index);.......省略......劃分?jǐn)?shù)據(jù)集在SplitData.java界面上單擊右鍵選擇“Run'SplitData.main()'”,運(yùn)行成功后,在HDFSWebUI查看文件/movie/trainData,/movie/validateData及/movie/testData,得到的訓(xùn)練數(shù)據(jù)集如圖

3-36所示圖3-36訓(xùn)練數(shù)據(jù)集劃分?jǐn)?shù)據(jù)集測試數(shù)據(jù)集如圖3-37所示,驗(yàn)證測試集如圖3-38所示。圖3-37測試數(shù)據(jù)集圖3-38驗(yàn)證測試集3.2.5實(shí)現(xiàn)用戶性別聚類實(shí)現(xiàn)用戶性別聚類在src/main目錄下創(chuàng)建KNN文件夾并激活,在KNN文件夾下創(chuàng)建名為k_demo的Package用于實(shí)現(xiàn)用戶性別聚類。MapReduce編程實(shí)現(xiàn)M電影網(wǎng)站用戶聚類的思路如圖3-39所示,實(shí)現(xiàn)思路描述如下。圖3-39MapReduce實(shí)現(xiàn)KNN算法思路實(shí)現(xiàn)用戶性別聚類(1)自定義值類型表示距離和類型,由于KNN算法是計(jì)算測試數(shù)據(jù)與已知類別的訓(xùn)練數(shù)據(jù)之間的距離,找到距離與測試數(shù)據(jù)最近的K個(gè)訓(xùn)練數(shù)據(jù),再根據(jù)這些訓(xùn)練所屬的類別的眾數(shù)來判斷測試數(shù)據(jù)的類別。所以在Map階段需要將測試數(shù)據(jù)與訓(xùn)練數(shù)據(jù)的距離及該訓(xùn)練數(shù)據(jù)的類別作為值輸出,程序可以使用Hadoop內(nèi)置的數(shù)據(jù)類型Text作為值類型輸出距離及類別,但為了提高程序的執(zhí)行效率,建議自定義值類型表示距離和類別。(2)Map階段,setup函數(shù)讀取測試數(shù)據(jù)。在map函數(shù)里讀取每條訓(xùn)練數(shù)據(jù),遍歷測試數(shù)據(jù),計(jì)算讀取進(jìn)來的訓(xùn)練記錄與每條測試數(shù)據(jù)的距離,計(jì)算距離采用的是歐式距離的計(jì)算方法,Map輸出的鍵是每條測試數(shù)據(jù),輸出的值是該測試數(shù)據(jù)與讀取的訓(xùn)練數(shù)據(jù)的距離和訓(xùn)練數(shù)據(jù)的類別。(3)Reduce階段,setup函數(shù)初始化參數(shù)K值,reduce函數(shù)對(duì)相同鍵的值根據(jù)距離進(jìn)行升序排序,取出前K個(gè)值,輸出reduce函數(shù)讀取進(jìn)來的鍵和這K個(gè)值中類別的眾數(shù)。根據(jù)上述的思路分析,可知Map階段輸出的值是距離和類別的組合,為了提高程序的執(zhí)行效率,筆者不建議使用Hadoop內(nèi)置的Text類型作為輸出的值類型,而是自定義一個(gè)值類型表示距離和類別。筆者自定義了一個(gè)值類型DistanceAndLabel類,該類實(shí)現(xiàn)Writable接口,根據(jù)需求定義聲明兩個(gè)對(duì)象,一個(gè)double類型的distance對(duì)象表示距離,一個(gè)String類型的label對(duì)象表示類別。同時(shí)需要注意寫入和讀取的順序,這里先把distance寫入out輸出流,然后再把label寫入out輸出流。那么在讀取的時(shí)候就需要先讀取distance,接著再讀取label。最后還需要重寫toString的方法,將距離distance和類別label用逗號(hào)連接起來(分隔符可以自己指定),具體實(shí)現(xiàn)代碼如代碼3-12所示。實(shí)現(xiàn)用戶性別聚類代碼3-12自定義值類型重要部分publicclassDistanceAndLabelimplementsWritable{ privatedoubledistance; privateStringlabel; publicDistanceAndLabel(){ } publicDistanceAndLabel(doubledistance,Stringlabel){ this.distance=distance; this.label=label; } publicdoublegetDistance(){ returndistance; } publicvoidsetDistance(doubledistance){ this.distance=distance; }......省略實(shí)現(xiàn)用戶性別聚類在Map階段,setup函數(shù)讀取測試數(shù)據(jù),map函數(shù)讀取訓(xùn)練數(shù)據(jù),計(jì)算訓(xùn)練數(shù)據(jù)與測試數(shù)據(jù)的距離,輸出測試數(shù)據(jù),以及測試數(shù)據(jù)與訓(xùn)練數(shù)據(jù)的距離和訓(xùn)練數(shù)據(jù)的類別。假設(shè)訓(xùn)練數(shù)據(jù)為(1,1,1,10,48067,0,2,6,18,0,14,0,0,5,5,2,3,20,3,14,3,21,0),測試數(shù)據(jù)如表3-4所示,計(jì)算訓(xùn)練數(shù)據(jù)與每天測試數(shù)據(jù)的距離,Map端輸出的結(jié)果如表3-5所示,從表中可以看出,Map每讀取一條訓(xùn)練數(shù)據(jù),結(jié)果輸出的鍵值對(duì)個(gè)數(shù)是測試數(shù)據(jù)集的記錄數(shù)。假設(shè)有n條訓(xùn)練數(shù)據(jù),m條測試數(shù)據(jù),則最終Map輸出的鍵值對(duì)個(gè)數(shù)是n*m。在Mapper類里面,需要定義一個(gè)計(jì)算距離的方法calDistance(String[]test,String[]train),具體實(shí)現(xiàn)代碼如代碼3-13所示。表3-4測試數(shù)據(jù)示例5892,0,45,2,10920,4,6,12,2,7,29,7,1,19,14,12,4,5,40,4,27,49,25893,0,25,7,02139,0,9,33,4,3,144,5,0,8,8,4,3,3,8,6,6,47,25894,0,35,0,70748,0,19,8,0,1,24,1,32,75,22,9,2,3,18,1,24,36,05895,0,25,1,43026,3,38,4,0,3,17,6,1,11,0,0,0,0,3,1,22,27,0表3-5Map輸出結(jié)果key:(5892,0,45,2,10920,4,6,12,2,7,29,7,1,19,14,12,4,5,40,4,27,49,2)value:(2.48,1)key:(5893,0,25,7,02139,0,9,33,4,3,144,5,0,8,8,4,3,3,8,6,6,47,2)value:(3.32,1)key:(5894,0,35,0,70748,0,19,8,0,1,24,1,32,75,22,9,2,3,18,1,24,36,0)value:(1.63,1)key:(5895,0,25,1,43026,3,38,4,0,3,17,6,1,11,0,0,0,0,3,1,22,27,0)value:(7.08,1)實(shí)現(xiàn)用戶性別聚類代碼3-13Mapper類實(shí)現(xiàn)publicclassMovieClassifyMapperextendsMapper<LongWritable,Text,Text,DistanceAndLabel>{ privateDistanceAndLabeldistance_label=newDistanceAndLabel(); privateStringsplitter=""; ArrayList<String>testData=newArrayList<String>(); privateStringtestPath=""; @Override protectedvoidsetup(Mapper<LongWritable,Text,Text,DistanceAndLabel>.Contextcontext) throwsIOException,InterruptedException{ Configurationconf=context.getConfiguration(); splitter=conf.get("SPLITTER"); testPath=conf.get("TESTPATH"); //讀取測試數(shù)據(jù)存于列表testData中 FileSystemfs=FileSystem.get(conf); FSDataInputStreamis=fs.open(newPath(testPath)); BufferedReaderbr=newBufferedReader(newInputStreamReader(is)); Stringline="";......省略實(shí)現(xiàn)用戶性別聚類在Reduce階段,setup函數(shù)初始化K值,reduce函數(shù)針對(duì)相同的key,對(duì)其值根據(jù)距離進(jìn)行升序排序,取出前K個(gè)值,并找到這K個(gè)值類別的眾數(shù),輸出key和類別的眾數(shù)。例如,假設(shè)reduce接收到的鍵值對(duì)為<(5892,0,45,2,10920,4,6,12,2,7,29,7,1,19,14,12,4,5,40,4,27,49,2),[(2.48,1),(3.80,1),(6.53,0),(4.21,0)]>,對(duì)其值根據(jù)距離升序排序,則得到列表[(2.48,1),(3.80,1),(4.21,0),(6.53,0)],設(shè)置參數(shù)k為3,取出列表的前3個(gè)值,得到列表[(2.48,1),(3.80,1),(4.21,0)],這三個(gè)值中,類別1出現(xiàn)了2次,類別0出現(xiàn)了1次,即類別眾數(shù)為1,所以reduce輸出<1,(5892,0,45,2,10920,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論