倒排索引和利用PageRank算法进行网页排序

第三章 倒排索引

前面通过词频统计,已经可以找出高频率的“关键词”了,这些词汇出现的频率很高以至于很难直接对其所在的文档进行查找。必须借助一定的关系模型表示单词与文本的关系,然后才可以实现快速搜索查找。

在这里插入图片描述

单词-文档矩阵是表达这种包含关系的最简洁的概念模型。每列代表文档包含了哪些单词,比如文档1包含了词汇1和词汇4,而不包含其它单词。每行代表了哪些文档包含了某个单词。比如对于词汇1来说,文档1和文档4中出现过单词1,而其它文档不包含词汇1。

搜索引擎的索引其实就是实现“单词-文档矩阵”的具体数据结构。可以有不同的方式来实现上述概念模型,比如“倒排索引”、“签名文件”、“后缀树”等方式。但是各项实验数据表明,“倒排索引”是实现单词到文档映射关系的最佳实现方式

本关任务

要求:编写处理带词频属性的文档倒排索引程序,运行程序,对莎士比亚文集文档数据进行倒排索引处理,结果输出到指定文件。

注:输入输出文件的路径已经指定,

相关知识

文本特征

文档(Document):一般搜索引擎的处理对象是互联网网页,而文档这个概念要更宽泛些,代表以文本形式存在的存储对象,相比网页来说,涵盖更多种形式,比如Word,PDF,html,XML等不同格式的文件都可以称之为文档。再在本关后续内容,很多情况下会使用文档来表征文本信息。
文档集合(Document Collection):由若干文档构成的集合称之为文档集合。
文档编号(Document ID):在搜索引擎内部,会将文档集合内每个文档赋予一个唯一的内部编号,以此编号来作为这个文档的唯一标识,这样方便内部处理,每个文档的内部编号即称之为“文档编号”,后文有时会用DocID来便捷地代表文档编号。
单词编号(Word ID):与文档编号类似,搜索引擎内部以唯一的编号来表征某个单词,单词编号可以作为某个单词的唯一表征。

倒排索引

在这里插入图片描述

倒排索引(Inverted Index):倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。
单词词典(Lexicon):搜索引擎的通常索引单位是单词,单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针。
倒排列表(PostingList):倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词。
倒排文件(Inverted File):所有单词的倒排列表往往顺序地存储在磁盘的某个文件里,这个文件即被称之为倒排文件,倒排文件是存储倒排索引的物理文件。

编程要求

本关的编程任务是补全右侧代码片段中map和reduce函数中的代码,具体要求及说明如下:

在主函数main中已初始化hadoop的系统设置,包括hadoop运行环境的连接。
在main函数中,已经设置好了待处理文档路径(即input),以及结果输出路径(即output)。
在main函数中,已经声明了job对象,程序运行的工作调度已经设定好。
本关只要求在map和reduce函数的指定区域进行代码编写,其他区域请勿改动。

测试说明

测试输入样例数据集:文本文档test1.txt, test2.txt

文档test1.txt中的内容为:

 tale as old as time
   true as it can be
   beauty and the beast

文档test2.txt中的内容为:

ever just the same
   ever as before
   beauty and the beast

预期输出文件result.txt的内容为:
在这里插入图片描述

注:由于启动服务、编译等耗时,以及MapReduce过程资源消耗较大且时间较长,因而单个用户使用资源有限,评测时间较长(30s左右)!
请耐心等待!相信自己!通往成功的路上不会太久!

工欲善其事必先利其器!要想实现海量数据搜索,必须先得到文档倒排索引

开始你的任务吧,祝你成功!

如果你觉得这一关的内容对你有帮助,请你在下面点赞。

注释

import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;

import java.util.Iterator;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.util.GenericOptionsParser;

public class InvertedIndex {
	public static class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text> 
	{
		public void map(LongWritable key, Text value, Context context)  
				throws IOException, InterruptedException 
		 
