繁体   English   中英

使用 Apache Spark RDD map 方法(Java API)生成非列结果

[英]Using the Apache Spark RDD map method (Java API) to produce a non-columnar result

请注意:相信我在这里尝试使用 RDD map方法是正确的,但如果有另一种方法来完成我正在寻找的东西,我会全力以赴!


Spark 2.4.x 的全新版本,使用Java不是Scala)API。

我正试图围绕 RDD map(...)方法,特别是在Datasets上,而不仅限于 RDD。 官方文档中使用它的典型示例是:

public class GetLength implements Function<String, Integer> {
  public Integer call(String s) { return s.length(); }
}

JavaRDD<String> lines = sc.textFile("data.txt");
JavaRDD<Integer> lineLengths = lines.map(new GetLength());

因此,在这种情况下,似乎在创建 RDD lines之后,它有一个列(我不确定其名称),其中每列值是文件的不同行,并且 RDD 中的每一行也代表文件的不同行。 意思是, lines是一个nx1矩阵,其中n是文件中的行数/行数。

似乎当GetLength function 被执行时,它被输入每一行的唯一列作为输入字符串,并返回一个 integer 表示该字符串的行长度作为不同数据集中的新列值,这也是nx1 (只保存行长度信息而不是实际的行/字符串)。

好的,所以我得到了那个简单的例子。 但是,如果我们有nxm数据集,意思是很多行和很多列,并且我们想编写将它们转换为其他nxm数据集的函数怎么办?

例如,假设我有以下“输入”数据集:

+-------------------------+
| price | color | fizz    |
+-------------------------+
| 2.99  | red   | hallo   |
| 13.94 | blue  | yahtzee |
| 7.19  | red   | trueth  |
...
| 4.15  | green | whatevs |
+-------------------------+

其中price是数字/浮点类型,而colorfizz都是字符串。 所以这里我们有一个nx3形状的数据集; n行,每行总是 3 列。

我将如何编写一个 map function 也返回一个nx3数据集,具有相同的列/列名称/模式,但不同的值(基于函数)?

例如,假设我想要一个具有相同架构的新nx3数据集,但是如果行的color值等于字符串"red" ,那么将2.0添加到price列?

因此,使用上面的任意数据集,来自此 map function 的新数据集将如下所示:

+-------------------------+
| price | color | fizz    |
+-------------------------+
| 4.99  | red   | hallo   |  <== added 2.0 to price since color == "red"
| 13.94 | blue  | yahtzee |
| 9.19  | red   | trueth  |  <== added 2.0 to price since color == "red"
...
| 4.15  | green | whatevs |
+-------------------------+

很想做类似的事情:

public class UpdatedPriceForRedColors implements Function2<String, Double, Double> {
  public Double call(String color, Double currentPrice) {

    if ("red".equals(color) {
        return currentPrice + 2.0;
    } else {
        return currentPrice;
    }
  }
}

JavaRDD<Double> updatedPrices = myDS.map(new UpdatedPriceForRedColors());

但是,这里有几个问题:

  1. updatedPrices现在只是一个nx1数据集,由myDS中每一行的正确计算价格组成,而我想要具有相同price/color/fizz的东西,看起来像上面的第二个任意数据集
  2. UpdatedPriceForRedColors如何知道它的第一个字符串参数是color列,而不是fizz列?
  3. The Function API seems to only go up to either Function5 or Function6 (it's hard to discern what is available to the Java API and what is exclusive to the Scala API). 这意味着我只能编写包含 5 或 6 个 arguments 的函数,而我可能有包含 10 多列的数据集,我可能非常需要将这些列值中的大部分“注入”到 function 中,这样我就可以计算返回值新数据集的值。 在这种情况下,我有哪些选择?

首先,RDD 总是有一个column ,因为 RDD 没有模式信息,因此您与RDD<T>中的T类型相关联。

选项 1是使用Function<String,String>解析RDD<String> String的字符串,执行操作字符串中的内部元素的逻辑,并返回更新的字符串。

如果您希望您的RDD有一些架构信息,您可以使用RDD<Row> ,它可以让您访问Row中的单独元素(选项 2)

import org.apache.spark.sql.Row
JavaRDD<Row> rddRow = rddString.map(new Function<String, Row>() {
    @Override
    public Row call(String line) throws Exception {
      String[] parts = line.split("\\t");//tab separated values
      Row row = RowFactory.create(parts[0], parts[1], parts[2]);
      return row;
    }
  });

现在您可以 map 行:

RDD<Row> updatedRdd = rddRow.map(new Function<Row, Row>() {
    @Override
    public Row call(Row row) throws Exception {
      Float price = row.get(0);
      String color = row.get(1);
      //Your logic here          
      Row row = RowFactory.create(/* three elements here, or whatever*/);
      return row;
    }
  });

如果您进一步使用 go,则可以使用真正的数据集(如此所述)并利用数据帧/数据集 API (选项 3)

import org.apache.spark.sql.Row
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;

StructType schema = DataTypes.createStructType(
    new StructField[]{
            DataTypes.createStructField("price", FloatType, false),
            DataTypes.createStructField("color", StringType, false),
            DataTypes.createStructField("fizz", StringType, false)
    });


JavaRDD<Row> rddRow = rddString.map(new Function<String, Row>() {
    @Override
    public Row call(String line) throws Exception {
      String[] parts = line.split("\\t");//tab separated values
      Row row = RowFactory.create(parts[0], parts[1], parts[2]);
      return row;
    }
  });

DataFrame df = sqlContext.createDataFrame(rowRDD, schema);

拥有 dataframe 现在可以让您使用以下内容:

DataFrame df2 = df.withColumn("price", 
    when(col("color").equals("red"), col("price").add(2f))
        .otherwise(col("price")));

免责声明:我没有检查过 java 语法和 API,因为我已经习惯了 scala。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM