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
Apache spark Spark-如何使用数据帧Scala更新值_Apache Spark_Apache Spark Sql - Fatal编程技术网

Apache spark Spark-如何使用数据帧Scala更新值

Apache spark Spark-如何使用数据帧Scala更新值,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我有两个具有以下结构的文件 文件1 文件2 如果file1.gnk_id=file2.gnk_machid,我想用文件2中的matchid值更新文件1中的gnk_id值 为此,我在Spark中创建了两个数据帧。我想知道我们是否可以更新Spark中的值?如果没有,是否有任何解决方法可以提供更新的最终文件 更新 我做了这样的事 案例类GnkMatchIdgnk:String,gnk_matchid:String 案例类MatchGroupgnkid:String,matchid:String,ts:

我有两个具有以下结构的文件

文件1 文件2 如果file1.gnk_id=file2.gnk_machid,我想用文件2中的matchid值更新文件1中的gnk_id值

为此,我在Spark中创建了两个数据帧。我想知道我们是否可以更新Spark中的值?如果没有,是否有任何解决方法可以提供更新的最终文件

更新

我做了这样的事

案例类GnkMatchIdgnk:String,gnk_matchid:String 案例类MatchGroupgnkid:String,matchid:String,ts:String val gnkmatchidRDD=sc.textFile000000000001.map_u2;.split','.mapx=>x0,x1 val gnkmatchidDF=gnkmatchidd.map x=>GnkMatchIdx.\u 1,x.\u 2.toDF val matchGroupMr=sc.textFilepart-00000.map_uu.split','.mapx=>x0,x1,x2.map f=>MatchGroupf._1,f._2,f._3.toString.toDF val matchgrp_joinDF=matchGroupMr.joingnkmatchidDF,matchGroupMrgnkid==gnkmatchidDFgnk_matchid,左 matchgrp_joinDF.mapx=>ifx.getAs[String]gnk_matchid.length!=0{MatchGroupx.getAs[String]gnk_matchid,x.getAs[String]matchid,x.getAs[String]ts}其他{MatchGroupx.getAs[String]gnkid,x.getAs[String]matchid,x.getAs[String]ts}.toDF.show
但在最后一步,它的NULLpointerEXception失败了,这取决于您使用的数据源是否支持它

和你在一起。 使用该文件,您只需过滤掉行,进行更改并将其添加回。 希望能有所帮助

2018/04/11
更新链接。

这取决于您使用的数据源是否支持该链接

和你在一起。 使用该文件,您只需过滤掉行,进行更改并将其添加回。 希望能有所帮助

2018/04/11
更新链接。

这可能是您正在寻找的加入。假设在文件1和文件2中有数据帧,可以尝试以下操作:

val结果=文件1 .joinfile2,file1matchId==file2matchid 选择 colgnk_matchid.asgnk_id, 科尔马奇德, 时间戳
这可能是你正在寻找的一个加入。假设在文件1和文件2中有数据帧,可以尝试以下操作:

val结果=文件1 .joinfile2,file1matchId==file2matchid 选择 colgnk_matchid.asgnk_id, 科尔马奇德, 时间戳 DataFrame基于RDD,所以不能更新其中的值

但您可以使用column通过添加新列来更新值

在您的情况下,您可以通过使用UDF执行join和withColumn操作:

// df1: your File1
// +------+-------+---+
// |gnk_id|matchId| ts|
// +------+-------+---+
// |     1|     10|100|
// |     2|     20|200|
// +------+-------+---+

// df2: your File2
// +-----------+-------+
// |gnk_matchid|matchid|
// +-----------+-------+
// |          1|   1000|
// |          3|   3000|
// +-----------+-------+

// UDF: choose values from matchid or gnk_id for the new column
val myUDF = udf[Integer,Integer,Integer]((df2_matchid: Integer, df1_gnk_id: Integer) => {
  if (df2_matchid == null) df1_gnk_id
  else df2_matchid
})

df1.join(df2, $"gnk_id"===$"gnk_matchid", "left_outer")
  .select($"df1.*", $"df2.matchid" as "matchid2")
  .withColumn("gnk_id", myUDF($"matchid2", $"gnk_id"))
  .drop($"matchid2")
  .show()
以下是输出:

DataFrame基于RDD,所以不能更新其中的值

但您可以使用column通过添加新列来更新值

在您的情况下,您可以通过使用UDF执行join和withColumn操作:

// df1: your File1
// +------+-------+---+
// |gnk_id|matchId| ts|
// +------+-------+---+
// |     1|     10|100|
// |     2|     20|200|
// +------+-------+---+

// df2: your File2
// +-----------+-------+
// |gnk_matchid|matchid|
// +-----------+-------+
// |          1|   1000|
// |          3|   3000|
// +-----------+-------+

// UDF: choose values from matchid or gnk_id for the new column
val myUDF = udf[Integer,Integer,Integer]((df2_matchid: Integer, df1_gnk_id: Integer) => {
  if (df2_matchid == null) df1_gnk_id
  else df2_matchid
})