		{	
			FileSplit fileSplit = (FileSplit)context.getInputSplit();
			String fileName = fileSplit.getPath().getName();
			
			String word;
			IntWritable frequence=new IntWritable();
			int one=1;
			Hashtable<String,Integer>	hashmap=new Hashtable();//key关键字设置为String
			StringTokenizer itr = new StringTokenizer(value.toString());
			
//****请用hashmap定义的方法统计每一行中相同单词的个数,key为行值是每一行对应的偏移****//
/*********begin*********/

 for(;itr.hasMoreTokens(); ) 
            {   
                word=itr.nextToken();
                if(hashmap.containsKey(word)){
                    hashmap.put(word,hashmap.get(word)+1);
                }else{
                    hashmap.put(word, one);
                }
            }




/*********end**********/			
							

			for(Iterator<String> it=hashmap.keySet().iterator();it.hasNext();){
				word=it.next();
				frequence=new IntWritable(hashmap.get(word));
				Text fileName_frequence = new Text(fileName+"@"+frequence.toString());//以<K2,“单词 文件名@出现频次”> 的格式输出
				context.write(new Text(word),fileName_frequence);
			}
			
		}
	}

	public static class InvertedIndexCombiner extends Reducer<Text,Text,Text,Text>{
		protected void reduce(Text key,Iterable<Text> values,Context context)
						throws IOException ,InterruptedException{ 
//****请合并mapper函数的输出,并提取“文件@1”中‘@’后面的词频,以<K2,list(“单词 文件名@出现频次”)>的格式输出****//
/*********begin*********/
 String fileName="";
            int sum=0;
            String num;
            String s;
            for (Text val : values) {
                    s= val.toString();
                    fileName=s.substring(0, val.find("@"));
                    num=s.substring(val.find("@")+1, val.getLength());
                    sum+=Integer.parseInt(num);
            }
        IntWritable frequence=new IntWritable(sum);
        context.write(key,new Text(fileName+"@"+frequence.toString()));





/*********end**********/				

		}
	}
	
	public static class InvertedIndexReducer extends Reducer<Text, Text, Text, Text> 
	{	@Override
		protected void reduce(Text key, Iterable<Text> values, Context context)
				throws IOException, InterruptedException 
	 	{	Iterator<Text> it = values.iterator();
			StringBuilder all = new StringBuilder();
			if(it.hasNext())  all.append(it.next().toString());
			for(;it.hasNext();) {
				all.append(";");
				all.append(it.next().toString());					
			}
//****请输出最终键值对list(K3,“单词", “文件1@频次; 文件2@频次;...")****//
/*********begin*********/

            context.write(key, new Text(all.toString()));



/*********end**********/		
		}
	}

	public static void main(String[] args) 
    {
		if(args.length!=2){
			System.err.println("Usage: InvertedIndex <in> <out>");
			System.exit(2);
		}
		
      try {
		        Configuration conf = new Configuration();
		        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
		        
		        Job job = new Job(conf, "invertedindex");
				job.setJarByClass(InvertedIndex.class);
				job.setMapperClass(InvertedIndexMapper.class);
			//****请为job设置Combiner类****//
/*********begin*********/
                job.setCombinerClass(InvertedIndexCombiner.class);
/*********end**********/								
				job.setReducerClass(InvertedIndexReducer.class);
				
				job.setOutputKeyClass(Text.class);
			//****请设置输出value的类型****//
/*********begin*********/
                job.setOutputValueClass(Text.class);
/*********end**********/									
				FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
				FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
				
				System.exit(job.waitForCompletion(true) ? 0 : 1);
	 
        } catch (Exception e) { 
        	e.printStackTrace();
        }
    }
}

第四章 网页排序——PageRank算法

前面我们关注了文本中词频的统计筛选出了文本中的高频词汇,也通过倒排索引建立了关键词和文本集间的索引关系。接下来从宏观地关注文本间的关系。文本间的引用最具代表性,比如网页的相互链接。显而易见某些文本(网页)被引用(链接)次数多更加重要,在面对海量的文本时可以以此对文本重要性进行排序,尽快地找到有用信息。

本关任务

要求:编写实现网页数据集PageRank算法的程序,对网页数据集进行处理得到网页权重排序。

相关知识
PageRank算法原理

1.基本思想:
如果网页T存在一个指向网页A的连接,则表明T的所有者认为A比较重要,从而把T的一部分重要性得分赋予A。这个重要性得分值为:PR(T)/L(T)

其中PR(T)为T的PageRank值,L(T)为T的出链数。则A的PageRank值为一系列类似于T的页面重要性得分值的累加。

