hadoop(十五)—倒排序

上節(jié)課我們一起學(xué)習(xí)了Combiner的理論知識,這節(jié)課我們來一起學(xué)習(xí)一下倒排索引,那么首先我們來了解一下什么是倒排索引,如下圖所示,我們可以看到表中有單詞ID,單詞還有倒排列表,倒排列表存放的是某個單詞在第幾篇文章中出現(xiàn)的次數(shù),比如谷歌這個單詞在第一篇文章中出現(xiàn)了1次,第二篇文章中出現(xiàn)了1次,第三篇文章中出現(xiàn)了2次,第四、第五篇文章各出現(xiàn)1次。那么倒排索引的用處是什么呢?我們以搜索引擎為例,像百度、谷歌這樣大的搜索引擎商家,每天面對的數(shù)據(jù)量是百億、千億甚至更多,如此龐大的數(shù)據(jù)量,如何保證用戶搜索時的快捷高效?這就用到倒排索引了,我們知道用戶搜索東西的時候是通過輸入關(guān)鍵詞來搜索的,百度、谷歌是有自己的關(guān)鍵詞列表的,它們先通過MapReduce建立起一個倒排索引列表,每個關(guān)鍵詞在哪些文章中出現(xiàn)過以及出現(xiàn)過幾次都可以在倒排索引列表快速找到,如此一來當用戶搜索的時候便不用再去所有的文章中挨個查找了,直接便可以定位到相關(guān)的文章,這就極大的提高了查詢效率,提升客戶滿意度。

image

接下來我們一起來做個倒排索引的簡單的例子,假如我們現(xiàn)在有3個txt文件,里面存放的內(nèi)容如下圖所示,單詞與單詞之間是以一個空格分隔的。

image
       那么根據(jù)上圖的三個文件,我們想要的結(jié)果如下:

       hello  a.txt->3  b.txt->2  c.txt->2

       tom  a.txt->1  b.txt->2  c.txt->2

       jerry  a.txt->1

       kitty  a.txt->1 b.txt->1

       想要得到上面的結(jié)果,一個MapReduce無法完成,我們可以通過兩個MapReduce來完成也可以在Map和Reduce之間加一個Combiner做中間處理來完成,上節(jié)課我們剛學(xué)了Combiner的理論,這節(jié)我們便使用Combiner來處理。我們要想得到最終的結(jié)果,從正面推不好推,我們可以倒著推,我們以"hello"來推,最后一個Reducer輸出的形式是:context.write("hello","a.txt->3  b.txt->2  c.txt->2");,那么傳給Reducer的數(shù)據(jù)形式是:<"hello",{"a.txt->3","b.txt->2","c.txt->2"}>,進而我們知道m(xù)apper輸出的形式是:context.write("hello","a.txt->3");context.write("hello","b.txt->2");context.write("hello","c.txt->2");。那么第一個reducer輸出的形式便是:context.write("hello","a.txt->3");context.write("hello","b.txt->2");context.write("hello","c.txt->2");第一個mapper的輸出就應(yīng)該是context.write("hello->a.txt","1");context.write("hello->a.txt","1");context.write("hello->a.txt","1");。

        通過上面的倒推過程,我們基本上知道該怎么做了,現(xiàn)在就通過程序來實現(xiàn)。關(guān)于如何創(chuàng)建一個Maven工程并如何配置pom.xml等內(nèi)容大家可以參考:http://blog.csdn.net/u012453843/article/details/52600313這篇博客來學(xué)習(xí)。由于我們是在前面幾節(jié)課的基礎(chǔ)上學(xué)習(xí)的,我就在一個已有的sortdatacount工程下寫我們的代碼了。如下所示
image

我們只需要完成一個類ReverseIndex.java即可,現(xiàn)在我把這個類的代碼粘貼出來,如下所示

package myhadoop.mr.index;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class ReverseIndex {

public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
Job job = Job.getInstance(conf);

job.setJarByClass(ReverseIndex.class);
//將Mapper類設(shè)置到Job當中
job.setMapperClass(ReverseIndexMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job, new Path(args[0]));
//將Combiner類設(shè)置到Job當中
job.setCombinerClass(ReverseIndexCombiner.class);
//將Reducer類設(shè)置到Job當中
job.setReducerClass(ReverseIndexReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//等待執(zhí)行結(jié)束
job.waitForCompletion(true);

}

public static class ReverseIndexMapper extends       Mapper<LongWritable, Text, Text, Text>{
      private Text k=new Text();
      private Text v=new Text();
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line=value.toString();
String[] words=line.split(" ");
//我們怎么知道文件在什么位置呢?其實我們可以通過context來獲取到
FileSplit fileSplit=(FileSplit) context.getInputSplit();
//文件所在的位置
String path=fileSplit.getPath().toString();
//我們這個例子比較簡單只有3個文件,還都在同一個目錄下,path目錄是帶著hdfs路徑前綴的
//為了與我們最終的想要的結(jié)果完全一致,我們把路徑進行截取,我們    a.txt,b.txt,c.txt有個
//共同的特點就是長度都是5,因此我們只需要截取路徑最后5個字符就可以了。
String filepath=path.substring(path.length()-5);
for(String word:words){
 k.set(word+"->"+filepath);
 v.set("1");
 context.write(k, v);
}
}
}

