例如我在spark上执行一些查询,在spark UI中我可以看到一些查询有更多的shuffle,这个shuffle似乎是本地读取的数据量和执行者之间的读取数据。
但是所以我不理解一件事,例如下面这个查询从HDFS加载了7GB,但是读取后缀+ shuffled写入超过10GB。但我看到其他查询从HDFS加载7GB而且shuffle就像500kb。所以我不明白这一点,你能帮忙吗?混洗的数据量与从hdfs读取的数据无关?
select
nation, o_year, sum(amount) as sum_profit
from
(
select
n_name as nation, year(o_orderdate) as o_year,
l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount
from
orders o join
(select l_extendedprice, l_discount, l_quantity, l_orderkey, n_name, ps_supplycost
from part p join
(select l_extendedprice, l_discount, l_quantity, l_partkey, l_orderkey,
n_name, ps_supplycost
from partsupp ps join
(select l_suppkey, l_extendedprice, l_discount, l_quantity, l_partkey,
l_orderkey, n_name
from
(select s_suppkey, n_name
from nation n join supplier s on n.n_nationkey = s.s_nationkey
) s1 join lineitem l on s1.s_suppkey = l.l_suppkey
) l1 on ps.ps_suppkey = l1.l_suppkey and ps.ps_partkey = l1.l_partkey
) l2 on p.p_name like '%green%' and p.p_partkey = l2.l_partkey
) l3 on o.o_orderkey = l3.l_orderkey
)profit
group by nation, o_year
order by nation, o_year desc;
答案 0 :(得分:2)
我强烈建议您阅读我认为的the paper on explaining the Mapreduce programming model。
基本上没有它不是HDFS(或任何来源)上的数据量决定了混洗了多少数据。我将尝试使用三个示例进行解释:
示例1。混洗的数据量少于输入数据:
val wordCounts = words.map((_, 1)).reduceByKey(_ + _)
这里我们计算每个分区中的单词数(每个键),然后只调整结果。然后,一旦我们对子计数进行了洗牌,我们就将它们加起来。因此,我们洗牌的数据量与计数量有关。因此,在这种情况下,它与唯一单词的数量有关。
如果我们只有一个独特的单词,我们将比输入更少的数据。事实上,与线程一样多(非常少)。
假设如果每个单词都是唯一的,那么我们会随机播放更多数据(详情请参阅论文)。因此,此示例中混洗的数据量与我们拥有的唯一密钥数量(唯一字)有关。
示例2 。混洗的数据量与输入数据相同:
val wordCounts = words.map((_, 1)).groupByKey().mapValues(_.size)
在这里,我们将所有单词组合在一起,然后计算有多少单词。所以我们需要改组所有数据。
示例3 。混洗的数据量大于输入数据:
val silly =
words.map(word =>
(word, generateReallyLongString()))
.groupByKey()
这里我们的地图阶段将每个单词映射到一个非常长的随机字符串,然后我们将它们按字组合在一起。在这里,我们生成的数据多于输入数据,并且将比输入更多的数据。
答案 1 :(得分:2)
随机播放是Spark的重新分发数据的机制,因此它可以跨分区进行不同的分组。这通常涉及跨执行程序和机器复制数据。因此,非常清楚的是,混洗数据并不真正取决于输入数据的数量。但是,它取决于您对输入数据执行的操作,这会导致数据在执行程序(以及机器)之间移动。请通过http://spark.apache.org/docs/latest/programming-guide.html#shuffle-operations了解并理解为什么改组是一个代价高昂的过程。
查看您粘贴的查询,您似乎正在进行大量的连接操作(看起来很难理解您正在进行的最终操作)。这肯定要求跨分区移动数据。可以通过重新访问查询并优化相同或者以一种导致数据移动较少的方式处理或预处理输入数据来处理问题(例如:将已连接的数据放在一起以便它们落入相同的分区中)。同样,这只是一个示例,您必须从您的用例中确定哪种方法最适合您。