Scala 遍历DataFrame中的行并将其转换为多行

Scala 遍历DataFrame中的行并将其转换为多行,scala,apache-spark,dataframe,Scala,Apache Spark,Dataframe,作为scala中的一个例子,我有一个列表,每个项目都与我希望出现两次的条件相匹配(可能不是这个用例的最佳选项,但这一点很重要): 我想在Spark中做一些类似的事情——迭代数据帧中的行,如果一行匹配某个条件,那么我需要在副本中进行一些修改来复制该行。如何做到这一点 例如,如果我的输入是下表: | name | age | |-------|-----| | Peter | 50 | | Paul | 60 | | Mary | 70 | 我希望遍历该表,并针对多个条件测试每一行,对

作为scala中的一个例子,我有一个列表,每个项目都与我希望出现两次的条件相匹配(可能不是这个用例的最佳选项,但这一点很重要):

我想在Spark中做一些类似的事情——迭代数据帧中的行,如果一行匹配某个条件,那么我需要在副本中进行一些修改来复制该行。如何做到这一点

例如,如果我的输入是下表:

| name  | age |
|-------|-----|
| Peter | 50  |
| Paul  | 60  |
| Mary  | 70  |
我希望遍历该表,并针对多个条件测试每一行,对于匹配的每个条件,应使用匹配条件的名称创建一个条目


例如,条件#1是“年龄>60岁”,条件#2是“姓名.长度这里有一种方法可以使用
rdd.flatMap将其展平:

import org.apache.spark.sql.types._
import org.apache.spark.sql.Row

val new_rdd = (df.rdd.flatMap(r => {
    val conditions = Seq((1, r.getAs[Int](1) > 60), (2, r.getAs[String](0).length <= 4))
    conditions.collect{ case (i, c) if c => Row.fromSeq(r.toSeq :+ i) }
}))

val new_schema = StructType(df.schema :+ StructField("condition", IntegerType, true))