df1.join(df2, $"gnk_id"===$"gnk_matchid", "left_outer")
  .select($"df1.*", $"df2.matchid" as "matchid2")
  .withColumn("gnk_id", myUDF($"matchid2", $"gnk_id"))
  .drop($"matchid2")
  .show()
以下是输出:


最简单的实现方法是,下面的代码读取每个批次的维度数据文件夹,但请记住新维度数据值。在我的例子中,国家名称必须是一个新文件

下面是流+批连接的解决方案

package com.databroccoli.streaming.dimensionupateinstreaming

import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.{DataFrame, ForeachWriter, Row, SparkSession}
import org.apache.spark.sql.functions.{broadcast, expr}
import org.apache.spark.sql.types.{StringType, StructField, StructType, TimestampType}

object RefreshDimensionInStreaming {

  def main(args: Array[String]) = {

    @transient lazy val logger: Logger = Logger.getLogger(getClass.getName)

    Logger.getLogger("akka").setLevel(Level.WARN)
    Logger.getLogger("org").setLevel(Level.ERROR)
    Logger.getLogger("com.amazonaws").setLevel(Level.ERROR)
    Logger.getLogger("com.amazon.ws").setLevel(Level.ERROR)
    Logger.getLogger("io.netty").setLevel(Level.ERROR)

    val spark = SparkSession
      .builder()
      .master("local")
      .getOrCreate()

    val schemaUntyped1 = StructType(
      Array(
        StructField("id", StringType),
        StructField("customrid", StringType),
        StructField("customername", StringType),
        StructField("countrycode", StringType),
        StructField("timestamp_column_fin_1", TimestampType)
      ))

    val schemaUntyped2 = StructType(
      Array(
        StructField("id", StringType),
        StructField("countrycode", StringType),
        StructField("countryname", StringType),
        StructField("timestamp_column_fin_2", TimestampType)
      ))

    val factDf1 = spark.readStream
      .schema(schemaUntyped1)
      .option("header", "true")
      .csv("src/main/resources/broadcasttest/fact")

    var countryDf: Option[DataFrame] = None: Option[DataFrame]

    def updateDimensionDf() = {
      val dimDf2 = spark.read
        .schema(schemaUntyped2)
        .option("header", "true")
        .csv("src/main/resources/broadcasttest/dimension")

      if (countryDf != None) {
        countryDf.get.unpersist()
      }

      countryDf = Some(
        dimDf2
          .withColumnRenamed("id", "id_2")
          .withColumnRenamed("countrycode", "countrycode_2"))

      countryDf.get.show()
    }

    factDf1.writeStream
      .outputMode("append")
      .foreachBatch { (batchDF: DataFrame, batchId: Long) =>
        batchDF.show(10)

        updateDimensionDf()

        batchDF
          .join(
            countryDf.get,
            expr(
              """
      countrycode_2 = countrycode 
      """
            ),
            "leftOuter"
          )
          .show

      }
      .start()
      .awaitTermination()

  }

}

最简单的实现方法是,下面的代码读取每个批次的维度数据文件夹,但请记住新维度数据值。在我的例子中,国家名称必须是一个新文件

下面是流+批连接的解决方案

package com.databroccoli.streaming.dimensionupateinstreaming

import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.{DataFrame, ForeachWriter, Row, SparkSession}
import org.apache.spark.sql.functions.{broadcast, expr}
import org.apache.spark.sql.types.{StringType, StructField, StructType, TimestampType}

object RefreshDimensionInStreaming {

  def main(args: Array[String]) = {

    @transient lazy val logger: Logger = Logger.getLogger(getClass.getName)

    Logger.getLogger("akka").setLevel(Level.WARN)
    Logger.getLogger("org").setLevel(Level.ERROR)
    Logger.getLogger("com.amazonaws").setLevel(Level.ERROR)
    Logger.getLogger("com.amazon.ws").setLevel(Level.ERROR)
    Logger.getLogger("io.netty").setLevel(Level.ERROR)

    val spark = SparkSession
      .builder()
      .master("local")
      .getOrCreate()

    val schemaUntyped1 = StructType(
      Array(
        StructField("id", StringType),
        StructField("customrid", StringType),
        StructField("customername", StringType),
        StructField("countrycode", StringType),
        StructField("timestamp_column_fin_1", TimestampType)
      ))

    val schemaUntyped2 = StructType(
      Array(
        StructField("id", StringType),
        StructField("countrycode", StringType),
        StructField("countryname", StringType),
        StructField("timestamp_column_fin_2", TimestampType)
      ))

    val factDf1 = spark.readStream
      .schema(schemaUntyped1)
      .option("header", "true")
      .csv("src/main/resources/broadcasttest/fact")

    var countryDf: Option[DataFrame] = None: Option[DataFrame]

    def updateDimensionDf() = {
      val dimDf2 = spark.read
        .schema(schemaUntyped2)
        .option("header", "true")
        .csv("src/main/resources/broadcasttest/dimension")

      if (countryDf != None) {
        countryDf.get.unpersist()
      }

      countryDf = Some(
        dimDf2
          .withColumnRenamed("id", "id_2")
          .withColumnRenamed("countrycode", "countrycode_2"))

      countryDf.get.show()
    }

    factDf1.writeStream
      .outputMode("append")
      .foreachBatch { (batchDF: DataFrame, batchId: Long) =>
        batchDF.show(10)

        updateDimensionDf()

        batchDF
          .join(
            countryDf.get,
            expr(
              """
      countrycode_2 = countrycode 
      """
            ),
            "leftOuter"
          )
          .show

      }
      .start()
      .awaitTermination()

  }

}

