如何在Spark Scala数据帧中应用布尔索引?

如何在Spark Scala数据帧中应用布尔索引?,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有两个Spark Scala数据帧,我需要使用一个数据帧中的一个布尔列来过滤第二个数据帧。两个数据帧的行数相同 在熊猫中,我希望它是这样的: import pandas as pd df1 = pd.DataFrame({"col1": ["A", "B", "A", "C"], "boolean_column": [True, False, True, False]})

我有两个Spark Scala数据帧,我需要使用一个数据帧中的一个布尔列来过滤第二个数据帧。两个数据帧的行数相同

在熊猫中,我希望它是这样的:

import pandas as pd

df1 = pd.DataFrame({"col1": ["A", "B", "A", "C"], "boolean_column": [True, False, True, False]})
df2 = pd.DataFrame({"col1": ["Z", "X", "Y", "W"], "col2": [1, 2, 3, 4]})

filtered_df2 = df2[df1['boolean_column']]

// Expected filtered_df2 should be this:
// df2 = pd.DataFrame({"col1": ["Z", "Y"], "col2": [1, 3]})
如何以最节省时间的方式在Spark Scala中执行相同的操作

我目前的解决方案是将
“boolean_column”从
df1
添加到
df2
,然后过滤
df2
,只选择新添加列中具有
true
值的行,最后从
df2
中删除
“boolean_column”
,但我不确定这是最佳解决方案

如有任何建议,我们将不胜感激

编辑:

  • 预期输出是一个Spark Scala数据帧(不是列表或列),与第二个数据帧具有相同的模式,并且只有
    df2
    中满足
    df1
    的“布尔列”
    中的布尔掩码的行子集
  • 上面介绍的
    df2
    模式只是一个示例。我希望接收
    df2
    作为参数,具有任意数量的不同(且不固定)模式的列

您可以压缩
数据帧
并对这些元组进行过滤

val ints     = sparkSession.sparkContext.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
val bools    = sparkSession.sparkContext.parallelize(List(true, false, true, false, true, false, true, false, true, false))
val filtered = ints.zip(bools).filter { case (int, bool) => bool }.map { case (int, bool) => int }
println(filtered.collect().toList) //List(1, 3, 5, 7, 9)

我用以下代码解决了这个问题:

import org.apache.spark.sql.types.{LongType, StructField, StructType}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, Row, SQLContext, SparkSession}

val spark = SparkSession.builder().appName(sc.appName).master(sc.master).getOrCreate()
val sqlContext = spark.sqlContext


def addColumnIndex(df: DataFrame, sqlContext: SQLContext) = sqlContext.createDataFrame(
  // Add Column index
  df.rdd.zipWithIndex.map{case (row, columnindex) => Row.fromSeq(row.toSeq :+ columnindex)},
  // Create schema
  StructType(df.schema.fields :+ StructField("columnindex", LongType, nullable = false))
)

import spark.implicits._

val DF1 = Seq(
  ("A", true),
  ("B", false),
  ("A", true),
  ("C", false)
).toDF("col1", "boolean_column")

val DF2 = Seq(
  ("Z", 1),
  ("X", 2),
  ("Y", 3),
  ("W", 4)
).toDF("col_1", "col_2")

// Add index
val DF1WithIndex = addColumnIndex(DF1, sqlContext)
val DF2WithIndex = addColumnIndex(DF2, sqlContext)

// Join
val joinDF  = DF2WithIndex
  .join(DF1WithIndex, Seq("columnindex"))
  .drop("columnindex", "col1")

// Filter
val filteredDF2 = joinDF.filter(joinDF("boolean_column")).drop("boolean_column")
过滤后的数据帧将如下所示:

+-----+-----+
|col_1|col_2|
+-----+-----+
|    Z|    1|
|    Y|    3|
+-----+-----+

它们有共同的键连接在一起吗?否则,无法合并/加入数据帧。我建议过滤df1(仅保留
true
),然后使用
左半
连接我同意,如果没有连接条件,则无法保证两个表中的行将以相同的顺序连接否,数据集没有任何公共键,即使第一个数据集的每一行引用第二个数据集的每一行(第一行与第一行、第二行与第二行等),如果它们没有公共键,您如何知道
df1[row1]
对应于
df2[row1]
?每次加载两个数据集时,它们的顺序是否一致?一般来说,从一个数据集到另一个数据集使用/应用值的唯一方法是通过join,正如@RaphaelRoth已经提到的那样。如果两个数据集的顺序都是确定的,那么您可以使用类似于
rowNumber
的方法向两个数据集添加一个公共id,并最终将它们连接起来。正如您所说的,顺序是确定的这可以通过
ints.zip(bools)更简洁地完成。收集{case(int,bool)If bool=>int}
我对问题进行了编辑,对预期的输出和输入进行了一些额外的说明,因为建议的答案不会返回与
df2