`
davidxiaozhi
  • 浏览: 236682 次
  • 性别: 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();
      }
    }
 
 

 

分享到:
评论

相关推荐

    Toxi / Oxy Pro 便携式气体检测仪参考手册 使用说明书

    Toxi Oxy Pro 便携式气体检测仪参考手册 使用说明书

    科傻模拟网优化操作-教程书

    官方的的说明书资料,部分视频说明在这里: https://www.bilibili.com/video/BV1Fz4y1d7rn/?spm_id_from=333.999.0.0&vd_source=13dc65dbb4ac9127d9af36e7b281220e

    node-v8.14.0-x64.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    2023商业银行数据资产体系白皮书,主要介绍了“三位一体”数据资产体系的构成与工作机制,以及商业银行数据资产体系建设实践

    2023商业银行数据资产体系白皮书 目录 第 1 章 数据资产化与数据要素市场化相辅相成,相互促进 第 2 章 数据资产化是企业数据治理向上演进的必经之路 第 3 章 数据资产体系发展概述 第 4 章 “三位一体”数据资产体系的构思 4.1“三位一体”数据资产体系的构成与工作机制 数据资产管理 数据资产运营 数据资产评价 数据资产体系工作机制 4.2“三位一体”数据资产体系的相互作用关系 4.3“三位一体”数据资产体系的构建 4.4“三位一体”数据资产体系的优势 第 5 章 商业银行数据资产体系建设实践 5.1商业银行开展数据资产体系建设的背景和目标 5.2商业银行数据资产体系建设的工作步骤 5.3上海银行数据资产体系建设实践的主要成果 第 6 章 数据要素流通市场赋能企业数据资产化 6.1全国多层次数据要素市场的建设 6.2上海数据交易所赋能企业数据资产化 6.3数据要素流通交易市场赋能企业数据资产化的展望 第 7 章 未来演进与展望

    基于微信小程序的助农扶贫小程序

    大学生毕业设计、大学生课程设计作业

    车辆销售数据Python爬取并做数据分析,项目源码注解清晰一看就懂.zip

    车辆销售数据Python爬取并做数据分析,项目源码注解清晰一看就懂

    毕业设计:基于SSM的mysql-学生社团管理系统(源码 + 数据库 + 说明文档)

    毕业设计:基于SSM的mysql_学生社团管理系统(源码 + 数据库 + 说明文档) 第2章 主要技术和工具介绍 1 2.1 JSP语言 1 2.2 MySQL数据库 1 2.3 jsp技术 2 2.4ssm简介 3 第3章 系统分析 1 3.1可行性分析 1 3.1.1经济可行性 1 3.1.2技术可行性 1 3.1.3操作可行性 1 3.2需求分析 1 3.3业务流程分析 2 3.4数据流程分析 3 第4章 系统设计 5 4.1系统结构设计 5 4.2功能模块设计 5 4.3数据库设计 6 4.3.1数据库设计概述 6 4.3.1概念设计 6 4.3.2表设计 7 第5章 系统实现 15 5.1基本任务 15 5.2登录模块的实现 15 5.2.1首页实现 15 5.2.2管理员后台登录 16 5.3用户模块的实现 19 5.3.1注册模块及登录的实现 19 5.2.2入团模块的实现 21 5.2.3场地预约模块的实现 22 5.4管理员模块的实现 24 5.4.1系统用户管理模块的实现 24 5.4.2活动公告管理模块的实现 26 5.5社团模块的实现 28 5.5.1活动信息

    大健康零售业务O2O数字化战略规划方案.pptx

    大健康零售业务O2O数字化战略规划方案.pptx

    数据中台项目主要岗位及其职责和任务

    数据中台项目主要岗位及其职责和任务

    node-v8.0.0-linux-armv7l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    流程制造行业数字化智能工厂总体规划建设方案.pptx

    流程制造行业数字化智能工厂总体规划建设方案.pptx

    c语言学生成绩管理系统源码.zip

    c语言学生成绩管理系统源码.zip

    DEV-C++-5.11下载链接

    DEV-C++-5.11下载链接

    电器租赁小程序.zip

    电器租赁小程序.zip

    学生成绩管理系统 数据结构与算法课程设计 C++.zip

    学生成绩管理系统 数据结构与算法课程设计 C++

    知乎小程序算法.zip

    知乎小程序算法.zip

    基于R语言SIR传染病传播的SIR模型,很全,可直接应用仿真模拟.rar

    基于R语言SIR传染病传播的SIR模型,很全,可直接应用仿真模拟.rar

    node-v6.13.0.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v10.11.0-darwin-x64.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    项目申报系统(Struts2+Spring+Hibernate+Jsp+Mysql5).zip

    广东工业大学工程管理

Global site tag (gtag.js) - Google Analytics