我有一个如下的数据框 -
Id,timestamp
100,1
200,2
300,3
400,4
500,5
600,6
现在我想只得到一行,其值小于时间戳5。
等效的SQL查询:select * from table1 where id <5 order by timestamp desc limit 1.
但是在spark查询中我不想按操作执行顺序,因为我们的数据量太大,所以需要花费太多时间。 如果不使用订单,是否可以在spark中执行相同操作?
答案 0 :(得分:1)
首先,您可以在spark中运行该SQL查询:
dataframe.createOrReplaceTempView("table1")
spark.sql("select * from table1 where id <5 order by timestamp desc limit 1")
除此之外,您知道id
(我认为您的意思是timestamp
)恰好是4:
dataframe.where("timestamp = 4")
答案 1 :(得分:1)
虽然其他答案是正确的(您可以直接在临时视图或orderBy
+ limit
上使用您的查询),但似乎无法解决您的主要问题:
但是在Spark查询中我不想按操作执行顺序,因为我们的数据量太大,所以需要花费太多时间。 Spark中是否可以在不使用order by的情况下执行相同操作?
让我们来看看幕后发生的事情:
df = spark.createDataFrame(
[(100, 1), (200, 2), (300, 3), (400, 4), (500, 5), (600, 6)],
("id", "timestamp"))
df.filter("timestamp < 5").orderBy(df["timestamp"].desc()).limit(1).explain()
# == Physical Plan ==
# TakeOrderedAndProject(limit=1, orderBy=[timestamp#35L DESC NULLS LAST], output=[id#34L,timestamp#35L])
# +- *(1) Filter (isnotnull(timestamp#35L) && (timestamp#35L < 5))
# +- Scan ExistingRDD[id#34L,timestamp#35L]
正如你所看到的,根本没有任何排序。 Spark分析了计划,代替完全排序,应用了TakeOrderedAndProject
。结果,每个分区只记录最高记录。
操作在行数方面是线性的,但您不必担心排序所有记录所需的全部随机播放。
结论?只要极限值很小,就没有什么可担心的了(有很大的限制,事情可能会变得难看)。
答案 2 :(得分:0)
简而言之:排序,按值过滤&lt;指定,选择结果的最后一个元素。
答案 3 :(得分:0)
另一种方式:
import pyspark.sql.functions as f
df.filter("id<5").orderBy(f.col("timestamp").desc()).first()
答案 4 :(得分:0)
如果由于数据帧大小而要避免ordering
,请考虑使用reduce
仅在过滤后获得最大值:
val df = Seq(
(100, 1),
(200, 2),
(300, 3),
(400, 4),
(500, 5),
(600, 6)
).toDF("id", "ts")
df.where($"ts" < 5).reduce( (acc, r) =>
if (r.getAs[Int]("ts") > acc.getAs[Int]("ts")) r else acc
)
// res1: org.apache.spark.sql.Row = [400,4]