背景
平台HDFS数据存储规则是按照“数据集/天目录/小时目录/若干文件”进行的,其中数据集是依据产品线或业务划分的。
用户分析数据时,可能需要处理以下五个场景:
(一)分析指定数据集、指定日期、指定小时、指定文件的数据;
(二)分析指定数据集、指定日期、指定小时的数据;
(三)分析指定数据集、指定日期的数据(24个小时目录的数据);
(四)分析多个数据集、多个日期或多个小时的数据;
(五)多种存储格式(textfile、sequencefile、rcfile等)。
目前我们平台提供给用户的分析工具为PySpark(Spark、Spark SQL、Python),本文讨论的就是使用PySpark如果应对上述场景。
示例
假设HDFS存在一个wordcount目录,包含三个子目录:data1、data2、data3,
这三个子目录下均含有一个文本文件words,各自的内容如下:
解决方案
这里我们暂时只考虑文本文件。
1. 分析指定数据集、指定日期、指定小时、指定文件的数据;
2. 分析指定数据集、指定日期、指定小时的数据;
SparkContext textFile默认情况下可以接收一个文本文件路径或者仅仅包含文本文件的目录,使用该方法可以应对场景(一)、(二)。
(1)分析指定文本文件的数据,这里我们假设待分析的数据为“/user/hdfs/yurun/wordcount/data1/words”:
可以得到如下输出:
(2)分析指定目录的数据,且该目录仅包含文本文件,这里我们假设待分析的数据为“/user/hdfs/yurun/wordcount/data1/”:
运行上述代码会得到与(1)相同的结果。
3. 分析指定数据集、指定日期的数据(24个小时目录的数据);
针对我们的示例,也就是需要“递归”分析wordcount目录下三个子目录data1、data2、data3中的数据。我们尝试将上面示例中的输入路径修改为“/user/hdfs/yurun/wordcount/”,
运行上述代码会出现异常:
根据1、2、3中的示例,如果我们指定的输入路径是一个目录,而这个目录中存在子目录就会出现上述异常。究其原因,实际上与FileInputFormat(org.apache.hadoop.mapred.FileInputFormat)的“某个”配置属性值有关。
注意:源码中有两个模块中都包含这个类,
这里使用的是模块hadoop-mapreduce-client中的类。
根据抛出的异常信息,我们可以在FileInputFormat的源码中找到如下代码块:
可以看出,如果files中的任何一个FileStatus实例(由file表示)为目录,便会引发“Not a file”的异常,而files来源于方法listStatus,
我们需要注意两个很重要的变量:
(1)dirs
dirs为我们指定的输入文件或目录,它是由getInputPaths计算而来的,
可以看出,我们通过SparkContext textfile指定的输入路径实际是保存在Configuration中的,以属性FileInputFormat.INPUT_DIR(mapreduce.input.fileinputformat.inputdir)表示,从代码逻辑可知,它的值可以为多个以“,”分隔的字符串。
与就是说,理论上我们是可以指定多个输入文件或目录的(SparkContext textfile仅支持单个文件路径或目录路径)。
(2)recursive
如果我们指定的是一个目录路径,recursive表示着是否允许在后续的切片计算过程中“递归”处理该路径中的子目录,它的值由属性INPUT_DIR_RECURSIVE(mapreduce.input.fileinputformat.input.dir.recursive)决定,默认值为false。
也就是说,默认情况下,FileInputFormat是不会以“递归”的形式处理指定目录中的子目录的,这也是引发上述异常的根本原因。
如果我们需要处理“递归”目录的场景,可以采用下述两个方法:
(1)在Hadoop的配置文件mapred-site.xml中添加属性mapreduce.input.fileinputformat.input.dir.recursive,并指定值为true;
仅仅需要在Spark Client(提交Spark Application的机器)相关机器上操作即可,不需要修改Hadoop集群配置。
修改配置文件后,再次提交上述程序,即可正常执行。
(2)使用hadoopRDD;
这种方式不需要修改配置文件,而是在代码中通过Hadoop Configuration(hadoopConf)直接指定相关属性:
mapreduce.input.fileinputformat.inputdir:hdfs://dip.cdh5.dev:8020/user/hdfs/yurun/wordcount/;
mapreduce.input.fileinputformat.input.dir.recursive:true;
此外还需要注意hadoopRDD的几个参数:
inputFormatClass:org.apache.hadoop.mapred.TextInputFormat
keyClass:org.apache.hadoop.io.LongWritable
valueClass:org.apache.hadoop.io.Text
这仅仅是针对textfile设置的参数值,对于其它的数据格式会有所不同,后面会讨论。
使用hadoopRDD的运行结果会有所不同:
这是因为SparkContext textfile省略了TextInputFormat中的“key”,它表示每一行文本在各自文件中的起始偏移量。
4. 分析多个数据集、多个日期或多个小时的数据;
这种场景要求我们能够指定多个目录或文件,其中还可能需要“递归”处理子目录,SparkContext textfile只能接收一个目录或文件,此时我们只能使用hadoopRDD。
前面提到过,“mapreduce.input.fileinputformat.inputdir”可以以“,”分隔的形式接收多个目录或文件路径。假设我们需要分析的数据为“hdfs://dip.cdh5.dev:8020/user/hdfs/yurun/wordcount/data1”、“hdfs://dip.cdh5.dev:8020/user/hdfs/yurun/wordcount/data2”、“hdfs://dip.cdh5.dev:8020/user/hdfs/yurun/wordcount/data3/words”,代码示例如下:
运行结果同上。
5. 多种存储格式;
1-4的讨论仅仅局限于textfile,textfile易于人的阅读和分析,但存储开销很大,即使采用相应的压缩,效果也并是很理想。在实践中我们发现rcfile采用列式压缩效果显著,因此也需要考虑如何使得PySpark支持rcfile。
为什么这个地方要有专门的“考虑”?
简单来讲,Hadoop是使用Java构建的,Spark是使用Scala构建的,而我们现在使用的开发语言为Python,这就带来一个问题:Java/Scala中的数据类型如何转换为相应的Python数据类型?
如TextInputFormat返回的键值对类型为LongWritable、Text,可以被“自动”转换为Python中的int、str(基本数据类型均可以被“自动”转换),RCFileInputFormat返回的键值对类型为LongWritable、BytesRefArrayWritable,BytesRefArrayWritable不是基本数据类型,它应该如何被转换呢?
我们查看SparkContext hadoopRDD的文档可知,
keyConverter、valueConverter就是用来负责完成键值类型的转换的。
假设我们有一个RCFile格式的文件:
RCFileInputFormat的键类型为LongWritable,可以自动被转换;
RCFileInputFormat的值类型为BytesRefArrayWritable,无法被自动转换,需要一个Converter,这里我们把每一个BytesRefArrayWritable实例转换为一个Text实例,其中三列数据以空格分隔。
我们将Converter定义为BytesRefArrayWritableToStringConverter(com.sina.dip.spark.converter.BytesRefArrayWritableToStringConverter),代码如下:
其实Converter的逻辑非常简单,就是将BytesRefArrayWritable中的数据提取、转换为基本数据类型Text。
将上述代码编译打包为converter.jar。
PySpark代码如下:
重点注意几个参数值:
mapreduce.input.fileinputformat.inputdir:hdfs://dip.cdh5.dev:8020/user/hdfs/yurun/rcfile/data
inputFormatClass:org.apache.hadoop.hive.ql.io.RCFileInputFormat
keyClass:org.apache.hadoop.io.LongWritable
valueClass:org.apache.hadoop.io.Text
valueConverter:com.sina.dip.spark.converter.BytesRefArrayWritableToStringConverter
执行命令:
结果输出:
三行数据,每行数据均为字符串输出,且以空格分隔,可见数据得到正常转换。
通过上述方式,我们可以通过SparkContext hadoopRDD支持多种数据格式数据的分析。
总结
本文通过五种常见应用场景的讨论,可以得出使用PySpark可以支持灵活的数据输入路径,还可以根据需求扩展支持多种数据格式。
- 【异常】hbase启动后hdfs文件权限目录不一致,导致Phoenix无法删除表结构
1 异常信息 Received error when attempting to archive files ([class org.apache.hadoop.hbase.backup.HFileA ...
- HDFS文件操作
hadoop装好后,文件系统中没有任何目录与文件 1. 创建文件夹 hadoop fs -mkdir -p /hkx/learn 参数-p表示递归创建文件夹 2. 浏览文件 hadoop fs -ls ...
- hive1.1.0建立外部表关联HDFS文件
0. 说明 已经安装好Hadoop和hive环境,hive把元数据存储在mysql数据库.这里仅讨论外部表和HDFS的关联,并且删掉外部表之后,对HDFS上的文件没有影响. 1. 在HDFS创建分区, ...
- 大数据之路week07--day01(HDFS学习,Java代码操作HDFS,将HDFS文件内容存入到Mysql)
一.HDFS概述 数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统 ...
- 5、创建RDD(集合、本地文件、HDFS文件)
一.创建RDD 1.创建RDD 进行Spark核心编程时,首先要做的第一件事,就是创建一个初始的RDD.该RDD中,通常就代表和包含了Spark应用程序的输入源数据.然后在创建了初始的RDD之后,才可 ...
- HDFS文件的基本操作
HDFS文件的基本操作: package wjn; import java.io.BufferedInputStream; import java.io.BufferedReader; import ...
- HDFS文件和HIVE表的一些操作
1. hadoop fs -ls 可以查看HDFS文件 后面不加目录参数的话,默认当前用户的目录./user/当前用户 $ hadoop fs -ls 16/05/19 10:40:10 WARN ...
- Hadoop之HDFS文件操作常有两种方式(转载)
摘要:Hadoop之HDFS文件操作常有两种方式,命令行方式和JavaAPI方式.本文介绍如何利用这两种方式对HDFS文件进行操作. 关键词:HDFS文件 命令行 Java API HD ...
- java基础八 [序列化和文件的输入/输出](阅读Head First Java记录)
对象具有状态和行为两种属性.行为存在类中的方法中,想要保存状态有多种方法,这里介绍两种: 一是保存整个当前对象本身(通过序列化):一是将对象中各个状态值保存到文件中(这种方式可以给其他非JAVA程序用 ...
随机推荐
- ubuntu 安装 fcitx
安装fcitx (1)添加ppa源 sudo add-apt-repository ppa:fcitx-team/nightly 或 sudo add-apt-repository ppa:fcitx ...
- MathType支持64位 WIN 7Office 2013(完美解决)(转载)
经过几次尝试解决了,方法如下: 1. 安装MathType 6.8 (别的版本不知是否适用,本人安装的是该版本) 2. 将以下两个文件拷贝出来 C:\Program Files (x86)\MathT ...
- 二、 What's Maven,How to learning?
1. 哈哈,什么是Maevn, ←_←|| ?我怎么知道,来看看官方解释, Apache Maven is a software project management and comprehensio ...
- PAT_1002 写出这个数
宝宝不开心了.自从回家开始百练就上不去POJ也上不去,今天突然HDU也上不去了,PAT25分的题目都快更新完了.我就按顺序往下面更新了.回学校之后题目质量能高出不少= =. 问题描述: 读入一个自然数 ...
- 九度OJ 1435 迷瘴
题目地址:http://ac.jobdu.com/problem.php?pid=1435 题目描述: 通过悬崖的yifenfei,又面临着幽谷的考验—— 幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满 ...
- mysql 主从 Got fatal error 1236 from master when reading data from binary log: 'Could not find first 错误
本地MySQL环境,是两台MySQL做M-M复制.今天发现错误信息: mysql 5.5.28-log> show slave status\G ************************ ...
- uboot下 Nand flash 启动 内核与根文件系统
u-boot版本: u-boot-2010.03_tekkamanninja修改的u-boot 1.将uboot通过j-link烧写到norflash,启动后 saveenv 将参数保存到 nandf ...
- BFC与hasLayout之间的故事
刚拒绝了一个很有诱惑的公司,不是不想去,而是对现在的能力还不确定,希望能够进一步提高自己的技能,所有想写博客了,监督自己的学习进度·········现在还没有开放博客,希望成熟一些后再开放吧! 进入正 ...
- J2EE中的HttpSession
J2EE中的HttpSession总结: ①什么是session? session是服务器端技术,利用这个技术,服务器在运行时可以为每一个浏览器创建一个共享的session对象,由于 session为 ...
- phpstorm配置Xdebug进行调试PHP教程
运行环境: PHPSTORM版本 : 8.0.1 PHP版本 : 5.6.2 xdebug版本:php_xdebug-2.2.5-5.6-vc11-x86_64.dll ps : php版本和xdeb ...