热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

hivemap转string_Hive如何确定map数的?

最近批量刷数据的时候,由于集群资源紧张,需要控制一些map的数量,本文从底层代码触发,带大家了解一下MR是如何让切分map数

最近批量刷数据的时候,由于集群资源紧张,需要控制一些 map 的数量,本文从底层代码触发,带大家了解一下 MR 是如何让切分 map 数的。

Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的 sql 查询功能,可以将 sq l语句转换为 MapReduce 任务进行运行。当运行一个 hql 语句的时候,map 数是如何计算出来的呢?有哪些方法可以调整 map 数呢?

本文测试集群版本:cdh-4.3.0

hive 默认的 input format

在 cdh-4.3.0 的 hive 中查看 hive.input.format 值(为什么是hive.input.format?):

hive> set hive.input.format;hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

可以看到默认值为 CombineHiveInputFormat,如果你使用的是 IDH 的hive,则默认值为:

hive> set hive.input.format;hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

CombineHiveInputFormat 类继承自 HiveInputFormat,而 HiveInputFormat 实现了 org.apache.hadoop.mapred.InputFormat 接口,关于 InputFormat 的分析,可以参考Hadoop深入学习:InputFormat组件.

InputFormat 接口功能

简单来说,InputFormat 主要用于描述输入数据的格式,提供了以下两个功能:

1)、数据切分,按照某个策略将输入数据且分成若干个 split,以便确定 Map Task 的个数即 Mapper 的个数,在 MapReduce 框架中,一个 split 就意味着需要一个 Map Task;

2)、为 Mapper 提供输入数据,即给定一个 split(使用其中的 RecordReader 对象)将之解析为一个个的 key/value 键值对。

该类接口定义如下:

public interface InputFormat{public InputSplit[] getSplits(JobConf job,int numSplits) throws IOException;public RecordReader getRecordReader(InputSplit split,JobConf job,Reporter reporter) throws IOException;}

其中,getSplit() 方法主要用于切分数据,每一份数据由,split 只是在逻辑上对数据分片,并不会在磁盘上将数据切分成 split 物理分片,实际上数据在 HDFS 上还是以 block 为基本单位来存储数据的。InputSplit 只记录了 Mapper 要处理的数据的元数据信息,如起始位置、长度和所在的节点。

MapReduce 自带了一些 InputFormat 的实现类:

011893349caeed3eab492967c567f011.png

hive 中有一些 InputFormat 的实现类,如:

AvroContainerInputFormatRCFileBlockMergeInputFormatRCFileInputFormatFlatFileInputFormatOneNullRowInputFormatReworkMapredInputFormatSymbolicInputFormatSymlinkTextInputFormatHiveInputFormat

HiveInputFormat 的子类有:

HiveInputFormat

以 HiveInputFormat 为例,看看其getSplit()方法逻辑:

