DataSet API编程指南之Data Sources(三)
1、Data Source创建
Data Sources也就是数据来源的意思。数据源可以从文件或者Java集合中创建初始数据集。创建数据集的一般机制被抽象为InputFormat。Flink提供几种内置格式,可以从常见的文件格式创建数据集。这些文件格式在ExecutionEnvironment中都有相应的快捷创建方式。总的来说可以分为下面两大类:基于文件和基于集合两种方式。接下来,我们将对每一种Data Source创建方式进行介绍。
(1)基于文件的创建方式
readTextFile(path)
/TextInputFormat
- 按行读取文件,并将其以字符串的形式返回。readTextFileWithValue(path)
/TextValueInputFormat
- 按行读取文件,并以StringValues的形式返回。StringValues是可变字符串。readCsvFile(path)
/CsvInputFormat
-解析以逗号(或其他字符)分隔的字段的文件。返回tuples, case class objects, or POJOs。支持基本的java类型及其对应值作为字段类型。readFileOfPrimitives(path, delimiter)
/PrimitiveInputFormat
- 使用给定的分隔符解析文件。文件是由新行(或者其他字符序列)分隔的原始数据类型,例如string,Integer。readSequenceFile(Key, Value, path)
/SequenceFileInputFormat
- 创建一个JobConf ,从指定的路径读取类型为SequenceFileInputFormat、Key类和Value类的文件,并以Tuple2的形式返回它们。
(2)基于集合的创建方式(常用于学习、测试)
fromCollection(Iterable)
- 从可迭代集合中创建数据集。从Iterable 中返回的所有元素必须是相同的类型。fromCollection(Iterator)
- 从迭代器中创建数据集。Class指定迭代器返回的元素的数据类型。fromElements(elements: _*)
- 根据给定的对象序列创建数据集。所有对象必须具有相同的类型。fromParallelCollection(SplittableIterator)
- 并行地从迭代器创建数据集。Class指定迭代器返回的元素的数据类型。generateSequence(from, to)
- 在给定区间内的数字序列创建并行数据集。
(3)使用介绍
val env = ExecutionEnvironment.getExecutionEnvironment
// 读取本地文件
val localLines = env.readTextFile("file:///path/to/my/textfile")
// 读取HDFS文件 nnHost:nnPort
val hdfsLines = env.readTextFile("hdfs://nnHost:nnPort/path/to/my/textfile")
// 读取CSV文件,包含3个字段
val csvInput = env.readCsvFile[(Int, String, Double)]("hdfs:///the/CSV/file")
// 读取CSV文件(包含5个字段), 但是,只读取其中的两个
val csvInput = env.readCsvFile[(String, Double)](
"hdfs:///the/CSV/file",
includedFields = Array(0, 3)) // take the first and the fourth field
// 以Case Classes形式读取CSV文件
case class MyCaseClass(str: String, dbl: Double)
val csvInput = env.readCsvFile[MyCaseClass](
"hdfs:///the/CSV/file",
includedFields = Array(0, 3)) // take the first and the fourth field
// 将具有三个字段的CSV文件读入具有相应字段的POJO (Person)
val csvInput = env.readCsvFile[Person](
"hdfs:///the/CSV/file",
pojoFields = Array("name", "age", "zipcode"))
// 通过给定的元素创建DataSet
val values = env.fromElements("Foo", "bar", "foobar", "fubar")
// 从序列中创建DataSet
val numbers = env.generateSequence(1, 10000000)
// 从指定的路径读取类型SequenceFileInputFormat的文件
val tuples = env.createInput(HadoopInputs.readSequenceFile(classOf[IntWritable], classOf[Text],
"hdfs://nnHost:nnPort/path/to/file"))
2、配置CSV解析参数
Flink为CSV解析提供了许多配置选项:
lineDelimiter: String
指定每条记录的分隔符,默认的行分隔符是'\n'
.fieldDelimiter: String
指定每条记录字段的分隔符。默认的字段分隔符是','
.includeFields: Array[Int]
Array[Int]定义了从输入文件中读取(忽略)哪些字段。默认情况下,解析前n个字段(由types()调用中的类型数量定义,也就是readCsvFile[types()])。pojoFields: Array[String]
指定映射到CSV字段的POJO字段。CSV字段的解析器将根据POJO字段的类型和顺序自动初始化。parseQuotedStrings: Character
启用引用字符串解析。如果字符串字段的第一个字符是引号字符,则字符串被解析为带引号的字符串(前导或尾的空格不被修剪)。引用字符串中的字段分隔符将被忽略。如果引号字符串字段的最后一个字符不是引号字符,则引号字符串解析失败。如果启用了带引号的字符串解析,并且字段的第一个字符是非带引号的字符串,则该字符串将解析为非带引号的字符串。默认情况下,引用的字符串解析是禁用的。ignoreComments: String
指定注释前缀。所有以指定注释前缀开头的行都不会被解析和忽略。默认情况下,不忽略任何行。lenient: Boolean
支持宽松的解析。例如,忽略不能正确解析的行。默认情况下,宽松的解析是禁用的,无效的行会引发异常。ignoreFirstLine: Boolean
配置InputFormat以忽略输入文件的第一行。默认情况下不忽略任何行。
3、递归读取输入路径下的文件
对于基于文件的输入,当输入路径是文件夹时,内层文件默认情况下是不会遍历读取的,只会读取根目录下的文件,而忽略嵌套文件夹下的文件。可以通过配置recursive.file.enumeration
参数,递归遍历嵌套文件夹下的文件。
// enable recursive enumeration of nested input files
val env = ExecutionEnvironment.getExecutionEnvironment
// create a configuration object
val parameters = new Configuration
// set the recursive enumeration parameter
parameters.setBoolean("recursive.file.enumeration", true)
// pass the configuration to the data source
env.readTextFile("file:///path/with.nested/files").withParameters(parameters)
4、读取压缩文件内容
如果压缩文件使用适当的文件扩展名进行标记,Flink目前支持对输入文件的透明解压。尤其是,不需要对输入格式做进一步的配置,并且任何FileInputFormat
支持压缩,包括自定义输入格式。注意,压缩文件可能不会并行读取,从而影响作业的可伸缩性。
下表列出了当前flink支持的压缩方法。
压缩方法 | 文件后缀 | 可并行 |
---|---|---|
DEFLATE | .deflate | no |
GZip | .gz , .gzip | no |
Bzip2 | .bz2 | no |
XZ | .xz | no |
因此,不论是压缩的文件还是普通的文件,都可以通过基于文件的方法读取数据,从而创建DataSet。压缩在实际生产中,是较为常用的措施,尤其是在大数据应用中。压缩能够带来空间的节省,磁盘IO,网络传输IO的性能提升。但是压缩文件是需要耗费CPU资源的。