即一个页面的得票数由所有链向它的页面的重要性来决定,到一个页面的超链接相当于对该页投一票。一个页面的PageRank是由所有链向它的页面(链入页面)的重要性经过递归算法得到的。一个有较多链入的页面会有较高的等级,相反如果一个页面没有任何链入页面,那么它没有等级。
在这里插入图片描述

2.PageRank简单计算:
假设一个由只有4个页面组成的集合:A,B,C和D。如图所示,如果所有页面都链向A,那么A的PR(PageRank)值将是B,C及D的和。

在这里插入图片描述

继续假设B也有链接到C,并且D也有链接到包括A的3个页面。一个页面不能投票2次。所以B给每个页面半票。以同样的逻辑,D投出的票只有三分之一算到了A的PageRank上。

在这里插入图片描述

换句话说,根据链出总数平分一个页面的PR值。

在这里插入图片描述

完整PageRank计算公式

由于存在一些出链为0不链接任何其他网页的网页,因此需要对 PageRank公式进行修正,即在简单公式的基础上增加了阻尼系数(damping factor)q, q一般取值q=0.85

在这里插入图片描述

P1,P2,…,Pn是被研究的页面,M(Pi)是Pi链入页面的数量,L(Pj)是Pj链出页面的数量,而N是所有页面的数量。PageRank值是一个特殊矩阵中的特征向量。这个特征向量为:

在这里插入图片描述

PageRank计算过程

在这里插入图片描述

幂法计算过程如下:
X 设任意一个初始向量, 即设置初始每个网页的 PageRank值均。一般为1。R = AX。

   while  (1){
        if ( |X - R| < e) 
             return R;  //如果最后两次的结果近似或者相同,返回R
        else   {
                X =R;
               R = AX;
               }
    }

MapReduce计算PageRank

上面的演算过程,采用矩阵相乘,不断迭代,直到迭代前后概率分布向量的值变化不大,一般迭代到30次以上就收敛了。真的的web结构的转移矩阵非常大,目前的网页数量已经超过100亿,转移矩阵是100亿*100亿的矩阵,直接按矩阵乘法的计算方法不可行,需要借助Map-Reduce的计算方式来解决

对于如下图所示的相互链接网页关系
在这里插入图片描述

可以利用转移矩阵进行表示。转移矩阵是一个多维的稀疏矩阵,把web图中的每一个网页及其链出的网页作为一行,这样第四节中的web图结构用如下方式表示:

1. A   B    C    D
2. B   A    D
3. C   C
4. D   B    C

可以看A有三条出链,分布指向A、B、C,实际上爬取的网页结构数据就是这样的。
1.Map阶段
Map操作的每一行,对所有出链发射当前网页概率值的1/k,k是当前网页的出链数,比如对第一行输出<B,1/31/4>,<C,1/31/4>,<D,1/31/4>;
2、Reduce阶段
Reduce操作收集网页id相同的值,累加并按权重计算,pj=a
(p1+p2+…Pm)+(1-a)*1/n,其中m是指向网页j的网页j数,n所有网页数。
思路就是这么简单,但是实践的时候,怎样在Map阶段知道当前行网页的概率值,需要一个单独的文件专门保存上一轮的概率分布值,先进行一次排序,让出链行与概率值按网页id出现在同一Mapper里面,整个流程如下:
在这里插入图片描述

这样进行一次迭代相当于需要两次MapReduce,但第一次的MapReduce只是简单的排序,不需要任何操作,用java调用Hadoop的Streaming.

编程要求

本关的编程任务是补全右侧代码片段中map和reduce函数中的代码,具体要求及说明如下:

在主函数main中已初始化hadoop的系统设置,包括hadoop运行环境的连接。
在main函数中,已经设置好了待处理文档路径(即input),在评测中设置了结果输出路径(即output),不要修改循环输出路径即可保证完成。
在main函数中,已经声明了job对象,程序运行的工作调度已经设定好。
原则上循环迭代次数越多越精准,但是为了保证平台资源,只允许运行5次迭代,多余过程被忽略无法展示,请勿增加循环次数。
本关只要求在map和reduce函数的指定区域进行代码编写,其他区域请勿改动。

测试说明
输入文件格式如下:

1    1.0 2 3 4 5 6 7 8
2    2.0 3 4 5 6 7 8
3    3.0 4 5 6 7 8
4    4.0 5 6 7 8
5    5.0 6 7 8
6    6.0 7 8
7    7.0 8
8    8.0 1 2 3 4 5 6 7

