倒排索引java
1.了解概念算法
"倒排索引"是文档检索系统中最经常使用的数据结构,被普遍地应用于全文搜索引擎。它主要是用来存储某个单词(或词组)在一个文档或一组文档中的存储位置的映射,即提供了一种根据内容来查找文档的方式。因为不是根据文档来肯定文档所包含的内容,而是进行相反的操做,于是称为倒排索引(Inverted Index)。数组
2.实例描述
一般状况下,倒排索引由一个单词(或词组)以及相关的文档列表组成,文档列表中的文档或者是标识文档的ID号,或者是指文档所在位置的URL。在实际应用中,还须要给每一个文档添加一个权值,用来指出每一个文档与搜索内容的相关度数据结构
3.样例输入输出app
4.算法思想框架
1)map过程搜索引擎
为统计每一个单词出如今每一个文件中的次数,将单词word做为map阶段的key值,“filename:1”做为value值。能够获得上图的结果。传到combine的格式为:MapReduce:file1.txt3d
这样作的好处是:能够利用MapReduce框架自带的Map端排序,将同一文档的相同单词的词频组成列表,传递给Combine过程,实现相似于WordCount的功能。orm
2)combine阶段blog
通过map方法处理后,Combine过程将key值相同的value值累加,获得一个单词在每一个文档中出现的次数,若是直接将图所示的输出做为Reduce过程的输入,在Shuffle过程时将面临一个问题:全部具备相同单词的记录(由word、filename和次数组成)应该交由同一个Reducer处理,但当前的key值没法保证这一点,因此必须修改key值和value值。此次将单词做为key值,filename和词频组成value值(如"file1.txt:1")。
3)reduce过程
reduce过程只需将相同key值的value值组合成倒排索引文件所需的格式便可,剩下的事情就能够直接交给MapReduce框架进行处理了。
5.代码实现
public class InvertedIndex {
static String INPUT_PATH="hdfs://master:9000/index";
static String OUTPUT_PATH="hdfs://master:9000/output/index";
static class MyMapper extends Mapper<Object,Object,Text,Text>{
private Text output_key=new Text();
private Text output_value=new Text();
String fileName=new String();
protected void setup(Context context)throws java.io.IOException,java.lang.InterruptedException{
FileSplit fs=(FileSplit)context.getInputSplit(); //获得文件的名字filename
fileName=fs.getPath().getName();
System.out.println(fileName);
}
protected void map(Object key, Object value, Context context) throws IOException, InterruptedException{
String[] tokens=value.toString().split(" "); //以空格为分隔
if(tokens!=null){
for(int i=0;i<tokens.length;i++){
output_key.set(tokens[i]+":"+fileName); //设置 key---word:filename
output_value.set("1"); //每出现一次+1
context.write(output_key, output_value);
System.out.print("1=="+output_key);
System.out.println("1=="+output_value); //1==simple:a02.txt 1== 1
}
}
}
}
static class Mycombine extends Reducer<Text,Text,Text,Text>{
Text output_key=new Text();
Text output_value=new Text();
protected void reduce(Text key,Iterable<Text> values,Context context) throws IOException,InterruptedException{
String[] tokens=key.toString().split(":"); //将word和filename以:分隔开
int sum=0;
for(Text val:values){
sum+=Integer.parseInt(val.toString()); //将单词相同的1相加
}
output_key.set(tokens[0]);
output_value.set(tokens[1]+":"+sum);
context.write(output_key, output_value); //2==mapreduce 2==a01.txt:1
System.out.print("2=="+output_key);
System.out.println("2=="+output_value);
}
}
static class MyReduce extends Reducer<Text,Text,Text,Text>{
private Text result = new Text();
protected void reduce(Text key,Iterable<Text> values,Context context) throws IOException,InterruptedException{
String fileList = new String();
for (Text value : values){ //链接filename和出现的次数
fileList += value.toString() + ";" ;
}
result.set(fileList);
context.write(key,result);
System.out.println("3=="+key);
}
}
public static void main(String[] args) throws Exception{
Path outputpath=new Path(OUTPUT_PATH);
Configuration conf=new Configuration();
FileSystem file = outputpath.getFileSystem(conf);
if(file.exists(outputpath)){
file.delete(outputpath,true);
}
Job job=Job.getInstance(conf);
FileInputFormat.setInputPaths(job, INPUT_PATH);
FileOutputFormat.setOutputPath(job,outputpath);
job.setMapperClass(MyMapper.class);
job.setReducerClass(MyReduce.class);
job.setCombinerClass(Mycombine.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.waitForCompletion(true);
}
}