Dataframe 使用数据帧在Spark中使用数据差异(增量)

Dataframe 使用数据帧在Spark中使用数据差异(增量),dataframe,apache-spark,hadoop,bigdata,parquet,Dataframe,Apache Spark,Hadoop,Bigdata,Parquet,我在hdfs中有一个拼花文件作为数据的初始加载。接下来的所有拼花只是这些数据集,这些数据集每天都会更改为初始荷载(按时间顺序)。这是我的三角洲。 我想读取所有或几个拼花地板文件,以获得特定日期的最新数据。增量也可以包含新记录 例如: 初始数据(文件夹:/path/spezific_Data/20180101): ID| Name | Street | 1 | "Tom" |"Street 1"| 2 | "Peter"|"Street 2"| ID| Name | Street

我在hdfs中有一个拼花文件作为数据的初始加载。接下来的所有拼花只是这些数据集,这些数据集每天都会更改为初始荷载(按时间顺序)。这是我的三角洲。 我想读取所有或几个拼花地板文件,以获得特定日期的最新数据。增量也可以包含新记录

例如:

初始数据(文件夹:/path/spezific_Data/20180101):

ID| Name  | Street    | 
1 | "Tom" |"Street 1"| 
2 | "Peter"|"Street 2"|
ID| Name  | Street    | 
1 | "Tom" |"Street 21"| 
ID| Name  | Street    | 
2 | "Peter" |"Street 44"|
3 | "Hans" | "Street 12"|
ID| Name  | Street    | 
2 | "Hans" |"Street 55"|
Delta 1(文件夹:/path/spezific_data/20180102):

ID| Name  | Street    | 
1 | "Tom" |"Street 1"| 
2 | "Peter"|"Street 2"|
ID| Name  | Street    | 
1 | "Tom" |"Street 21"| 
ID| Name  | Street    | 
2 | "Peter" |"Street 44"|
3 | "Hans" | "Street 12"|
ID| Name  | Street    | 
2 | "Hans" |"Street 55"|
Delta 2(文件夹::/path/spezific_data/20180103):

ID| Name  | Street    | 
1 | "Tom" |"Street 1"| 
2 | "Peter"|"Street 2"|
ID| Name  | Street    | 
1 | "Tom" |"Street 21"| 
ID| Name  | Street    | 
2 | "Peter" |"Street 44"|
3 | "Hans" | "Street 12"|
ID| Name  | Street    | 
2 | "Hans" |"Street 55"|
Delta 3(文件夹::/path/spezific_data/20180105):

