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"))