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

 

分享到:
评论

相关推荐

    人力资源经理绩效考核表.xls

    人力资源经理绩效考核表

    智慧环卫管理平台建设方案Word(211页).docx

    一、智慧环卫管理平台的建设背景与目标 智慧环卫管理平台的建设源于对环卫管理全面升级的需求。当前,城管局已拥有139辆配备车载GPS系统、摄像头和油耗传感器的环卫车辆,但环卫人员尚未配备智能移动终端,公厕也缺乏信息化系统和智能终端设备。为了提升环卫作业效率、实现精细化管理并节省开支,智慧环卫管理平台应运而生。该平台旨在通过信息化技术和软硬件设备,如车载智能终端和环卫手机App,实时了解环卫人员、车辆的工作状态、信息和历史记录,使环卫作业管理透明化、精细化。同时,平台还期望通过数据模型搭建和数据研读,实现更合理的环卫动态资源配置,为环卫工作的科学、健康、持续发展提供决策支持。 二、智慧环卫管理平台的建设内容与功能 智慧环卫管理平台的建设内容包括运行机制体制建设、业务流程设计、智慧公厕系统建设、网络建设、主机和储存平台需求、平台运维管理体系、硬件标准规范体系以及考核评价体系等多个方面。其中,智慧公厕系统建设尤为关键,它能实时监控公厕运行状态,保障公厕的清洁和正常运行。平台建设还充分利用了现有的电子政务网络资源,并考虑了有线和无线网络的需求。在功能上,平台通过普查、整合等手段全面收集环卫车辆、企业、人员、设施、设备等数据,建立智慧环卫基础数据库。利用智能传感、卫星定位等技术实现环卫作业的在线监管和远程监控,实现对道路、公共场所等的作业状况和卫生状况的全面监管。此外,平台还建立了环卫作业网格化管理责任机制,实现从作业过程到结果的全面监管,科学评价区域、部门、单位和人员的作业效果。 三、智慧环卫管理平台的效益与风险规避 智慧环卫管理平台的建设将带来显著的环境、经济和管理效益。环境方面,它将有力推进环境卫生监管服务工作,改善环境卫生状况,为人民群众创造更加清洁、卫生的工作和生活环境。经济方面,通过智慧化监管,大大降低了传统管理手段的成本,提高了监管的准确性和效率。管理方面,平台能够追踪溯源市民反映的问题,如公厕异味、渣土车辆抛洒等,并找到相应的责任单位进行处置,防止类似事件再次发生。同时,平台还拥有强大的预警机制功能,能够在很多环卫问题尚未出现前进行处置。然而,平台建设也面临一定的风险,如部门协调、配合问题,建设单位选择风险以及不可预测的自然灾害等。为了规避这些风险,需要加强领导、统一思想,选择优秀的系统集成商承接项目建设,并做好计算机和应用系统的培训工作。同时,也要注意标准制定工作和相关法律法规的制定工作,以保证系统建设完成后能够真正为环卫管理工作带来便利。

    apache-parent-10-14.el7.x64-86.rpm.tar.gz

    1、文件内容:apache-parent-10-14.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/apache-parent-10-14.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、安装指导:私信博主,全程指导安装

    用于卫星通信的CTS天线

    用于卫星通信的圆极化CTS天线研究

    人事档案登记及查询系统.xlsx

    人事档案登记及查询系统

    12 -防损部经理绩效考核表1.xlsx

    12 -防损部经理绩效考核表1

    泰尔指数模型stata全流程代码+数据+文献(数据权威)

    ## 一、泰尔指数模型stata全流程代码+数据+文献 参考C刊《农业经济问题》朱红根(2023)老师的做法,用泰尔指数是衡量个人或地区之间收入差距的重要指标,本文利用泰尔指数分析中国区域内和区域间数字乡村发展水平的差异,测算了全国总体差异、区域内差异、区域间差异以及相关贡献率。此资料包括stata全流程代码、案例数据、参考文献,用excel计算有标注有过程 ,并且参照文献讲的。 ## 二、2005-2021年城乡收入差距与泰尔指数:原始数据+测算结果 泰尔熵标准(Theil’s entropy measure)或者泰尔指数(Theil index)是衡量个人之间或者地区间收入差距(或者称不平等度)的指标。又称泰尔系数或锡尔指数,但我还是习惯叫泰尔指数。Theil指数用来表示区域经济差异状况,数值越大则差异程度越大。 数据名称:城乡收入差距与泰尔指数(原始数据+测算) 数据年份:2005-2021年 指标变量:泰尔指数、城镇收入占农村收入之比、城镇居民人均可支配收入、农村居民人均可支配收入、乡村人口、全体居民人均可支配收入、城镇人口、年末常住人口 测算公式:

    34 -配送部经理绩效考核表1.xlsx

    34 -配送部经理绩效考核表1

    [2024最新更新]全国城投公司数据大全(数据权威)

    1.资料名称:2021-1998年城投公司数据大全 2.数据指标:序号、公司名称、区域、城投评分、省内排名、最新主体评级、行政等级、 股东背景、股权关系、平台重要性、城投口径、实控人、 总资产(亿元)、 货币资金(亿元)、土地资产(亿元)、受限资产(亿元)、应收账款(亿元) 应收类款项政府占比(%)、营业收入(亿元)、公益性&准公益性主营占比(%)、归母净利润(亿元)、政府补助(亿元)、总资产报酬率(%)、有息债务(亿元)、 短期债务(亿元)、借款(亿元)、债券余额(亿元)、私募债占比(%)、 非标融资(亿元)、资产负债率(%)、债务资本化比率(%) 对外担保比例(%)、EBITDA/利息(倍)、EBITDA全部债务比(%)、授信余额(亿元)、 最新报告期 、申万行业 城投公司是城市建设投资公司的简称,是全国各大城市政府投资融资平台,起源于1991年,承担相应的政府职能,是特殊市场经营体。 此类城投公司大多是不具备盈利能力的,属于事业单位或者国有独资公司性质,他们是通过政府补贴的方式实现盈利,属于带有政府性质的特殊市场经营体。

    推广立方连通圈网络的Hamilton分解的算法.pdf

    推广立方连通圈网络的Hamilton分解的算法.pdf

    材料员绩效考核表.xls

    材料员绩效考核表

    2023年全国大学生英语竞赛样题(A类).pdf

    2023年全国大学生英语竞赛样题(A类)

    考虑柔性负荷的综合能源低碳经济调度模型研究:基于碳交易与场景分析的优化求解方法结合CPLEX的灵活求解方案 ,考虑柔性负荷的综合能源低碳经济调度 调度模型参考第一篇文献 碳交易模型参考第二篇 考虑三种

    考虑柔性负荷的综合能源低碳经济调度模型研究:基于碳交易与场景分析的优化求解方法结合CPLEX的灵活求解方案。,考虑柔性负荷的综合能源低碳经济调度 调度模型参考第一篇文献 碳交易模型参考第二篇 考虑三种场景并用cplex求解 场景一调度结果如图所示 本代码可改写能力强 ,核心关键词: 1. 柔性负荷综合能源低碳经济调度; 2. 调度模型; 3. 碳交易模型; 4. 场景分析; 5. Cplex求解; 6. 改写能力强。,"综合能源低碳调度:多场景Cplex求解的柔性负荷模型及优化结果展示"

    计算机网络技术考试题(含参考答案).doc

    计算机网络

    C语言刷题-lesson3.pdf

    C语言刷题-lesson3

    基于条件风险价值CVaR的微网动态定价与调度策略:主从博弈模型下的社会福利最大化与产消者合作博弈,MATLAB代码:基于条件风险价值CVaR的微网动态定价与调度策略 关键词:P2P交易 微网优化调度

    基于条件风险价值CVaR的微网动态定价与调度策略:主从博弈模型下的社会福利最大化与产消者合作博弈,MATLAB代码:基于条件风险价值CVaR的微网动态定价与调度策略 关键词:P2P交易 微网优化调度 条件风险价值 合作博弈 动态定价 仿真平台:MATLAB yalmip+cplex+mosek 主要内容:代码主要做的是一个基于主从博弈的考虑差别定价和风险管理的微网动态定价与调度策略,构建了双层能源管理框架,上层为零商的动态定价模型,目标是社会福利最大化;下层是多个产消者的合作博弈模型,优化各产消者的能量管理策略,各产消者之间可以进行P2P交易。 同时,采用纳什谈判法对多个产消者的合作剩余进行公平分配,还考虑了运行风险,采用条件风险价值(CVaR)随机规划方法来描述零商的预期损失。 代码非常精品,注释保姆级 ,基于CVaR的微网动态定价与调度策略:P2P交易下的风险管理及优化调度

    企业员工安全生产教育培训.pptx

    企业员工安全生产教育培训

    树+线段树+LCA的讲解

    树+线段树+LCA的讲解

    岗位绩效考核评定表excel表格模板.xlsx

    岗位绩效考核评定表excel表格模板

    中国各地区能源消费量和能源产量(数据权威)

    资源名称:中国各地区能源消费量和能源产量 时间范围:1990-2021年 数据来源:《中国能源统计年

Global site tag (gtag.js) - Google Analytics