【问题标题】:Convert collect-map-foreach scala code block to spark/sql library functions将 collect-map-foreach scala 代码块转换为 spark/sql 库函数
【发布时间】:2021-11-25 18:34:33
【问题描述】:

我有一个 spark 数据框(我们称之为“记录”),如下所示:

id name
a1 john
b"2 alice
c3' joe

如果您注意到,主键列 (id) 值中可能包含单引号/双引号(如数据框中的第二行和第三行)。

我编写了以下 scala 代码来检查主键列值中的引号:

def checkForQuotesInPrimaryKeyColumn(primaryKey: String, records: DataFrame): Boolean = {
  // Extract primary key column values
  val pkcValues = records.select(primaryKey).collect().map(_(0)).toList
  // Check for single and double quotes in the values
  var checkForQuotes = false // indicates no quotes
  breakable {
    pkcValues.foreach(pkcValue => {
    if (pkcValue.toString.contains("\"") || pkcValue.toString.contains("\'")) {
      checkForQuotes = true
      println("Value that has quotes: " + pkcValue.toString)
      break()
    }
  })}
  checkForQuotes
}

此代码有效。但它没有利用火花功能。我希望使用能够更快完成此任务的 spark 执行器(和其他功能)。

更新后的函数如下所示:

def checkForQuotesInPrimaryKeyColumnsUpdated(primaryKey: String, records: DataFrame): Boolean = {
  val findQuotes = udf((s: String) => if (s.contains("\"") || s.contains("\'")) true else false)
  records
    .select(findQuotes(col(primaryKey)) as "quotes")
    .filter(col("quotes") === true)
    .collect()
    .nonEmpty
}

当在具有 100 个条目的数据帧上运行时,单元测试在我的机器上为这两个函数提供了相似的运行时间。

更新后的功能是否比原始功能更快(和/或更好)?有什么方法可以改进功能吗?

【问题讨论】:

    标签: scala apache-spark apache-spark-sql


    【解决方案1】:

    您的第一种方法将整个数据帧收集到驱动程序。如果您的数据不适合驱动程序的内存,它将中断。你也是对的,你没有利用火花。

    第二种方法使用 spark 检测引号。这样更好。问题是您随后收集了一个数据帧,其中每条记录包含一个布尔值,其中包含对驱动程序的引用,只是为了查看是否至少有一个。这是浪费时间,尤其是在许多记录包含引号的情况下。为此使用 UDF 也是一种耻辱,因为已知它们比 spark SQL 原语慢。

    您可以简单地使用 spark 来计算包含报价的记录数,而无需收集任何内容。

    records.where(col(primaryKey).contains("\"") || col(primaryKey).contains("'"))
         .count > 0
    

    因为,您实际上并不关心记录的数量。您只想检查是否至少有一个,您可以使用limit(1)。 SparkSQL 将能够进一步优化查询:

    records.where(col(primaryKey).contains("\"") || col(primaryKey).contains("'"))
        .limit(1).count > 0
    

    注意:在单元测试中,使用少量数据,您的两个查询花费相同的时间是有道理的。 Spark 适用于大数据并且有一些开销。使用真实数据,您的第二种方法应该比第一种方法更快,而且我建议的方法也是如此。此外,您的第一种方法会在您添加更多数据后立即在驱动程序上获得 OOM。

    【讨论】:

    • 谢谢你,奥利!
    猜你喜欢
    • 2023-02-02
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-09-05
    • 2018-03-31
    • 2017-05-20
    • 1970-01-01
    相关资源
    最近更新 更多