您的第一个链接已失效,我还怀疑您是否可以在配置单元表上使用Spark SQL进行更新,因为有一个开放的票证支持配置单元事务表的更新:来自本书。配置单元解决方案只是将文件连接起来,而不会更改或更改记录。可以使用ORC格式和配置单元中的事务表以及insert、update、delete更新配置单元中的数据,它会定期自动为您进行连接。目前,这仅适用于orc格式的表。存储为orc的表也可以使用Hbase和Phoenix,因为顶部配置单元上的SQL层最初不是为更新而设计的,因为它纯粹是以仓库为中心的,最近的一个可以进行更新,以事务方式删除etc。确实可以使用配置单元以ORC格式对配置单元事务表进行更新。但是,Spark SQL不支持这一点:目前无法在配置单元事务表上使用Spark SQL进行更新,正如我提到的票证中所记录的,您的第一个链接已失效,而且我怀疑您是否可以在配置单元表上使用Spark SQL进行更新,因为存在支持配置单元事务表更新的开放票证:来自本书。配置单元解决方案只是将文件连接起来,而不会更改或更改记录。可以使用ORC格式和配置单元中的事务表以及insert、update、delete更新配置单元中的数据,它会定期自动为您进行连接。目前,这仅适用于orc格式的表。存储为orc格式的表也可以使用Hbase和Phoenix,因为顶部配置单元上的SQL层最初不是为更新而设计的,因为它纯粹是以仓库为中心的,最近的一个可以以事务方式进行更新、删除等。这确实是
可以使用配置单元以ORC格式对配置单元事务表进行更新。但是,Spark SQL不支持这一点:目前不可能在配置单元事务表上使用Spark SQL进行更新,正如我提到的票证中记录的,这里回答了类似的问题这里回答了类似的问题
package com.databroccoli.streaming.dimensionupateinstreaming

import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.{DataFrame, ForeachWriter, Row, SparkSession}
import org.apache.spark.sql.functions.{broadcast, expr}
import org.apache.spark.sql.types.{StringType, StructField, StructType, TimestampType}

object RefreshDimensionInStreaming {

  def main(args: Array[String]) = {

    @transient lazy val logger: Logger = Logger.getLogger(getClass.getName)

    Logger.getLogger("akka").setLevel(Level.WARN)
    Logger.getLogger("org").setLevel(Level.ERROR)
    Logger.getLogger("com.amazonaws").setLevel(Level.ERROR)
    Logger.getLogger("com.amazon.ws").setLevel(Level.ERROR)
    Logger.getLogger("io.netty").setLevel(Level.ERROR)

    val spark = SparkSession
      .builder()
      .master("local")
      .getOrCreate()

    val schemaUntyped1 = StructType(
      Array(
        StructField("id", StringType),
        StructField("customrid", StringType),
        StructField("customername", StringType),
        StructField("countrycode", StringType),
        StructField("timestamp_column_fin_1", TimestampType)
      ))

    val schemaUntyped2 = StructType(
      Array(
        StructField("id", StringType),
        StructField("countrycode", StringType),
        StructField("countryname", StringType),
        StructField("timestamp_column_fin_2", TimestampType)
      ))

    val factDf1 = spark.readStream
      .schema(schemaUntyped1)
      .option("header", "true")
      .csv("src/main/resources/broadcasttest/fact")

    var countryDf: Option[DataFrame] = None: Option[DataFrame]

    def updateDimensionDf() = {
      val dimDf2 = spark.read
        .schema(schemaUntyped2)
        .option("header", "true")
        .csv("src/main/resources/broadcasttest/dimension")

      if (countryDf != None) {
        countryDf.get.unpersist()
      }

      countryDf = Some(
        dimDf2
          .withColumnRenamed("id", "id_2")
          .withColumnRenamed("countrycode", "countrycode_2"))

      countryDf.get.show()
    }

    factDf1.writeStream
      .outputMode("append")
      .foreachBatch { (batchDF: DataFrame, batchId: Long) =>
        batchDF.show(10)

        updateDimensionDf()

        batchDF
          .join(
            countryDf.get,
            expr(
              """
      countrycode_2 = countrycode 
      """
            ),
            "leftOuter"
          )
          .show

      }
      .start()
      .awaitTermination()

  }

}