Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala/Spark DataFrame:连接行以在其内部获得一对_Scala_Apache Spark_Dataframe - Fatal编程技术网

Scala/Spark DataFrame:连接行以在其内部获得一对

Scala/Spark DataFrame:连接行以在其内部获得一对,scala,apache-spark,dataframe,Scala,Apache Spark,Dataframe,我正在尝试编写一个函数,它将按如下方式转换df->df2: // input dataframe df +-----+-----+ | T | S | +-----+-----+ | A| 4| | B| 8| | C| 8| | D| 2| +-----+-----+ 我需要一个将df作为输入并返回df2作为输出的函数 // output dataframe df2 +-----+-----+-----+ | T1 | T2 | S=T1+T2

我正在尝试编写一个函数,它将按如下方式转换df->df2:

// input dataframe df
+-----+-----+
|  T  |  S  |
+-----+-----+
|    A|   4|
|    B|   8|
|    C|   8|
|    D|   2|
+-----+-----+
我需要一个将
df
作为输入并返回
df2
作为输出的函数

// output dataframe df2
+-----+-----+-----+
| T1 | T2 | S=T1+T2 |
+-----+-----+-----+
|    A|    B|  12|
|    A|    C|  12|
|    A|    D|  6|
|    B|    C|  16|
|    B|    D|  10|
|    C|    D|  10|
+-----+-----+-----+
编辑 我想出了这个解决办法。任何改进都将受到欢迎

val sumOf = udf((left_score: Float, right_score: Float) => left_score + right_score)

val left = df.select("T", "S").withColumnRenamed("T", "T1").withColumnRenamed("S", "S1")
val right= df.select("T", "S").withColumnRenamed("T", "T2").withColumnRenamed("S", "S2")