注:为了简化运算,已经对网页集关系进行了规整,并且给出了相应的初始PR值。
以第一行为例: 1表示网址(以tab键隔开),1.0为给予的初始pr值,2,3,4,5,6,7,8为从网址1指向的网址。
输出文件格式:

The origin result
1    1.0 2 3 4 5 6 7 8
2    2.0 3 4 5 6 7 8
3    3.0 4 5 6 7 8
4    4.0 5 6 7 8
5    5.0 6 7 8
6    6.0 7 8
7    7.0 8
8    8.0 1 2 3 4 5 6 7
The 1th result
1    0.150 1.121 _2 3 4 5 6 7 8 
2    0.150 1.243 _3 4 5 6 7 8 
3    0.150 1.526 _4 5 6 7 8 
4    0.150 2.036 _5 6 7 8 
5    0.150 2.886 _6 7 8 
6    0.150 4.303 _7 8 
7    0.150 6.853 _8 
8    0.150 11.831 _1 2 3 4 5 6 7 
The 2th result
1    0.150 1.587 _2 3 4 5 6 7 8 
2    0.150 1.723 _3 4 5 6 7 8 
3    0.150 1.899 _4 5 6 7 8 
4    0.150 2.158 _5 6 7 8 
5    0.150 2.591 _6 7 8 
6    0.150 3.409 _7 8 
7    0.150 5.237 _8 
8    0.150 9.626 _1 2 3 4 5 6 7 
The 3th result
1    0.150 1.319 _2 3 4 5 6 7 8 
2    0.150 1.512 _3 4 5 6 7 8 
3    0.150 1.756 _4 5 6 7 8 
4    0.150 2.079 _5 6 7 8 
5    0.150 2.537 _6 7 8 
6    0.150 3.271 _7 8 
7    0.150 4.720 _8 
8    0.150 8.003 _1 2 3 4 5 6 7 
The 4th result
1    0.150 1.122 _2 3 4 5 6 7 8 
2    0.150 1.282 _3 4 5 6 7 8 
3    0.150 1.496 _4 5 6 7 8 
4    0.150 1.795 _5 6 7 8 
5    0.150 2.236 _6 7 8 
6    0.150 2.955 _7 8 
7    0.150 4.345 _8 
8    0.150 7.386 _1 2 3 4 5 6 7 
The 5th result
1    0.150 1.047 _2 3 4 5 6 7 8 
2    0.150 1.183 _3 4 5 6 7 8 
3    0.150 1.365 _4 5 6 7 8 
4    0.150 1.619 _5 6 7 8 
5    0.150 2.000 _6 7 8 
6    0.150 2.634 _7 8 
7    0.150 3.890 _8 
8    0.150 6.686 _1 2 3 4 5 6 7 

注:迭代方法和次数不同会对结果产生影响,不必完全与答案匹配,只需运行结果趋于合理即可。(第二列为多余值)

注:由于启动服务、编译、循环迭代等耗时,以及单次MapReduce过程资源消耗较大且时间较长,因而单个用户使用资源有限,评测时间较长(40s左右)!
请耐心等待!相信自己!通往成功的路上不会太久!

慧眼识珍发现有用的文本信息,请先从网页排序分析开始!

开始你的任务吧,祝你成功!

