J'essaie de comprendre les plans physiques sur spark mais je ne comprends pas certaines parties car elles semblent différentes des rdbms traditionnels. Par exemple, dans ce plan ci-dessous, c'est un plan sur une requête sur une table Hive. La requête est la suivante:
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= '1998-09-16'
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus;
== Physical Plan ==
Sort [l_returnflag#35 ASC,l_linestatus#36 ASC], true, 0
+- ConvertToUnsafe
+- Exchange rangepartitioning(l_returnflag#35 ASC,l_linestatus#36 ASC,200), None
+- ConvertToSafe
+- TungstenAggregate(key=[l_returnflag#35,l_linestatus#36], functions=[(sum(l_quantity#31),mode=Final,isDistinct=false),(sum(l_extendedpr#32),mode=Final,isDistinct=false),(sum((l_extendedprice#32 * (1.0 - l_discount#33))),mode=Final,isDistinct=false),(sum(((l_extendedprice#32 * (1.0l_discount#33)) * (1.0 + l_tax#34))),mode=Final,isDistinct=false),(avg(l_quantity#31),mode=Final,isDistinct=false),(avg(l_extendedprice#32),mode=Fl,isDistinct=false),(avg(l_discount#33),mode=Final,isDistinct=false),(count(1),mode=Final,isDistinct=false)], output=[l_returnflag#35,l_linestatus,sum_qty#0,sum_base_price#1,sum_disc_price#2,sum_charge#3,avg_qty#4,avg_price#5,avg_disc#6,count_order#7L])
+- TungstenExchange hashpartitioning(l_returnflag#35,l_linestatus#36,200), None
+- TungstenAggregate(key=[l_returnflag#35,l_linestatus#36], functions=[(sum(l_quantity#31),mode=Partial,isDistinct=false),(sum(l_exdedprice#32),mode=Partial,isDistinct=false),(sum((l_extendedprice#32 * (1.0 - l_discount#33))),mode=Partial,isDistinct=false),(sum(((l_extendedpri32 * (1.0 - l_discount#33)) * (1.0 + l_tax#34))),mode=Partial,isDistinct=false),(avg(l_quantity#31),mode=Partial,isDistinct=false),(avg(l_extendedce#32),mode=Partial,isDistinct=false),(avg(l_discount#33),mode=Partial,isDistinct=false),(count(1),mode=Partial,isDistinct=false)], output=[l_retulag#35,l_linestatus#36,sum#64,sum#65,sum#66,sum#67,sum#68,count#69L,sum#70,count#71L,sum#72,count#73L,count#74L])
+- Project [l_discount#33,l_linestatus#36,l_tax#34,l_quantity#31,l_extendedprice#32,l_returnflag#35]
+- Filter (l_shipdate#37 <= 1998-09-16)
+- HiveTableScan [l_discount#33,l_linestatus#36,l_tax#34,l_quantity#31,l_extendedprice#32,l_shipdate#37,l_returnflag#35], astoreRelation default, lineitem, None
Pour ce que je comprends dans le plan, c'est:
Commence d'abord par une analyse de la table Hive
Ensuite, il filtre en utilisant où la condition
Projetez ensuite pour obtenir les colonnes que nous voulons
Alors TungstenAggregate?
Alors TungstenExchange?
Puis TungstenAggregate à nouveau?
Alors ConvertToSafe?
Trie ensuite le résultat final
Mais je ne comprends pas les étapes 4, 5, 6 et 7. Tu sais ce que c'est? Je cherche des informations à ce sujet pour comprendre le plan mais je ne trouve rien de concret.
Regardons la structure de la requête SQL que vous utilisez:
SELECT
... -- not aggregated columns #1
... -- aggregated columns #2
FROM
... -- #3
WHERE
... -- #4
GROUP BY
... -- #5
ORDER BY
... -- #6
Comme vous le soupçonnez déjà:
Filter (...)
correspond aux prédicats de la clause WHERE
(#4
)Project ...
Limite le nombre de colonnes à celles requises par une union de (#1
Et #2
, Et #4
/#6
S'il n'est pas présent dans SELECT
)HiveTableScan
correspond à la clause FROM
(#3
)Les pièces restantes peuvent être attribuées comme suit:
#2
De la clause SELECT
- functions
champ dans TungstenAggregates
Clause GROUP BY
(#5
):
TungstenExchange
/partitionnement par hachagekey
champ dans TungstenAggregates
#6
- Clause ORDER BY
.
Le projet Tungsten décrit en général un ensemble d'optimisations utilisées par Spark DataFrames
(-sets
), notamment:
Sun.misc.Unsafe
. Cela signifie une utilisation de la mémoire "native" (hors segment) et une allocation/libération explicite de mémoire en dehors de la gestion du GC. Ces conversions correspondent aux étapes ConvertToUnsafe
/ConvertToSafe
du plan d'exécution. Vous pouvez en apprendre plus sur les détails dangereux à propos de nderstanding Sun.misc.UnsafePour en savoir plus sur Tungsten en général, consultez Project Tungsten: Bringing Apache Spark Closer to Bare Metal . Apache Spark = 2.0: plus rapide, plus facile et plus intelligent fournit quelques exemples de génération de code.
TungstenAggregate
se produit deux fois car les données sont d'abord agrégées localement sur chaque partition, puis mélangées, puis finalement fusionnées. Si vous connaissez l'API RDD, ce processus est à peu près équivalent à reduceByKey
.
Si le plan d'exécution n'est pas clair, vous pouvez également essayer de convertir le DataFrame
résultant en RDD
et d'analyser la sortie de toDebugString
.
Tungsten est le nouveau moteur de mémoire de Spark depuis la version 1.4, qui gère les données en dehors de la JVM pour économiser une surcharge du GC. Vous pouvez imaginer que cela implique de copier des données depuis et vers la JVM. C'est tout. Dans Spark 1.5, vous pouvez désactiver Tungsten via spark.sql.tungsten.enabled
, Puis vous verrez "l'ancien" plan, dans Spark 1.6 Je pense que vous ne pouvez plus le désactiver.