val joinDF = left.join(right, left.col("T1") !== right.col("T2"))
val outDF = joinDF.withColumn("S", sumOf($"S1", $"S2")).select("T1", "T2", "S")
val-df=sc.parallelize(顺序(“A”->4,“B”->8,“C”->8,“D”->2))
.toDF(“T”、“S”)
val df1=df.withColumnRename(“T”、“T1”)
.改名为(“S”、“S1”)
val df2=df.withColumnRename(“T”、“T2”)
.以列重命名(“S”、“S2”)
df1.join(df2,df1(“T1”)
基本上你不想要一个完整的笛卡尔积。只有T2>T1的所有可能性。这就是连接条件在代码中的含义。请注意,笛卡尔积生成n²记录。在这里,您将生成n(n-1)/2条记录。这小于n²,但仍为O(n²),因此应尽可能避免

val-df=sc.parallelize(顺序(“A”->4,“B”->8,“C”->8,“D”->2))
.toDF(“T”、“S”)
val df1=df.withColumnRename(“T”、“T1”)
.改名为(“S”、“S1”)
val df2=df.withColumnRename(“T”、“T2”)
.以列重命名(“S”、“S2”)
df1.join(df2,df1(“T1”)

基本上你不想要一个完整的笛卡尔积。只有T2>T1的所有可能性。这就是连接条件在代码中的含义。请注意,笛卡尔积生成n²记录。在这里,您将生成n(n-1)/2条记录。这小于n²,但仍为O(n²),因此应尽可能避免

抛开性能不谈(提示:Spark不可能在大型笛卡尔产品上表现出色),您可以使用Spark 2.x中引入的交叉连接

import sc.implicits._

val df = sc.parallelize(Seq("A" -> 4, "B" -> 8, "C" -> 8, "D" -> 2))
         .toDF("T", "S")

df.as("df1")
  .crossJoin(df.as("df2"))
    .filter($"df1.T" =!= $"df2.T")
      .select($"df1.T".as("T1"), $"df2.T".as("T2"))
      .withColumn("S", $"df1.S"+$"df2.S") // you can use udf here as well
同样的结果也可以通过内部连接实现,这使得它与Spark 1.6.x兼容

import sc.implicits._

val df = sc.parallelize(Seq("A" -> 4, "B" -> 8, "C" -> 8, "D" -> 2))
         .toDF("T", "S")

df.as("df1")
  .join(df.as("df2"), Seq("T"), "inner") // this line is different
    .filter($"df1.T" =!= $"df2.T")
     .select($"df1.T".as("T1"), $"df2.T".as("T2"))
     .withColumn("S", $"df1.S"+$"df2.S") // you can use udf here as well

撇开性能不谈(提示:Spark不可能在大型笛卡尔产品上表现出色),您可以使用Spark 2.x中引入的交叉连接

import sc.implicits._

val df = sc.parallelize(Seq("A" -> 4, "B" -> 8, "C" -> 8, "D" -> 2))
         .toDF("T", "S")

df.as("df1")
  .crossJoin(df.as("df2"))
    .filter($"df1.T" =!= $"df2.T")
      .select($"df1.T".as("T1"), $"df2.T".as("T2"))
      .withColumn("S", $"df1.S"+$"df2.S") // you can use udf here as well
同样的结果也可以通过内部连接实现,这使得它与Spark 1.6.x兼容

import sc.implicits._

val df = sc.parallelize(Seq("A" -> 4, "B" -> 8, "C" -> 8, "D" -> 2))
         .toDF("T", "S")

df.as("df1")
  .join(df.as("df2"), Seq("T"), "inner") // this line is different
    .filter($"df1.T" =!= $"df2.T")
     .select($"df1.T".as("T1"), $"df2.T".as("T2"))
     .withColumn("S", $"df1.S"+$"df2.S") // you can use udf here as well

我建议的解决方案根本不需要您使用
join
。但该解决方案也很昂贵,因为所有数据都将累积到一个执行器中进行处理

我的解决方案是结合内置函数,如
数组
收集列表
分解
,以及
窗口
函数,如下所示

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions._

def windowFunction = Window.orderBy("T").rowsBetween(1, Long.MaxValue)

df.withColumn("array", collect_list(array($"T", $"S")).over(windowFunction))
    .withColumn("array", explode($"array"))
    .select($"T".as("T1"), $"array"(0).as("T2"), ($"array"(1)+$"S").as("S=T1+T2"))
  .show(false)
这将为您提供所需的输出

+---+---+-------+
|T1 |T2 |S=T1+T2|
+---+---+-------+
|A  |B  |12.0   |
|A  |C  |12.0   |
|A  |D  |6.0    |
|B  |C  |16.0   |
|B  |D  |10.0   |
|C  |D  |10.0   |
+---+---+-------+

我建议的解决方案根本不需要您使用
join
。但该解决方案也很昂贵,因为所有数据都将累积到一个执行器中进行处理

我的解决方案是结合内置函数,如
数组
收集列表
分解
,以及
窗口
函数,如下所示

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions._

def windowFunction = Window.orderBy("T").rowsBetween(1, Long.MaxValue)

df.withColumn("array", collect_list(array($"T", $"S")).over(windowFunction))
    .withColumn("array", explode($"array"))
    .select($"T".as("T1"), $"array"(0).as("T2"), ($"array"(1)+$"S").as("S=T1+T2"))
  .show(false)
这将为您提供所需的输出

+---+---+-------+
|T1 |T2 |S=T1+T2|
+---+---+-------+
|A  |B  |12.0   |
|A  |C  |12.0   |
|A  |D  |6.0    |
|B  |C  |16.0   |
|B  |D  |10.0   |
|C  |D  |10.0   |
+---+---+-------+

你有没有试过自己做这件事?笛卡尔乘积计算起来非常昂贵…所以你刚刚更改了标题,但它仍然是笛卡尔连接…我建议你发布你的编辑作为答案。你不会得到更好的答案,尽管你对答案仍然不满意。如果可能的话,需要一些改进。你自己有没有尝试过?笛卡尔乘积计算起来非常昂贵…所以你刚刚更改了标题,但它仍然是笛卡尔连接…我建议你发布你的编辑作为答案。你不会得到更好的答案,尽管你对答案仍然不满意。如果可能的话,需要一些改进。这无法扩展。Spark仍将检查T1是否小于T2。@eliasah评论不错,请查看最新编辑中的答案。如果可能的话,给出一些建议。不幸的是@SujitS如果你需要精确的值,你将需要笛卡尔坐标。事实上,你的问题是“如何制作笛卡尔积?”,这是不可能的。我们给了你一条路,告诉你它很贵。关于这一点,没有什么可说的了。。。然而,如果你告诉我们为什么要这样做,我们可能会找到一种方法来避免完全使用笛卡尔积;-)这我理解。不幸的是,你所描述的实际上是T列的笛卡尔积。我的问题是你想用这些数据做什么?如果您所要求的只是做其他事情的中间步骤,我们可能会帮助您更有效地实现最终目标。这不会扩大规模。Spark仍将检查T1是否小于T2。@eliasah评论不错,请查看最新编辑中的答案。如果可能的话,给出一些建议。不幸的是@SujitS如果你需要精确的值,你将需要笛卡尔坐标。事实上,你的问题是“如何制作笛卡尔积?”,这是不可能的。我们给了你一条路,告诉你它很贵。关于这一点,没有什么可说的了。。。然而,如果你告诉我们为什么要这样做,我们可能会找到一种方法来避免完全使用笛卡尔积;-)这我理解。不幸的是,你所描述的实际上是T列的笛卡尔积。我的问题是你想用这些数据做什么?如果您所要求的是做其他事情的中间步骤,我们可能会帮助您更有效地实现最终目标。