`
davidxiaozhi
  • 浏览: 242107 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

MahoutDriver运作机制-mahout源码学习及总结

阅读更多

欢迎喜欢深入了解推荐系统和mahout的兄弟加入群     推荐系统之Mahout  135918911

 

mahout入口类MahoutDriver
 
如果我们想要研究MahoutDriver的源码,没有什么比测试类更好的了,下面我们看一下测试类
 

public final class MahoutDriverTest {

     //测试MahoutDriver.main方法

    @Test
     public void testMain() throws Throwable {

    //我们注释掉原有的简单help参数,增加自定定义参数
    //MahoutDriver.main(new String[] {"itemsimilarity", "help"});
    MahoutDriver.main(new String[] {"itemsimilarity", "-Djava.home=wwww.c.cn"," -input"," c:/c/c","-output", "d"," e", "f"});
    }

}

 
 下面我们来看一下MahoutDriver方法组成,下面先粘贴上其方法大纲
 
 
先简单介绍一下main方法之外的一些方法的作用
 
 //判断我们要使用的mahout类是否已经过期,过期返回true,不过期返回false
 private static boolean isDeprecated(Properties mainClasses, String keyString) {
    return "deprecated".equalsIgnoreCase(shortName(mainClasses.getProperty(keyString)));
  }
 
 
//加载资源属性文件
private static Properties loadProperties(String resource) throws IOException
//模拟linux中的shift命令,及让第一个参数失效(数组中index=0),及重新构造数组,保留index1位置开始到结束的全部参数
private static String[] shift(String[] args)
//例如org.apache.mahout.cf.taste.hadoop.similarity.item.ItemSimilarityJob = itemsimilarity : Compute the item-item-similarities for item-based collaborative filtering
private static String shortName(String valueString) {
    return valueString.contains(":") ? valueString.substring(0, valueString.indexOf(':')).trim() : valueString;
}

  private static String desc(String valueString) {
    return valueString.contains(":") ? valueString.substring(valueString.indexOf(':')).trim() : valueString;
  }
 
介绍一下MahoutDriver的核心代码,这里我们就不粘贴全部代码了,我们分逻辑块说明
 1.创建programdriver, 使用hadoop的驱动工具类进行相关类的实例化,及调用
 ProgramDriver programDriver = new ProgramDriver();
 2. 首先加载mahout配置文件driver.classes.props ,如果该文件不存在的话,我们加载driver.classes.default.props ,如果都不存在就会退出,停止运行,如果我们需要新添加算法类,可以再两个文件中添加
    Properties mainClasses = loadProperties("driver.classes.props");
    if (mainClasses == null) {
      mainClasses = loadProperties("driver.classes.default.props");
    }
    if (mainClasses == null) {
      throw new IOException("Can't load any properties file?");
    }
3.验证是否是算法类简称调用,算法类是否过时,并创建描述信息
 
    boolean foundShortName = false;
    for (Object key :  mainClasses.keySet()) {
      String keyString = (String) key;
 首先判断是我们是否是通过算法类简称及shortName调用,  
      if (args.length > 0 && shortName(mainClasses.getProperty(keyString)).equals(args[0])) {
        foundShortName = true;
      }
    第二步 判断是否是通过算法类全路径调用,如果是全路径调用但是获取算法类简称 是过时废弃的 即等于deprecated 那么退出main方法,防止我们通过全路径方式使用过时的算法类    
      if (args.length > 0 && keyString.equalsIgnoreCase(args[0]) && isDeprecated(mainClasses, keyString)) {
        log.error(desc(mainClasses.getProperty(keyString)));
        return;
      }
       不处理已经过时废弃的类
      if (isDeprecated(mainClasses, keyString)) {
        continue;
      }
    第三步 建立 全部算法类的描述信息类就是描述该类是做什么的,参数等等,
      addClass(programDriver, keyString, mainClasses.getProperty(keyString));
    }
 
 
 
4.验证我们是否调用帮助信息,如果是的话直接输出帮助信息,
   如果我们是使用全路径调用的,并没有使用简称,创建描述类,个人认为这里主要是针对第一个参数没有在配置文件中注册的情况出现的处理办法,最后让arg[0]失效,其他数组索引全部减一,(内部是通过copy数组实现的)
   if (args.length < 1 || args[0] == null || "-h".equals(args[0]) || "--help".equals(args[0])) {
      programDriver.driver(args);
    }

    String progName = args[0];
    if (!foundShortName) {
      addClass(programDriver, progName, progName);
    }
    shift(args);
 
5. 加载progName + ".props"指定配置文件(progName 就是我们传递的第一个参数),如果不存在的话,那么我们就只能使用命令行参数了
最后对参数进行封装处理
 Properties mainProps = loadProperties(progName + ".props");
    if (mainProps == null) {
      log.warn("No {}.props found on classpath, will use command-line arguments only", progName);
      mainProps = new Properties();
    }
   接下来对命令参数进行处理 分三步, 解析命令行参数 ,添加我们命令行没有覆盖的参数,还原命令行参数  
     Map<String,String[]> argMap = Maps.newHashMap();
    int i = 0;
    while (i < args.length && args[i] != null) {
      List<String> argValues = Lists.newArrayList();
      //取到当前参数,该值是用来作为map中的key使用的,
      1)arg一般情况下为当前参数 args[i]  当前args[i]后面的一系列参数都会作为args[i]的参数,除非我们查找到带 “ -  ”横杠的参数 
      2)但是如果是java命令行参数的话,该值会被替换为args[i]中=符号前面的部分,args[i]中=符号后面的字符串作为值
      String arg = args[i];
      i++;
       //验证是否是java的命令行参数设置
      if (arg.startsWith("-D")) { // '-Dkey=value' or '-Dkey=value1,value2,etc' case
        String[] argSplit = arg.split("=");
        arg = argSplit[0];
        if (argSplit.length == 2) { 传参格式必须正确长度必须是2
          argValues.add(argSplit[1]);
        }
      } else { 非java命令行参数value值添加处理                                     // '-key [values]' or '--key [values]' case.
        while (i < args.length && args[i] != null) {
           //非java命令行参数处理,只要遇到-
          if (args[i].startsWith("-")) {
            break;
          }
          argValues.add(args[i]);
          i++;
        }
      }
      argMap.put(arg, argValues.toArray(new String[argValues.size()]));
    }
   添加没有被我们覆盖的其他默认参数
// Add properties from the .props file that are not overridden on the command line
    for (String key : mainProps.stringPropertyNames()) {
       //举例配置文件中内容为
       // #i|input = /path/to/input
       // #o|output = /path/to/output  
      String[] argNamePair = key.split("\\|");
      //简写参数及长写参数
      String shortArg = '-' + argNamePair[0].trim();
      String longArg = argNamePair.length < 2 ? null : "--" + argNamePair[1].trim();
     //如果传递命令参数中不包含该参数,添加进处理的参数集合中
      if (!argMap.containsKey(shortArg) && (longArg == null || !argMap.containsKey(longArg))) {
        argMap.put(longArg, new String[] {mainProps.getProperty(key)});
      }
    }
  将处理好后的参数进行封装中可以使用的参数
 // Now add command-line args
    List<String> argsList = Lists.newArrayList();
    argsList.add(progName);
    for (Map.Entry<String,String[]> entry : argMap.entrySet()) {
      String arg = entry.getKey();
      if (arg.startsWith("-D")) { // arg is -Dkey - if value for this !isEmpty(), then arg -> -Dkey + "=" + value
        String[] argValues = entry.getValue();
        if (argValues.length > 0 && !argValues[0].trim().isEmpty()) {
          arg += '=' + argValues[0].trim();
        }
        argsList.add(1, arg);
      } else {
        argsList.add(arg);
        for (String argValue : Arrays.asList(argMap.get(arg))) {
          if (!argValue.isEmpty()) {
            argsList.add(argValue);
          }
        }
      }
    }
6 使用hadoop工具类驱动我们的算法类运行,并接传递相关参数
programDriver.driver(argsList.toArray(new String[argsList.size()]));
 
下面简单介绍一下hadoop的工具类,程序驱动类
 
ProgramDriver 主要功能求实输出我们添加的全部类描述信息,主要属性是一个存放ProgramDescription的treemap集合,
其他方法为 
 
          printUsage,打印Treemap<ProgramDescription>中的全部描述信息 
          addClass 创建ProgramDescription 并接添加进treemap当中
          driver(String[] args) 通过args[0] 取到 ProgramDescription  反射调用指定类的main方法并接传递参数
          其核心代码以去除非空判断及打印全部信息等等
    ProgramDescription pgm = programs.get(args[0]);
    if (pgm == null) {
      System.out.println("Unknown program '" + args[0] + "' chosen.");
      printUsage(programs);
      System.exit(-1);
    }
    
    // Remove the leading argument and call main
    String[] new_args = new String[args.length - 1];
    for(int i=1; i < args.length; ++i) {
      new_args[i-1] = args[i];
    }
    //这里开始调用ProgramDescription 的invoke方法
    pgm.invoke(new_args);
 
下面介绍一下其很重要的静态内部类ProgramDescription
 
  
 
     这里paramTypes主要是申明我们在反射调用时传递的是string数组类型(因为反射调用的默认都是main方法) 
     static final Class<?>[] paramTypes = new Class<?>[] {String[].class};
     我们将来要反射调用的方法实例
     Mehod main      
      我们自己定义的程序描述信息
     String description
    探秘一下构造器 
    public ProgramDescription(Class<?> mainClass, 
                              String description)
      throws SecurityException, NoSuchMethodException {
      负责获取我们将来要反射调用的main函数的Method的实例
      this.main = mainClass.getMethod("main", paramTypes);
      this.description = description;// 算法的描述信息
    }
      
    探秘一下invoke 很简单的反射调用
    public void invoke(String[] args)
      throws Throwable {
      try {
        main.invoke(null, new Object[]{args});
      } catch (InvocationTargetException except) {
        throw except.getCause();
      }
    }
 
 

 

分享到:
评论

相关推荐

    Java-美妆神域_3rm1m18i_221-wx.zip

    Java-美妆神域_3rm1m18i_221-wx.zip

    51单片机的温度监测与控制(温控风扇)

    51单片机的温度监测与控制(温控风扇)

    电赛案例,C++简单的智能家居系统,其中包含了温度监测、光照控制和报警系

    电赛案例,C++简单的智能家居系统,其中包含了温度监测、光照控制和报警系统。该系统可以: 监控室内温度:当温度超过设定阈值时,触发警报。 自动调节光照:根据光线传感器的值自动调节LED灯的亮度。 入侵检测:通过红外传感器检测入侵,并触发警报。

    圣诞树 html版 可修改祝福语

    圣诞树 html版 可修改祝福语。 记事本或vscode编辑html文件:ctrl+F寻找”myLabels“关键词,定位到该处即可修改祝福语

    基于python编写的selenium自动化测试框架,采用PO模式,页面元素采用yaml进行管理资料齐全+详细文档+高分项目+源码.zip

    【资源说明】 基于python编写的selenium自动化测试框架,采用PO模式,页面元素采用yaml进行管理资料齐全+详细文档+高分项目+源码.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    屏幕截图 2024-12-21 170434.png

    屏幕截图 2024-12-21 170434

    基于SpringBoot的学生信息管理系统源码

    基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理 基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理 请假信息管理 成绩信息管理基于SpringBoot的学生信息管理系统(前后端源码+数据库+文档+运行截图) 学生信息管理 班级信息管理 教师信息管理 课程信息管理 选课信息管理 考勤信息管理

    径向基函数内核 – 机器学习python案例脚本,内核在将数据转换为更高维空间方面发挥着重要作用

    径向基函数内核 – 机器学习 内核在将数据转换为更高维空间方面发挥着重要作用,使算法能够学习复杂的模式和关系。在众多的内核函数中,径向基函数(RBF)内核作为一种多功能且强大的工具脱颖而出。在本文中,我们深入探讨了RBF内核的复杂性,探讨了它的数学公式、直观理解、实际应用及其在各种机器学习算法中的重要性。

    工具变量-中国省级数字经济发展水平面板数据(2012-2022).xlsx

    详细介绍及样例数据:https://blog.csdn.net/samLi0620/article/details/144636765

    51单片机控制的智能小车.7z

    51单片机控制的智能小车.7z

    基于卷积神经网络的数字手势识别安卓APP,识别数字手势0-10详细文档+全部资料+优秀项目+源码.zip

    【资源说明】 基于卷积神经网络的数字手势识别安卓APP,识别数字手势0-10详细文档+全部资料+优秀项目+源码.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    pymssql-2.1.4.dev5-cp37-cp37m-win-amd64.whl pymssql-2.1.4.dev5-cp37-cp37m-win32.whl

    python 使用sqlserver必须要这个问题,没办法,只能满世界的找地方下载,终于让我下载到了,现在分享给大家使用

    四川采矿场生产安全事故管理制度.docx

    四川采矿场生产安全事故管理制度

    简约灰粉共存版_8.0.53.apk

    简约灰粉共存版_8.0.53.apk

    ECharts散点图-全国主要城市空气质量(百度地图).rar

    ECharts散点图-全国主要城市空气质量(百度地图)

    四川采矿场安全检查管理规定.docx

    四川采矿场安全检查管理规定

    JSP基于WEB网上论坛设计与实现(源代码+论文+开题报告+答辩PPT+外文翻译)(2024kt).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    空中俯视物体检测9-YOLOv5数据集合集.rar

    空中俯视物体检测9-YOLOv5数据集合集.rar使用YOLO算法从图像中检测对象-V2 2023-05-11 2:51 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括1015张图像。 以YOLO V5 PYTORCH格式注释检测对象 - 图像。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 没有应用图像增强技术。

    会使用到的js文件词云图

    词云图

    Python&OpenCV手势识别系统(完整源码&自定义UI操作界面&视频教程)

    Python高分毕设——Python&Opencv手势识别系统(完整源码&自定义UI操作界面&视频教程) Python高分毕设——Python&Opencv手势识别系统(完整源码&自定义UI操作界面&视频教程) 使用了OpenCV的视频采集, 图像色域转换, 颜色通道分割, 高斯滤波, OSTU自动阈值, 凸点检测, 边缘检测, 余弦定理计算手势等功能. 准备工作 安装 Python-OpenCV 库 pip install opencv-python -i https://mirrors.ustc.edu.cn/pypi/web/simple 利用 -i 为pip指令镜像源, 这里使用电子科技大学的源, 速度比官方源更快. 安装 Numpy 科学计算库 pip install numpy -i https://mirrors.ustc.edu.cn/pypi/web/simple 安装 PyAutogui 库 pip install pyautogui -i https://mirrors.ustc.edu.cn/pypi/web/simple 代码实现 import nu

Global site tag (gtag.js) - Google Analytics