for (Path dir : dirs) {PartitionDesc part = getPartitionDescFromPath(pathToPartitionInfo, dir);// create a new InputFormat instance if this is the first time to see this// classClass inputFormatClass = part.getInputFileFormatClass();InputFormat inputFormat = getInputFormatFromCache(inputFormatClass, job);Utilities.copyTableJobPropertiesToConf(part.getTableDesc(), newjob);// Make filter pushdown information available to getSplits.ArrayList aliases =mrwork.getPathToAliases().get(dir.toUri().toString());if ((aliases != null) && (aliases.size() == 1)) {Operator op = mrwork.getAliasToWork().get(aliases.get(0));if ((op != null) && (op instanceof TableScanOperator)) {TableScanOperator tableScan = (TableScanOperator) op;pushFilters(newjob, tableScan);}}FileInputFormat.setInputPaths(newjob, dir);newjob.setInputFormat(inputFormat.getClass());InputSplit[] iss = inputFormat.getSplits(newjob, numSplits / dirs.length);for (InputSplit is : iss) {result.add(new HiveInputSplit(is, inputFormatClass.getName()));}}

上面代码主要过程是:

遍历每个输入目录,然后获得 PartitionDesc 对象,从该对象调用 getInputFileFormatClass 方法得到实际的 InputFormat 类,并调用其 getSplits(newjob, numSplits / dirs.length) 方法。

按照上面代码逻辑,似乎 hive 中每一个表都应该有一个 InputFormat 实现类。在 hive 中运行下面代码,可以查看建表语句:

hive> show create table info;OKCREATE TABLE info(statist_date string,statistics_date string,inner_code string,office_no string,window_no string,ticket_no string,id_kind string,id_no string,id_name string,area_center_code string)ROW FORMAT DELIMITEDFIELDS TERMINATED BY ';'LINES TERMINATED BY ''STORED AS INPUTFORMAT'org.apache.hadoop.mapred.TextInputFormat'OUTPUTFORMAT'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'LOCATION'hdfs://node:8020/user/hive/warehouse/info'TBLPROPERTIES ('numPartitions'='0','numFiles'='1','transient_lastDdlTime'='1378245263','numRows'='0','totalSize'='301240320','rawDataSize'='0')Time taken: 0.497 seconds

从上面可以看到 info 表的 INPUTFORMAT 为org.apache.hadoop.mapred.TextInputFormat,TextInputFormat 继承自FileInputFormat。FileInputFormat 是一个抽象类,它最重要的功能是为各种 InputFormat 提供统一的 getSplits()方法,该方法最核心的是文件切分算法和 Host 选择算法。

算法如下:

long length = file.getLen();long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits);long minSize = Math.max(job.getLong(org.apache.hadoop.mapreduce.lib.input.FileInputFormat.SPLIT_MINSIZE, 1), minSplitSize);long blockSize = file.getBlockSize();long splitSize = computeSplitSize(goalSize, minSize, blockSize);long bytesRemaining = length;while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {String[] splitHosts = getSplitHosts(blkLocations,length-bytesRemaining, splitSize, clusterMap);splits.add(makeSplit(path, length-bytesRemaining, splitSize,splitHosts));bytesRemaining -= splitSize;}


华丽的分割线:以下摘抄自Hadoop深入学习:InputFormat组件

1)文件切分算法

文件切分算法主要用于确定InputSplit的个数以及每个InputSplit对应的数据段,FileInputSplit以文件为单位切分生成InputSplit。有三个属性值来确定InputSplit的个数:

  • goalSize:该值由 totalSize/numSplits 来确定 InputSplit 的长度,它是根据用户的期望的 InputSplit 个数计算出来的;numSplits 为用户设定的 Map Task 的个数,默认为1。
  • minSize:由配置参数 mapred.min.split.size(或者 mapreduce.input.fileinputformat.split.minsize)决定的 InputForma t的最小长度,默认为1。
  • blockSize:HDFS 中的文件存储块block的大小,默认为64MB。
  • numSplits=mapred.map.tasks 或者 mapreduce.job.maps

这三个参数决定一个 InputFormat 分片的最终的长度,计算方法如下:

splitSize = max{minSize,min{goalSize,blockSize}}

计算出了分片的长度后,也就确定了 InputFormat 的数目。

2)host 选择算法

InputFormat 的切分方案确定后,接下来就是要确定每一个 InputSplit 的元数据信息。InputSplit 元数据通常包括四部分,其意义为:

  • file 标识 InputSplit 分片所在的文件;
  • InputSplit 分片在文件中的的起始位置;
  • InputSplit 分片的长度;
  • 分片所在的 host 节点的列表。

InputSplit 的 host 列表的算作策略直接影响到运行作业的本地性。

我们知道,由于大文件存储在 HDFS上的 block 可能会遍布整个 Hadoop 集群,而一个 InputSplit 分片的划分算法可能会导致一个 split 分片对应多个不在同一个节点上的 blocks,这就会使得在 Map Task 执行过程中会涉及到读其他节点上的属于该 Task 的 block 中的数据,从而不能实现数据本地性,而造成更多的网络传输开销。

一个 InputSplit 分片对应的 blocks 可能位于多个数据节点地上,但是基于任务调度的效率,通常情况下,不会把一个分片涉及的所有的节点信息都加到其host列表中,而是选择包含该分片的数据总量的最大的前几个节点,作为任务调度时判断是否具有本地性的主要凭证。