spark.createDataFrame(new_rdd, new_schema).show
+----+---+---------+
|name|age|condition|
+----+---+---------+
|Paul| 60|        2|
|Mary| 70|        1|
|Mary| 70|        2|
+----+---+---------+
import org.apache.spark.sql.types_
导入org.apache.spark.sql.Row
val new_rdd=(df.rdd.flatMap(r=>{
val conditions=Seq((1,r.getAs[Int](1)>60),(2,r.getAs[String](0).行长.fromSeq(r.toSeq:+i)}
}))
val new_schema=StructType(df.schema:+StructField(“条件”,IntegerType,true))
createDataFrame(新的\ rdd,新的\模式).show
+----+---+---------+
|姓名|年龄|状况|
+----+---+---------+
|保罗| 60 | 2|
|玛丽| 70 | 1|
|玛丽| 70 | 2|
+----+---+---------+

这里有一种使用rdd.flatMap将其展平的方法:

import org.apache.spark.sql.types._
import org.apache.spark.sql.Row

val new_rdd = (df.rdd.flatMap(r => {
    val conditions = Seq((1, r.getAs[Int](1) > 60), (2, r.getAs[String](0).length <= 4))
    conditions.collect{ case (i, c) if c => Row.fromSeq(r.toSeq :+ i) }
}))

val new_schema = StructType(df.schema :+ StructField("condition", IntegerType, true))

spark.createDataFrame(new_rdd, new_schema).show
+----+---+---------+
|name|age|condition|
+----+---+---------+
|Paul| 60|        2|
|Mary| 70|        1|
|Mary| 70|        2|
+----+---+---------+
import org.apache.spark.sql.types_
导入org.apache.spark.sql.Row
val new_rdd=(df.rdd.flatMap(r=>{
val conditions=Seq((1,r.getAs[Int](1)>60),(2,r.getAs[String](0).行长.fromSeq(r.toSeq:+i)}
}))
val new_schema=StructType(df.schema:+StructField(“条件”,IntegerType,true))
createDataFrame(新的\ rdd,新的\模式).show
+----+---+---------+
|姓名|年龄|状况|
+----+---+---------+
|保罗| 60 | 2|
|玛丽| 70 | 1|
|玛丽| 70 | 2|
+----+---+---------+

您还可以结合使用UDF和
explode()
,如以下示例所示:

// set up example data
case class Pers1 (name:String,age:Int)
val d = Seq(Pers1("Peter",50), Pers1("Paul",60), Pers1("Mary",70))
val df = spark.createDataFrame(d)

// conditions logic - complex as you'd like
// probably should use a Set instead of Sequence but I digress..
val conditions:(String,Int)=>Seq[Int] =  { (name,age) => 
    (if(age > 60) Seq(1) else Seq.empty) ++ 
    (if(name.length <=4) Seq(2) else Seq.empty)  
}
// define UDF for spark
import org.apache.spark.sql.functions.udf
val conditionsUdf = udf(conditions)
// explode() works just like flatmap
val result  = df.withColumn("condition", 
   explode(conditionsUdf(col("name"), col("age"))))
result.show

+----+---+---------+
|name|age|condition|
+----+---+---------+
|Paul| 60|        2|
|Mary| 70|        1|
|Mary| 70|        2|
+----+---+---------+
//设置示例数据
案例类Pers1(名称:String,年龄:Int)
val d=序号(第1人称(“彼得”,50岁)、第1人称(“保罗”,60岁)、第1人称(“玛丽”,70岁))
val df=spark.createDataFrame(d)
//条件逻辑-如您所愿复杂
//可能应该使用集合而不是序列,但我离题了。。
val条件:(String,Int)=>Seq[Int]={(姓名,年龄)=>
(如果(年龄>60岁)序号(1)否则序号为空)+

(如果(name.length您也可以使用UDF和
explode()
的组合,如以下示例所示:

// set up example data
case class Pers1 (name:String,age:Int)
val d = Seq(Pers1("Peter",50), Pers1("Paul",60), Pers1("Mary",70))
val df = spark.createDataFrame(d)

// conditions logic - complex as you'd like
// probably should use a Set instead of Sequence but I digress..
val conditions:(String,Int)=>Seq[Int] =  { (name,age) => 
    (if(age > 60) Seq(1) else Seq.empty) ++ 
    (if(name.length <=4) Seq(2) else Seq.empty)  
}
// define UDF for spark
import org.apache.spark.sql.functions.udf
val conditionsUdf = udf(conditions)
// explode() works just like flatmap
val result  = df.withColumn("condition", 
   explode(conditionsUdf(col("name"), col("age"))))
result.show

+----+---+---------+
|name|age|condition|
+----+---+---------+
|Paul| 60|        2|
|Mary| 70|        1|
|Mary| 70|        2|
+----+---+---------+
//设置示例数据
案例类Pers1(名称:String,年龄:Int)
val d=序号(第1人称(“彼得”,50岁)、第1人称(“保罗”,60岁)、第1人称(“玛丽”,70岁))
val df=spark.createDataFrame(d)
//条件逻辑-如您所愿复杂
//可能应该使用集合而不是序列,但我离题了。。
val条件:(String,Int)=>Seq[Int]={(姓名,年龄)=>
(如果(年龄>60岁)序号(1)否则序号为空)+

(如果(name.length您可以
过滤
匹配条件
数据帧
,然后最后
联合
所有条件

import org.apache.spark.sql.functions._
val condition1DF = df.filter($"age" > 60).withColumn("condition", lit(1))
val condition2DF = df.filter(length($"name") <= 4).withColumn("condition", lit(2))

val finalDF = condition1DF.union(condition2DF)

我希望答案是有帮助的

您可以
筛选
匹配条件
数据帧
,然后最后
合并
所有这些条件

import org.apache.spark.sql.functions._
val condition1DF = df.filter($"age" > 60).withColumn("condition", lit(1))
val condition2DF = df.filter(length($"name") <= 4).withColumn("condition", lit(2))

val finalDF = condition1DF.union(condition2DF)

我希望答案是有帮助的

你也应该能够用
flatMap
来做。你能展示一些实际的数据吗?添加了一些示例以使其更清晰。如果你想把行放到
name.length>4
,如果
age>60
但也
name.length>4
,你还需要条件列吗?应该有对于行匹配的每个条件,都是结果表中的一个条目。如果没有匹配项,则没有条目,多个匹配项意味着多个entries。您应该也可以使用
flatMap
执行此操作。您可以显示一些实际数据吗?添加示例以使其更清晰。是否要将行放到
name.length>4
的位置,如果
age>60
但也
name.length>4
?您还需要条件列吗?对于行匹配的每个条件,结果表中都应该有一个条目。如果没有匹配,那么没有条目,多个匹配意味着多个entries为什么使用
flatMap
?@JacekLaskowski如果我不使用
rdd
,我会出错。找不到编码器…@Psidom尝试导入spark.implicits.\u
,有了它,你应该可以在数据帧上使用
flatMap
spark
这里是
SparkSession
。你为什么
df.rdd
要使用
flatMap
如果我不使用
rdd
,就会出错。找不到编码器…@Psidom请尝试导入spark.implicits.\u
,使用它,您应该能够在数据帧上使用
flatMap
spark
这是
SparkSession
。谢谢,这个解决方案给了我最大的灵活性,并且非常适合多种情况,谢谢从配置读取的条件,多表等等。这个解决方案给了我最大的灵活性,非常适合于多个条件,从配置读取的条件,多表等等