如果你觉得这一关的内容对你有帮助,请你在下面点赞。

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.StringTokenizer;
import java.util.Iterator;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class PageRank {

  public static class MyMapper   extends Mapper<Object, Text, Text, Text>
  {
	  	private Text id = new Text();
  	 	public void map(Object key, Text value, Context context ) throws IOException, InterruptedException
  	 	{
  	 		String line = value.toString();
//判断是否为输入文件
  	 		if(line.substring(0,1).matches("[0-9]{1}"))
  	 		{
				  boolean flag = false;
				  if(line.contains("_"))
				  {
						line = line.replace("_","");
						flag = true;
				  }
//对输入文件进行处理
				  String[] values = line.split("\t");
				  Text t = new Text(values[0]);
				  String[] vals = values[1].split(" ");
				  String url="_";//保存url,用作下次计算
				  double pr = 0;
				  int i = 0;
				  int num = 0;
				  
				  if(flag)
				  {
					  i=2;
					  pr=Double.valueOf(vals[1]);
					  num=vals.length-2;
				  }
				  else
				  {
					  i=1;
					  pr=Double.valueOf(vals[0]);
					  num=vals.length-1;
				  }
				  
				  for(;i<vals.length;i++)
				  {
					  url=url+vals[i]+" ";
					  id.set(vals[i]);
					  Text prt = new Text(String.valueOf(pr/num));
					  context.write(id,prt);
				  }
				  context.write(t,new Text(url));
			  }
		  }
  }

  public static class MyReducer  extends Reducer<Text,Text,Text,Text>
  {
			  private Text result = new Text();
			  private Double pr = new Double(0);
			  
		 public void reduce(Text key, Iterable<Text> values,  Context context  ) throws IOException, InterruptedException
		 {
			  double sum=0;
			  String url="";
			  
//****请通过url判断否则是外链pr,作计算前预处理****//
/*********begin*********/
   for(Text val:values)
              {
                  if(!val.toString().contains("_"))
                  {
                      sum=sum+Double.valueOf(val.toString());
                  }
                  else
                 {
                      url=val.toString();
                  }
              }


/*********end**********/			
	  
  			 
//****请补全用完整PageRank计算公式计算输出过程,q取0.85****//
/*********begin*********/
 pr=0.15+0.85*sum;
              String str=String.format("%.3f",pr);
              result.set(new Text(str+" "+url));
              context.write(key,result);



/*********end**********/	

		  }
 }

	public static void main(String[] args) throws Exception
	{
		     String paths="file:///tmp/input/Wiki0";//输入文件路径,不要改动
			String path1=paths;
			String path2="";

			for(int i=1;i<=5;i++)//迭代5次
			  {
				System.out.println("This is the "+i+"th job!");
				System.out.println("path1:"+path1);
				System.out.println("path2:"+path2);
				Configuration conf = new Configuration();
				Job job = new Job(conf, "PageRank");
				path2=paths+i;	  
				job.setJarByClass(PageRank.class);
				job.setMapperClass(MyMapper.class);
		//****请为job设置Combiner类****//
/*********begin*********/
                job.setCombinerClass(MyReducer.class);

/*********end**********/					
				job.setReducerClass(MyReducer.class);
				job.setOutputKeyClass(Text.class);
				job.setOutputValueClass(Text.class);
				FileInputFormat.addInputPath(job, new Path(path1));
 				FileOutputFormat.setOutputPath(job, new Path(path2));
				path1=path2;	  
			 job.waitForCompletion(true);
			System.out.println(i+"th end!");
		}
	  }	
 }

本文最后,给出上述内容源码

test 3
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import java.util.Iterator;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.util.GenericOptionsParser;

public class InvertedIndex {
    public static class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text> 
    {
        public void map(LongWritable key, Text value, Context context)  
                throws IOException, InterruptedException 
        {    
            FileSplit fileSplit = (FileSplit)context.getInputSplit();
            String fileName = fileSplit.getPath().getName();
            String word;
            IntWritable frequence=new IntWritable();
            int one=1;
            Hashtable<String,Integer>    hashmap=new Hashtable();
            StringTokenizer itr = new StringTokenizer(value.toString());

            for(;itr.hasMoreTokens(); ) 
            {   
                word=itr.nextToken();
                if(hashmap.containsKey(word)){
                    hashmap.put(word,hashmap.get(word)+1);
                }else{
                    hashmap.put(word, one);
                }
            }

            for(Iterator<String> it=hashmap.keySet().iterator();it.hasNext();){
                word=it.next();
                frequence=new IntWritable(hashmap.get(word));
                Text fileName_frequence = new Text(fileName+"@"+frequence.toString());    
                context.write(new Text(word),fileName_frequence);
            }
        }
    }
    public static class InvertedIndexCombiner extends Reducer<Text,Text,Text,Text>{
        protected void reduce(Text key,Iterable<Text> values,Context context)
                        throws IOException ,InterruptedException{ 
            String fileName="";
            int sum=0;
            String num;
            String s;
            for (Text val : values) {
                    s= val.toString();
                    fileName=s.substring(0, val.find("@"));
                    num=s.substring(val.find("@")+1, val.getLength());
                    sum+=Integer.parseInt(num);
            }
        IntWritable frequence=new IntWritable(sum);
        context.write(key,new Text(fileName+"@"+frequence.toString()));
        }
    }
    public static class InvertedIndexReducer extends Reducer<Text, Text, Text, Text> 
    {    @Override
        protected void reduce(Text key, Iterable<Text> values, Context context)
                throws IOException, InterruptedException 
         {    Iterator<Text> it = values.iterator();
            StringBuilder all = new StringBuilder();
            if(it.hasNext())  all.append(it.next().toString());
            for(;it.hasNext();) {
                all.append(";");
                all.append(it.next().toString());                    
            }
            context.write(key, new Text(all.toString()));
        }
    }
    public static void main(String[] args) 
    {
        if(args.length!=2){
            System.err.println("Usage: InvertedIndex <in> <out>");
            System.exit(2);
        }
      try {
                Configuration conf = new Configuration();
                String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
                Job job = new Job(conf, "invertedindex");
                job.setJarByClass(InvertedIndex.class);
                job.setMapperClass(InvertedIndexMapper.class);
                job.setCombinerClass(InvertedIndexCombiner.class);
                job.setReducerClass(InvertedIndexReducer.class);
                job.setOutputKeyClass(Text.class);
                job.setOutputValueClass(Text.class);
                FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
                FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
                System.exit(job.waitForCompletion(true) ? 0 : 1);
        } catch (Exception e) { 
            e.printStackTrace();
        }
    }
}