FileInputFormat 使用了一个启发式的 host 选择算法:首先按照 rack 机架包含的数据量对 rack 排序,然后再在 rack 内部按照每个 node 节点包含的数据量对 node 排序,最后选取前 N 个(N 为 block 的副本数),node 的 host 作为 InputSplit 分片的 host 列表。当任务地调度 Task 作业时,只要将 Task 调度给 host 列表上的节点,就可以认为该 Task 满足了本地性。

从上面的信息我们可以知道,当 InputSplit 分片的大小大于 block 的大小时,Map Task 并不能完全满足数据的本地性,总有一本分的数据要通过网络从远程节点上读数据,故为了提高 Map Task 的数据本地性,减少网络传输的开销,应尽量是 InputFormat 的大小和 HDFS 的 block 块大小相同。


CombineHiveInputFormat

getSplits(JobConf job, int numSplits) 代码运行过程如下:

init(job);CombineFileInputFormatShim combine = ShimLoader.getHadoopShims().getCombineFileInputFormat();ShimLoader.loadShims(HADOOP_SHIM_CLASSES, HadoopShims.class);Hadoop23ShimsHadoopShimsSecure.getCombineFileInputFormat()

CombineFileInputFormatShim 继承了org.apache.hadoop.mapred.lib.CombineFileInputFormat,CombineFileInputFormatShim 的 getSplits 方法代码如下:

public InputSplitShim[] getSplits(JobConf job, int numSplits) throws IOException {long minSize = job.getLong("mapred.min.split.size



推荐阅读
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 如何使用 `org.opencb.opencga.core.results.VariantQueryResult.getSource()` 方法及其代码示例详解 ... [详细]
  • 如何将Python与Excel高效结合:常用操作技巧解析
    本文深入探讨了如何将Python与Excel高效结合,涵盖了一系列实用的操作技巧。文章内容详尽,步骤清晰,注重细节处理,旨在帮助读者掌握Python与Excel之间的无缝对接方法,提升数据处理效率。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 在使用 Cacti 进行监控时,发现已运行的转码机未产生流量,导致 Cacti 监控界面显示该转码机处于宕机状态。进一步检查 Cacti 日志,发现数据库中存在 SQL 查询失败的问题,错误代码为 145。此问题可能是由于数据库表损坏或索引失效所致,建议对相关表进行修复操作以恢复监控功能。 ... [详细]
  • 在PHP中,高效地分割字符串是一项常见的需求。本文探讨了多种技术,用于在特定字符(如“或”)后进行字符串分割。通过使用正则表达式和内置函数,可以实现更加灵活和高效的字符串处理。例如,可以使用 `preg_split` 函数来实现这一目标,该函数允许指定复杂的分隔符模式,从而提高代码的可读性和性能。此外,文章还介绍了如何优化分割操作以减少内存消耗和提高执行速度。 ... [详细]
  • 本文详细介绍了批处理技术的基本概念及其在实际应用中的重要性。首先,对简单的批处理内部命令进行了概述,重点讲解了Echo命令的功能,包括如何打开或关闭回显功能以及显示消息。如果没有指定任何参数,Echo命令会显示当前的回显设置。此外,文章还探讨了批处理技术在自动化任务执行、系统管理等领域的广泛应用,为读者提供了丰富的实践案例和技术指导。 ... [详细]
  • 在Ubuntu上安装MySQL时解决缺少libaio.so.1错误及libaio在MySQL中的重要性分析
    在Ubuntu系统上安装MySQL时,遇到了缺少libaio.so.1的错误。本文详细介绍了如何解决这一问题,并深入探讨了libaio库在MySQL性能优化中的重要作用。对于初学者而言,理解这些依赖关系和配置步骤是成功安装和运行MySQL的关键。通过本文的指导,读者可以顺利解决相关问题,并更好地掌握MySQL在Linux环境下的部署与管理。 ... [详细]
author-avatar
冰_若真人_755_171
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有