【发布时间】:2016-10-14 21:32:20
【问题描述】:
我想通过将一个巨大的 csv 文件细分为不同的分区来优化 Spark 应用程序的运行时间,具体取决于它们的特性。
例如我有一列带有客户 ID(整数,a),一列带有日期(月 + 年,例如 01.2015,b),以及带有产品 ID(整数,c)的列(以及更多带有产品特定数据的列,不需要用于分区)。
我想建立一个像/customer/a/date/b/product/c 这样的文件夹结构。当用户想了解客户 X 于 2016 年 1 月售出的产品信息时,他可以加载并分析保存在/customer/X/date/01.2016/* 中的文件。
是否可以通过通配符加载此类文件夹结构?还应该可以加载特定时间范围内的所有客户或产品,例如01.2015 至 09.2015。是否可以使用像/customer/*/date/*.2015/product/c 这样的通配符?或者这样的问题怎么解决?
我想对数据进行一次分区,然后在分析中加载特定文件,以减少这些作业的运行时间(忽略分区的额外工作)。
解决方案:使用 Parquet 文件
我更改了我的 Spark 应用程序以将我的数据保存到 Parquet 文件中,现在一切正常,我可以通过提供文件夹结构来预先选择数据。这是我的代码sn-p:
JavaRDD<Article> goodRdd = ...
SQLContext sqlContext = new SQLContext(sc);
List<StructField> fields = new ArrayList<StructField>();
fields.add(DataTypes.createStructField("keyStore", DataTypes.IntegerType, false));
fields.add(DataTypes.createStructField("textArticle", DataTypes.StringType, false));
StructType schema = DataTypes.createStructType(fields);
JavaRDD<Row> rowRDD = goodRdd.map(new Function<Article, Row>() {
public Row call(Article article) throws Exception {
return RowFactory.create(article.getKeyStore(), article.getTextArticle());
}
});
DataFrame storeDataFrame = sqlContext.createDataFrame(rowRDD, schema);
// WRITE PARQUET FILES
storeDataFrame.write().partitionBy(fields.get(0).name()).parquet("hdfs://hdfs-master:8020/user/test/parquet/");
// READ PARQUET FILES
DataFrame read = sqlContext.read().option("basePath", "hdfs://hdfs-master:8020/user/test/parquet/").parquet("hdfs://hdfs-master:8020/user/test/parquet/keyStore=1/");
System.out.println("READ : " + read.count());
重要
不要尝试只有一列的表格!当您尝试调用partitionBy 方法时,您将得到异常!
【问题讨论】:
-
你不能为 hdfs 路径创建配置单元表吗? hive 表支持动态分区和静态分区。使用数据框,您可以根据需要查询数据。
-
@RamPrasadG 您不需要创建配置单元表。 Spark 可以很好地做到这一点。无论如何,也许我会回答这个问题;)
-
@GlennieHellesSindholt:也就是说,Spark 可以解释像“/customer/*/date/*/products/123”这样的路径?
-
与调用一些过滤器转换相比,ist 在运行时是否有很大的不同?
-
@D.Müller ehm,我的回答是您想要的吗?如果是,您能否将其标记为已回答?如果不是,您能否具体说明问题?
标签: apache-spark hdfs wildcard