public static class ReverseIndexCombiner extends Reducer<Text,       Text, Text, Text>{
      private Text k=new Text();
      private Text v=new Text();
@Override
protected void reduce(Text key, Iterable<Text> values,Context     context)
throws IOException, InterruptedException {
String line=key.toString();
String[] wordAndPath=line.split("->");
int sum=0;
for(Text t : values){
sum+=Integer.parseInt(t.toString());
}
k.set(wordAndPath[0]);
v.set(wordAndPath[1]+"->"+sum);
context.write(k, v);
  }
}

public static class ReverseIndexReducer extends Reducer<Text,     Text, Text, Text>{      
      private Text v=new Text();
@Override
protected void reduce(Text key, Iterable<Text> values,Context context)
throws IOException, InterruptedException {
StringBuilder builder=new StringBuilder();
for(Text t:values){
builder.append(t+"\t");
}   
v.set(builder.toString());
context.write(key, v);
}
}

}

寫完了代碼,現(xiàn)在我們導(dǎo)出這個工程,關(guān)于具體導(dǎo)出的過程大家可以參考:http://blog.csdn.net/u012453843/article/details/52600313這篇博文進行學(xué)習(xí),下面這張圖是導(dǎo)出的最后一步,我們勾選第二個復(fù)選框,JAR file我們寫上/root/reverseindex.jar,然后點擊"Finish"。

image

導(dǎo)出成功后,我們到root根目錄下看一下是否有我們剛才所取的名為reverseindex.jar,如下圖所示,發(fā)現(xiàn)確實有的。

image

在執(zhí)行這個程序之前,我們需要把數(shù)據(jù)上傳到hdfs系統(tǒng)上,首先我們先把a.txt,b.txt,c.txt從Windows系統(tǒng)上傳到虛擬機root根目錄下,可以通過Filezilla工具來上傳,如果不知道怎么使用FileZilla,大家可以參考:http://blog.csdn.net/u012453843/article/details/52422736這篇博文進行學(xué)習(xí)。上傳到root根目錄后,我們?nèi)oot根目錄查看一下是否真的已經(jīng)有了,如下圖所示,發(fā)現(xiàn)確實已經(jīng)有a.txt,b.txt,c.txt三個文件了。

image

接著我們再把這三個文件上傳到hdfs系統(tǒng)上,在上傳之前需要先檢查hdfs和yarn是否都已經(jīng)啟動起來了,如果沒有啟動的話,需要先啟動它們,關(guān)于它們的啟動大家可以參考:http://blog.csdn.net/u012453843/article/details/52433457這篇博客進行學(xué)習(xí)。當我們使用命令jps后如果可以看到NodeManager、ResourceManager、DataNode、SecondaryNameNode、NameNode說明所有的進程都正常啟動起來了。如下圖所示。

image

現(xiàn)在我們開始將a.txt,b.txt,c.txt文件上傳到hdfs系統(tǒng)根目錄下的index文件夾下,在上傳之前我們需要現(xiàn)在hdfs系統(tǒng)根目錄下新建一個index文件夾,使用命令:hadoop fs -mkdir /index

創(chuàng)建成功后,我們通過命令hadoop fs -ls /來查看一下hdfs系統(tǒng)根目錄下是否有index文件,發(fā)現(xiàn)確實是有的,然后開始上傳文件,我們?nèi)齻€文件一起上傳,使用命令:hadoop fs -put a.txt b.txt c.txt /index來實現(xiàn)上傳,上傳完后我們進入到hdfs系統(tǒng)的index目錄下,看看是否有我們剛才上傳的文件,發(fā)現(xiàn)是有的,如下圖所示。

image

準備好了一切,我們開始執(zhí)行jar,命令是:hadoop jar reverseindex.jar myhadoop.mr.index.ReverseIndex /index /reverseindex,執(zhí)行成功之后我們看看reverseindex目錄下生成了哪些文件,發(fā)現(xiàn)有兩個文件,其中part-r-00000文件便是生成的結(jié)果文件,我們使用命令:hadoop fs -cat /reverseindex/part-r-00000來查看文件的內(nèi)容,發(fā)現(xiàn)里面確實是我們想要看到的結(jié)果,如下圖所示。

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評論 6 342
  • 問過一個朋友,為什么不愛看書。回答是,上學(xué)的時候念夠了。 假期回家,到樓下的新華書店轉(zhuǎn)悠,一半都是中小學(xué)教材及輔導(dǎo)...
    邵芒閱讀 1,567評論 0 2
  • 雨,仍在下,飄絲一般,不疏不密,松散有致。比之剛才的急管繁弦,此刻的溫柔讓人心里多少寧靜了些。休息了一會,下課鈴就...
    秋水妹妹閱讀 320評論 1 1
  • 什么是字節(jié) 字節(jié)就是存儲數(shù)據(jù)的單位,并且是硬件所能訪問的最小單位。 一字節(jié)=8位 1K=1024字...
    無語_ae67閱讀 268評論 0 0

友情鏈接更多精彩內(nèi)容