Scala 加入spark后有效统计记录

Scala 加入spark后有效统计记录,scala,apache-spark,dataset,Scala,Apache Spark,Dataset,这就是我正在做的。我需要获取一个数据集中存在的记录数,而不是另一个数据集中的记录数,然后再次与第三个数据集联接以获取其他一些列 val tooCompare = dw .select( "loc", "id", "country", "region" ).dropDuplicates() val prev

这就是我正在做的。我需要获取一个数据集中存在的记录数,而不是另一个数据集中的记录数,然后再次与第三个数据集联接以获取其他一些列

val tooCompare = dw
        .select(
          "loc",
          "id",
          "country",
          "region"
        ).dropDuplicates()

val previous = dw
        .select(
          "loc",
          "id",
          "country",
          "region"
        ).dropDuplicates()

val delta = tooCompare.exceptAll(previous).cache()
 
val records = delta
        .join(
          dw,//another dataset
          delta
            .col("loc").equalTo(dw.col("loc"))
            .and(delta.col("id").equalTo(dw.col("id")))
            .and(delta.col("country").equalTo(dw.col("country")))
            .and(delta.col("region").equalTo(dw.col("region")))
        )
        .drop(delta.col("loc"))
        .drop(delta.col("id"))
        .drop(delta.col("country"))
        .drop(delta.col("region"))
        .cache()
    }

 val recordsToSend = records.cache()
 val count = recordsToSend.select("loc").distinct().count()
有没有更有效的方法?
我是新手。我很确定我在这里遗漏了一些东西

我建议使用SQL来提高可读性

首先,创建相关数据帧的临时视图。不知道确切的数据帧是什么,所以

dfToCompare.createOrReplaceTempView("toCompare")
previousDf.createOrReplaceTempView("previous")
anotherDataSet.createOrReplaceTempView("another")
然后可以在一条SQL语句中继续执行所有操作

val records = spark.sql("""select loc, id, country,region
              from toCompare c
              inner join another a
               on a.loc = c.loc  
                and a.id = p.id
                and a.country = c.country
                and a.region = c.region
             where not exists (select null
                                from previous p
                                where p.loc = c.loc  
                                 and p.id = p.id
                                 and p.country = c.country
                                 and p.region = c.region""")
然后你可以像以前一样继续

val recordsToSend = records.cache()
val count = recordsToSend.select("loc").distinct().count()

我认为您粘贴的代码中可能存在一些错误,因为tooCompare和previous是相同的,+第三个数据集连接引用了deAnon,但表上的dw

对于这个示例答案,假设您的当前表名为“current”,previous称为“previous”,第三个表名为“extra”。然后:

这可能更有效,但我希望你能评论一下它是否真的有效

顺便说一句:请注意,我使用Seq[String]作为连接参数(这要求两个表上的列名相同,并且不会产生两个列的副本)。但是,可以更简洁地编写原始连接逻辑,如下所示(使用我的命名约定):


更好的做法是编写一个drop函数,让您可以提供多个列,但我现在真的离题了;-)

为什么在使用cache()函数时重新分配了dataframe?在使用缓存函数时,您不需要重新分配数据帧。
val recordsToSend=records.cache()
。此外,对于记录数据帧,您可以尝试
records.alias(“fst”).join(第二个df,您的加入条件)。选择(“fst.”
,但这如何更有效呢?根据操作,问题是以一种有效的方式解决问题,而不是让问题变得易读或一目了然。即使查询是一行,spark也会创建类似的计划和任务,使用本机代码和spark.sql()计算输出。我同意。不知何故,缓存后跟计数的速度不如我希望的那么快。如果只访问一次数据集,缓存可能会对性能造成轻微影响,而不是提高性能。还要记住,Spark执行得很慢,所以缓存线不做任何事情,它只在带有计数的行中被缓存operation@Nick是的,我明白。然而,这就是我所做的。我的问题是,有没有更好的办法。缓存可能不起作用,但有没有更快执行的方法?嗨,尼克。感谢您的编辑和回复。
Seq
如何比
exceptall
更有效?您是指反连接,我在这里使用Seq作为指定连接条件的更简洁的方法。我的想法是,您的第一组dropDuplicates将首先对每一组数据执行一次洗牌,然后Exceptal可能会执行第二次洗牌(但可能不会),因为antijoin肯定只执行一次洗牌。反连接也可以更直接地做您想做的事情,spark可能有更好的优化程序来处理此查询。很有可能没有性能差异,不过我刚刚更优雅地编写了您的查询!不过请告诉我。
val delta = current.join(
              previous, 
              Seq("loc","id","country","region"), 
              "leftanti"
            ).select("loc","id","country","region").distinct

val recordsToSend = delta
                    .join(
                      extra,
                      Seq("loc", "id", "country", "region")
                    )

val count = recordsToSend.select("loc").distinct().count()
val recordsToSend = delta
                    .join(
                      extra,
                      delta("loc") === extra("loc")
                        && delta("id") === extra("id")
                        && delta("country") === extra("country")
                        && delta("region") === extra("region")
                    )
                    .drop(delta("loc"))
                    .drop(delta("id"))
                    .drop(delta("country"))
                    .drop(delta("region"))