Hadoop编程基于MR程序实现倒排索引示例
程序员文章站
2022-07-09 13:16:16
相信接触过搜索引擎开发的同学对倒排索引并不陌生,谷歌、百度等搜索引擎都是用的倒排索引,关于倒排索引的有关知识,这里就不再深入讲解,有兴趣的同学到网上了解一下。这篇博文就带着...
相信接触过搜索引擎开发的同学对倒排索引并不陌生,谷歌、百度等搜索引擎都是用的倒排索引,关于倒排索引的有关知识,这里就不再深入讲解,有兴趣的同学到网上了解一下。这篇博文就带着大家一起学习下如何利用hadoop的mr程序来实现倒排索引的功能。
一、数据准备
1、输入文件数据
这里我们准备三个输入文件,分别如下所示
a.txt
hello tom hello jerry hello tom
b.txt
hello jerry hello jerry tom jerry
c.txt
hello jerry hello tom
2、最终输出文件数据
最终输出文件的结果为:
[plain] view plain copy hello c.txt-->2 b.txt-->2 a.txt-->3 jerry c.txt-->1 b.txt-->3 a.txt-->1 tom c.txt-->1 b.txt-->1 a.txt-->2
二、倒排索引过程分析
根据输入文件数据和最终的输出文件结果可知,此程序需要利用两个mr实现,具体流程可总结归纳如下:
-------------第一步mapper的输出结果格式如下:-------------------- context.wirte("hello->a.txt", "1") context.wirte("hello->a.txt", "1") context.wirte("hello->a.txt", "1") context.wirte("hello->b.txt", "1") context.wirte("hello->b.txt", "1") context.wirte("hello->c.txt", "1") context.wirte("hello->c.txt", "1") -------------第一步reducer的得到的输入数据格式如下:------------- <"hello->a.txt", {1,1,1}> <"hello->b.txt", {1,1}> <"hello->c.txt", {1,1}> -------------第一步reducer的输出数据格式如下--------------------- context.write("hello->a.txt", "3") context.write("hello->b.txt", "2") context.write("hello->c.txt", "2") -------------第二步mapper得到的输入数据格式如下:----------------- context.write("hello->a.txt", "3") context.write("hello->b.txt", "2") context.write("hello->c.txt", "2") -------------第二步mapper输出的数据格式如下:-------------------- context.write("hello", "a.txt->3") context.write("hello", "b.txt->2") context.write("hello", "c.txt->2") -------------第二步reducer得到的输入数据格式如下:----------------- <"hello", {"a.txt->3", "b.txt->2", "c.txt->2"}> -------------第二步reducer输出的数据格式如下:----------------- context.write("hello", "a.txt->3 b.txt->2 c.txt->2") 最终结果为: hello a.txt->3 b.txt->2 c.txt->2
三、程序开发
3.1、第一步mr程序与输入输出
package com.lyz.hdfs.mr.ii; import java.io.ioexception; import org.apache.commons.lang.stringutils; 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; /** * 倒排索引第一步map reduce程序,此处程序将所有的map/reduce/runner程序放在一个类中 * @author liuyazhuang * */ public class inverseindexstepone { /** * 完成倒排索引第一步的mapper程序 * @author liuyazhuang * */ public static class steponemapper extends mapper<longwritable, text, text, longwritable>{ @override protected void map(longwritable key, text value, mapper<longwritable, text, text, longwritable>.context context) throws ioexception, interruptedexception { //获取一行数据 string line = value.tostring(); //切分出每个单词 string[] fields = stringutils.split(line, " "); //获取数据的切片信息 filesplit filesplit = (filesplit) context.getinputsplit(); //根据切片信息获取文件名称 string filename = filesplit.getpath().getname(); for(string field : fields){ context.write(new text(field + "-->" + filename), new longwritable(1)); } } } /** * 完成倒排索引第一步的reducer程序 * 最终输出结果为: * hello-->a.txt 3 hello-->b.txt 2 hello-->c.txt 2 jerry-->a.txt 1 jerry-->b.txt 3 jerry-->c.txt 1 tom-->a.txt 2 tom-->b.txt 1 tom-->c.txt 1 * @author liuyazhuang * */ public static class steponereducer extends reducer<text, longwritable, text, longwritable>{ @override protected void reduce(text key, iterable<longwritable> values, reducer<text, longwritable, text, longwritable>.context context) throws ioexception, interruptedexception { long counter = 0; for(longwritable value : values){ counter += value.get(); } context.write(key, new longwritable(counter)); } } //运行第一步的mr程序 public static void main(string[] args) throws exception{ configuration conf = new configuration(); job job = job.getinstance(conf); job.setjarbyclass(inverseindexstepone.class); job.setmapperclass(steponemapper.class); job.setreducerclass(steponereducer.class); job.setmapoutputkeyclass(text.class); job.setmapoutputvalueclass(longwritable.class); job.setoutputkeyclass(text.class); job.setoutputvalueclass(longwritable.class); fileinputformat.addinputpath(job, new path("d:/hadoop_data/ii")); fileoutputformat.setoutputpath(job, new path("d:/hadoop_data/ii/result")); job.waitforcompletion(true); } }
3.1.1 输入数据
a.txt
hello tom hello jerry hello tom
b.txt
hello jerry hello jerry tom jerry
c.txt
hello jerry hello tom
3.1.2
输出结果:
hello-->a.txt 3 hello-->b.txt 2 hello-->c.txt 2 jerry-->a.txt 1 jerry-->b.txt 3 jerry-->c.txt 1 tom-->a.txt 2 tom-->b.txt 1 tom-->c.txt 1
3.2 第二步mr程序与输入输出
package com.lyz.hdfs.mr.ii; import java.io.ioexception; import org.apache.commons.lang.stringutils; 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.output.fileoutputformat; /** * 倒排索引第二步map reduce程序,此处程序将所有的map/reduce/runner程序放在一个类中 * @author liuyazhuang * */ public class inverseindexsteptwo { /** * 完成倒排索引第二步的mapper程序 * * 从第一步mr程序中得到的输入信息为: * hello-->a.txt 3 hello-->b.txt 2 hello-->c.txt 2 jerry-->a.txt 1 jerry-->b.txt 3 jerry-->c.txt 1 tom-->a.txt 2 tom-->b.txt 1 tom-->c.txt 1 * @author liuyazhuang * */ public static class steptwomapper extends mapper<longwritable, text, text, text>{ @override protected void map(longwritable key, text value, mapper<longwritable, text, text, text>.context context) throws ioexception, interruptedexception { string line = value.tostring(); string[] fields = stringutils.split(line, "\t"); string[] wordandfilename = stringutils.split(fields[0], "-->"); string word = wordandfilename[0]; string filename = wordandfilename[1]; long counter = long.parselong(fields[1]); context.write(new text(word), new text(filename + "-->" + counter)); } } /** * 完成倒排索引第二步的reducer程序 * 得到的输入信息格式为: * <"hello", {"a.txt->3", "b.txt->2", "c.txt->2"}>, * 最终输出结果如下: * hello c.txt-->2 b.txt-->2 a.txt-->3 jerry c.txt-->1 b.txt-->3 a.txt-->1 tom c.txt-->1 b.txt-->1 a.txt-->2 * @author liuyazhuang * */ public static class steptworeducer extends reducer<text, text, text, text>{ @override protected void reduce(text key, iterable<text> values, reducer<text, text, text, text>.context context) throws ioexception, interruptedexception { string result = ""; for(text value : values){ result += value + " "; } context.write(key, new text(result)); } } //运行第一步的mr程序 public static void main(string[] args) throws exception{ configuration conf = new configuration(); job job = job.getinstance(conf); job.setjarbyclass(inverseindexsteptwo.class); job.setmapperclass(steptwomapper.class); job.setreducerclass(steptworeducer.class); job.setmapoutputkeyclass(text.class); job.setmapoutputvalueclass(text.class); job.setoutputkeyclass(text.class); job.setoutputvalueclass(text.class); fileinputformat.addinputpath(job, new path("d:/hadoop_data/ii/result/part-r-00000")); fileoutputformat.setoutputpath(job, new path("d:/hadoop_data/ii/result/final")); job.waitforcompletion(true); } }
3.2.1 输入数据
hello-->a.txt 3 hello-->b.txt 2 hello-->c.txt 2 jerry-->a.txt 1 jerry-->b.txt 3 jerry-->c.txt 1 tom-->a.txt 2 tom-->b.txt 1 tom-->c.txt 1
3.2.2 输出结果
hello c.txt-->2 b.txt-->2 a.txt-->3 jerry c.txt-->1 b.txt-->3 a.txt-->1 tom c.txt-->1 b.txt-->1 a.txt-->2
总结
以上就是本文关于hadoop编程基于mr程序实现倒排索引示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:hadoop对文本文件的快速全局排序实现方法及分析、hadoop重新格式化hdfs步骤解析、浅谈七种常见的hadoop和spark项目案例等,有什么问题可以直接留言,小编会及时回复大家的。感谢朋友们对本站的支持!