test 4
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.StringTokenizer;
import java.util.Iterator;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class PageRank {
  public static class MyMapper   extends Mapper<Object, Text, Text, Text>
  {
          private Text id = new Text();
           public void map(Object key, Text value, Context context ) throws IOException, InterruptedException
           {
               String line = value.toString();
               if(line.substring(0,1).matches("[0-9]{1}"))
               {
                  boolean flag = false;
                  if(line.contains("_"))
                  {
                        line = line.replace("_","");
                        flag = true;
                  }
                  String[] values = line.split("\t");
                  Text t = new Text(values[0]);
                  String[] vals = values[1].split(" ");
                  String url="_";
                  double pr = 0;
                  int i = 0;
                  int num = 0;
                  if(flag)
                  {
                      i=2;
                      pr=Double.valueOf(vals[1]);
                      num=vals.length-2;
                  }
                  else
                  {
                      i=1;
                      pr=Double.valueOf(vals[0]);
                      num=vals.length-1;
                  }
                  for(;i<vals.length;i++)
                  {
                      url=url+vals[i]+" ";
                      id.set(vals[i]);
                      Text prt = new Text(String.valueOf(pr/num));
                      context.write(id,prt);
                  }
                  context.write(t,new Text(url));
              }
          }
  }
  public static class MyReducer  extends Reducer<Text,Text,Text,Text>
  {
              private Text result = new Text();
              private Double pr = new Double(0);
         public void reduce(Text key, Iterable<Text> values,  Context context  ) throws IOException, InterruptedException
         {
              double sum=0;
              String url="";

              for(Text val:values)
              {
                  if(!val.toString().contains("_"))
                  {
                      sum=sum+Double.valueOf(val.toString());
                  }
                  else
                 {
                      url=val.toString();
                  }
              }
              pr=0.15+0.85*sum;
              String str=String.format("%.3f",pr);
              result.set(new Text(str+" "+url));
              context.write(key,result);

          }
 }
    public static void main(String[] args) throws Exception
    {
             String paths="file:///tmp/input/Wiki0";
            String path1=paths;
            String path2="";
            for(int i=1;i<=20;i++)
              {
                System.out.println("This is the "+i+"th job!");
                System.out.println("path1:"+path1);
                System.out.println("path2:"+path2);
                Configuration conf = new Configuration();
                Job job = new Job(conf, "PageRank");
                path2=paths+i;      
                job.setJarByClass(PageRank.class);
                job.setMapperClass(MyMapper.class);
                job.setCombinerClass(MyReducer.class);
                job.setReducerClass(MyReducer.class);
                job.setOutputKeyClass(Text.class);
                job.setOutputValueClass(Text.class);
                FileInputFormat.addInputPath(job, new Path(path1));
                 FileOutputFormat.setOutputPath(job, new Path(path2));
                path1=path2;      
             job.waitForCompletion(true);
            System.out.println(i+"th end!");
        }
      }    
 }
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值