ID| Name  | Street    | 
1 | "Tom" |"Street 1"| 
2 | "Peter"|"Street 2"|
ID| Name  | Street    | 
1 | "Tom" |"Street 21"| 
ID| Name  | Street    | 
2 | "Peter" |"Street 44"|
3 | "Hans" | "Street 12"|
ID| Name  | Street    | 
2 | "Hans" |"Street 55"|
可能某一天有增量,但在第二天加载。(看看Delta 2和Delta 3) 所以文件夹/path/spezific_data/20180104确实存在,我们永远不想加载这个日期。 现在我想加载不同的案例

  • 仅初始数据: 这是一个简单的目录加载
  • 直到特定日期(20180103)
  • 现在我必须合并(“更新”我知道spark RDD或dataframes无法进行更新)这些数据集,并将另一个数据集也合并。目前,我用这行代码(但在for循环中)解决了这个问题:

    new_df=delta_df.union(initila_df).dropDuplicates(“ID”)
    delta_df=spark.read.parqeut(“hdfs:/mypath/20180103/”)
    new_df=delta_df.union(new_df).dropDuplicates(“ID”)
    但我认为这不是一个好办法

  • 加载文件夹“/path/spezific_data”中的所有数据 我这样做就像第一步一样,用for循环到最晚的日期
  • 问题: 我可以这样做吗? 有更好的方法吗? 我可以把它加载到一个df中并合并到那里吗
    当前加载时间很长(一小时)

    更新1:
    我试着做这样的事。如果我运行此代码,它将遍历所有日期,直到我的enddate(我在println(date)上看到)。之后,我得到一个Java.lang.StackOverflower错误。 错误在哪里

    import org.apache.spark.sql.functions.col
    import util.control.Breaks._
    
    var sourcePath = "hdfs:sourceparth/"
    var destinationPath = "hdfs:destiantionpath/result"
    var initial_date = "20170427"
    var start_year = 2017
    var end_year = 2019
    var end_month = 10
    var end_day = 31
    
    var m : String = _
    var d : String = _
    var date : String = _
    var delta_df : org.apache.spark.sql.DataFrame = _
    var doubleRows_df : org.apache.spark.sql.DataFrame = _
    
    //final DF, initial load
    var final_df = spark.read.parquet(sourcePath + initial_date +  "*")
    
    breakable{
       for(year <- 2017 to end_year; month <- 1 to 12; day <- 1 to 31){
         //Create date String
         m = month.toString()
         d = day.toString()
         if(month < 10)
           m = "0" + m
         if(day < 10)
           d = "0" + d
         date = year.toString() + m + d
    
         try{
           //one delta
           delta_df = spark.read.parquet(sourcePath + date + "*")
    
           //delete double Rows (i want to ignore them
           doubleRows_df  = delta_df.groupBy("key").count().where("count > 1").select("key")
           delta_df = delta_df.join(doubleRows_df, Seq("key"), "leftanti")
    
           //deletes all (old) rows in final_df, that are in delta_df
           final_df = final_df.join(delta_df, Seq("key"), "leftanti")
    
           //add all new rows in delta
           final_df = final_df.union(delta_df)
    
           println(date)
         }catch{
           case e:org.apache.spark.sql.AnalysisException=>{}
         }
        if(day == end_day && month == end_month &&  year == end_year)
           break
       }
     }
     final_df.write.mode("overwrite").parquet(destinationPath)
    
    import org.apache.spark.sql.functions.col
    导入util.control.Breaks_
    var sourcePath=“hdfs:sourceparth/”
    var destinationPath=“hdfs:destinationPath/result”
    风险值初始日=“20170427”
    风险值起始年=2017年
    var年末=2019年
    月底风险值=10
    var结束日=31
    变量m:String=_
    变量d:字符串=_
    变量日期:字符串=_
    var delta_df:org.apache.spark.sql.DataFrame=_
    var doubleRows_df:org.apache.spark.sql.DataFrame=_
    //最终DF,初始荷载
    var final\u df=spark.read.parquet(源路径+初始日期+“*”)
    易碎的{
    年
    
  • distinct
    dropDuplicates
    不是一个选项,因为您无法控制将采用哪些值。很可能发生的情况是,不会添加新值,而保留旧值
  • 您需要在
    ID
    上执行
    join
    操作-请参见连接类型。然后,连接的行应仅包含旧的、或仅包含新的或两者都包含。当仅包含旧的或仅包含新的行时,您将获取当前的行,当两者都包含时,您将仅获取新的行
  • 如何一次添加多个增量的示例

    问题:在每个类别中,什么是最畅销和第二畅销的产品

    val dataset = Seq(
      ("Thin",       "cell phone", 6000),
      ("Normal",     "tablet",     1500),
      ("Mini",       "tablet",     5500),
      ("Ultra thin", "cell phone", 5000),
      ("Very thin",  "cell phone", 6000),
      ("Big",        "tablet",     2500),
      ("Bendable",   "cell phone", 3000),
      ("Foldable",   "cell phone", 3000),
      ("Pro",        "tablet",     4500),
      ("Pro2",       "tablet",     6500))
      .toDF("product", "category", "revenue")
    
    val overCategory = Window.partitionBy('category).orderBy('revenue.desc)
    
    val ranked = data.withColumn("rank", dense_rank.over(overCategory))
    
    scala> ranked.show
    +----------+----------+-------+----+
    |   product|  category|revenue|rank|
    +----------+----------+-------+----+
    |      Pro2|    tablet|   6500|   1|
    |      Mini|    tablet|   5500|   2|
    |       Pro|    tablet|   4500|   3|
    |       Big|    tablet|   2500|   4|
    |    Normal|    tablet|   1500|   5|
    |      Thin|cell phone|   6000|   1|
    | Very thin|cell phone|   6000|   1|
    |Ultra thin|cell phone|   5000|   2|
    |  Bendable|cell phone|   3000|   3|
    |  Foldable|cell phone|   3000|   3|
    +----------+----------+-------+----+
    
    scala> ranked.where('rank <= 2).show
    +----------+----------+-------+----+
    |   product|  category|revenue|rank|
    +----------+----------+-------+----+
    |      Pro2|    tablet|   6500|   1|
    |      Mini|    tablet|   5500|   2|
    |      Thin|cell phone|   6000|   1|
    | Very thin|cell phone|   6000|   1|
    |Ultra thin|cell phone|   5000|   2|
    +----------+----------+-------+----+
    
    有关更多详细信息,请参阅


    第二-请发布完整的stacktrace,而不仅仅是
    StackOverflowException

    您是否仅限于spark?您描述的用例几乎适用于HBase或其他数据库。这是我的任务。我被告知要使用spark执行此操作。我是这个BigData上下文中的新手。我的第一步是使用spark执行此操作。在此之后,我还可以使用其他技术可以做到这一点,但我如何才能仅使用联接获取特定日期的数据帧?如果初始日期为20180101,我希望加载到20180101,这是31个文件夹。我必须加载31次do 31联接吗?或者我可以加载initial和一个delta。然后在initial中删除所有键,它们位于delta和dann Union initial和delta中?要知道该日期-您需要有一个指定日期的列。例如,您可以在从名称读取数据后进行设置。对于加载多个增量,我认为您有几种方法。一种方法是逐个执行31个联接。另一种方法是读取所有增量,然后从所有增量中找出最新值,然后执行一个联接。要查找需要窗口操作的最新值-