美文网首页
在hadoop的map-reduce框架下实现倒排索引Inver

在hadoop的map-reduce框架下实现倒排索引Inver

作者: Mr_Relu | 来源:发表于2019-04-28 21:42 被阅读0次

编程环境:

Ubuntu16.4 uklin
Hadoop3.2.0
openjdk version "1.8.0_191"
完整代码已经更新至GitHub,欢迎fork~GitHub链接


声明:创作不易,未经授权不得复制转载
statement:No reprinting without authorization


二、在本地编写程序和调试

1、mapper设计:

输入:
<string line> ---------读入文档的每行字符串

处理过程1:
<进行token,正则化去除英文数字外的字符,转为小写,利用空格符分词> ----------得到一个个独立的英文单词

处理过程2:
<得到文档的文件名,加在每隔单词的后面结合成输出的key值(中间用特殊字符分隔),这样设计方便统计每个单词在每篇文档中的词频信息>

处理过程3:
<将每个key对应的value值设为“1”>
输出:
<<key1,1>,<key2,1>,<key3,1>...>

示例:


image.png
//倒排索引mapper类
    public static class InvertedIndexMapper extends Mapper<LongWritable, Text, Text, Text>{

        private static Text keyInfo = new Text();// 存储单词和文档名组合 eg: hello 
        private static final Text valueInfo = new Text("1");// 存储词频,初始化为1  

        @Override  
        protected void map(LongWritable key, Text value, Context context)  
                throws IOException, InterruptedException {  
                        
            String line = value.toString(); 
            
            //去除标点token操作
            line = line.replaceAll("[^a-zA-Z0-9]", " ");
            line = line.replaceAll("\\s{2,}", " ").trim();
            line = line.toLowerCase();
            String[] fields = line.split(" ");// 得到字段数组  

            FileSplit fileSplit = (FileSplit) context.getInputSplit();// 得到这行数据所在的文件切片  
            String fileName = fileSplit.getPath().getName();// 根据文件切片得到文件名  

            for (String field : fields) {
                if(field!=null){
                    // key值由单词和URL组成,如“MapReduce:file1”  
                    keyInfo.set(field + "," + fileName);  
                    context.write(keyInfo, valueInfo);  
                }               
            }  
        }  

    }

2、Combine设计

通过一个Reduce过程无法同时完成词频统计和生成文档列表,所以必须增加一个Combine过程完成词频统计
输入:
<key,valuelist<1...>> -----eg:<word+’,’+filename, <1,1,1>>

处理过程:
<根据特殊的字符将key进行拆分,将key设置为单词,并统计词频信息,将value list中的每个1相加,将文档名和词频信息组合成新的value输出,同样用特殊的字符分隔>

输出:
<newKey,newValue> --------eg:<word, filename+’,’+countNumber>

//倒排索引combiner类
    public static class InvertedIndexCombiner extends Reducer<Text, Text, Text, Text>{

        private static Text info = new Text();  

        // 输入: <MapReduce:file3 {1,1,...}>  
        // 输出:<MapReduce file3:2>  
        @Override  //伪代码,表示重写 系统可以帮你检查正确性
        protected void reduce(Text key, Iterable<Text> values, Context context)  
                throws IOException, InterruptedException {  
            int sum = 0;// 统计词频  
            for (Text value : values) {  
                sum += Integer.parseInt(value.toString());  
            }  
            
            int splitIndex = key.toString().indexOf(",");  
            // 重新设置 value 值由 URL 和词频组成  
            info.set(key.toString().substring(splitIndex + 1) + "," + sum);  
            // 重新设置 key 值为单词  
            key.set(key.toString().substring(0, splitIndex));  

            context.write(key, info);  
        }  
    }

key-value经过map和combine后的变化示例:

image.png

3、停用词处理设计

设计字符串使用config.set()进行传递,在程序map-reduce工作前设计方法,得到停用词列表存储入string sword中,而后在reducer中重载setup函数,config.get()函数取出停用词:


image.png
public static String catStopWords(Configuration conf, String remoteFilePath) {
        Path remotePath = new Path(remoteFilePath);
        //String Swords[] = new String[100];
        //ArrayList<String> strArray = new ArrayList<String> ();
        String sword = "";
        try (FileSystem fs = FileSystem.get(conf);
            FSDataInputStream in = fs.open(remotePath);
            BufferedReader d = new BufferedReader(new InputStreamReader(in));) {
            String line;
            while ((line = d.readLine()) != null) {
                
                line = line.replaceAll("[^a-zA-Z0-9]", "");
                if(line!=null)
                    sword+=line+",";
                    //strArray.add(line);                
            }
        } catch (IOException e) {
            e.printStackTrace();
        }            
        return sword;
    }

4、reducer设计:

经过combiner之后,Reduce过程只需将相同key值的value值组合成倒排索引文件所需的格式即可,利用value中的词频信息,分割相加得到total的词频数,注意对于传入的key值,如果在停用词列表中出现,则不将其输出写入context中,剩下的事情就可以直接交给MapReduce框架进行处理了。

示例输出:


image.png
//倒排索引reducer类
    public static class InvertedIndexReducer extends Reducer<Text, Text, Text, Text>{
        private static Text result = new Text();  
        private static String[] fields;
        @Override
        protected void setup(Context context)
                throws IOException, InterruptedException {
            try {
                //从全局配置获取配置参数
                Configuration conf = context.getConfiguration();
                String Str = conf.get("swords"); //这样就拿到了
                fields = Str.split(",");// 得到字段数组
                            
            } catch (Exception e) {                
                e.printStackTrace();
            }
            
        }
        // 输入:<MapReduce file3,2>  
        // 输出:<MapReduce file1,1;file2,1;file3,2;>  
        
        @Override  
        protected void reduce(Text key, Iterable<Text> values, Context context)  
                throws IOException, InterruptedException {  
            
            // 生成文档列表  
            String fileList = new String();  
            int totalNum = 0;
            for (Text value : values) { 
                String va = value.toString();
                int index = va.indexOf(',');
                String subva = va.substring(index+1);
                int num = Integer.valueOf(subva);
                totalNum += num;
                fileList += "<" + va + ">;";  
            }  
            fileList += "<total," + String.valueOf(totalNum)+">.";
            result.set(fileList);  
            //去除停用词
            String k = key.toString();
            k = k.replaceAll("[^a-z0-9]", "");                      
            if(k!=null){
                boolean tag = true;
                for(String tmp:fields){
                    //System.out.println(tmp);
                    if(tmp.equals(k)){  
                        tag = false;
                        break;
                    }
                }               
                if(tag){
                    context.write(key, result);
                }
            }             
        }  
    }

相关文章

网友评论

      本文标题:在hadoop的map-reduce框架下实现倒排索引Inver

      本文链接:https://www.haomeiwen.com/subject/imksnqtx.html