web-dev-qa-db-fra.com

Quand mettre en cache un DataFrame?

Ma question est, quand dois-je faire dataframe.cache () et quand est-ce utile?

De plus, dans mon code, dois-je mettre en cache les cadres de données dans les lignes commentées?

Remarque: Mes trames de données sont chargées à partir d'une base de données Redshift.

Merci beaucoup

Voici mon code:

def sub_tax_transfer_pricing_eur_aux(manager, dataframe, seq_recs, seq_reservas, df_aux):
    df_vta = manager.get_dataframe(tables['dwc_oth_v_re_v_impuesto_sap_vta'])
    df_cpa = manager.get_dataframe(tables['dwc_oth_v_re_v_impuesto_sap_cpa'])

    dataframe = dataframe.filter(dataframe.seq_rec.isin(seq_recs)) \
        .filter(dataframe.seq_reserva.isin(seq_reservas))

    ##################################################
    #SHOULD I CACHE HERE df_vta, df_cpa and dataframe
    ##################################################

    dataframe = dataframe.join(df_vta, [dataframe.ind_tipo_imp_vta_fac == df_vta.ind_tipo_imp_vta,
                                        dataframe.cod_impuesto_vta_fac == df_vta.cod_impuesto_vta,
                                        dataframe.cod_clasif_vta_fac == df_vta.cod_clasif_vta,
                                        dataframe.cod_esquema_vta_fac == df_vta.cod_esquema_vta,
                                        dataframe.cod_empresa_vta_fac == df_vta.cod_emp_atlas_vta,
                                        ]).drop("ind_tipo_imp_vta", "cod_impuesto_vta", "cod_clasif_vta",
                                                "cod_esquema_vta", "cod_emp_atlas_vta") \
        .join(df_cpa, [dataframe.ind_tipo_imp_vta_fac == df_cpa.ind_tipo_imp_cpa,
                       dataframe.cod_impuesto_vta_fac == df_cpa.cod_impuesto_cpa,
                       dataframe.cod_clasif_vta_fac == df_cpa.cod_clasif_cpa,
                       dataframe.cod_esquema_vta_fac == df_cpa.cod_esquema_cpa,
                       dataframe.cod_empresa_vta_fac == df_cpa.cod_emp_atlas_cpa,
                       ]).drop("ind_tipo_imp_cpa", "cod_impuesto_cpa", "cod_clasif_cpa",
                               "cod_esquema_cpa", "cod_emp_atlas_cpa") \
        .select("seq_rec", "seq_reserva", "ind_tipo_regimen_fac", "imp_margen_canal", "ind_tipo_regimen_con",
                "imp_coste", "imp_margen_canco", "imp_venta", "pct_impuesto_vta", "pct_impuesto_cpa")

    ######################################         
    #SHOULD I CACHE HERE dataframe AGAIN ?
    ######################################

    dataframe = dataframe.withColumn("amount1",
                                     func.when(dataframe.ind_tipo_regimen_fac == 'E',
                                               dataframe.imp_margen_canal * (
                                                   1 - (1 / (1 + (dataframe.pct_impuesto_vta
                                                                  / 100)))))
                                     .otherwise(dataframe.imp_venta * (
                                         1 - (1 / (1 + (dataframe.pct_impuesto_vta / 100)))) - (
                                                    dataframe.imp_venta - dataframe.imp_margen_canal) * (
                                                    1 - (1 / (1 + (dataframe.pct_impuesto_cpa / 100))))))

    dataframe = dataframe.withColumn("amount2",
                                     func.when(dataframe.ind_tipo_regimen_con == 'E',
                                               dataframe.imp_margen_canco * (
                                                   1 - (1 / (1 + (dataframe.pct_impuesto_vta
                                                                  / 100)))))
                                     .otherwise((dataframe.imp_coste + dataframe.imp_margen_canco) * (
                                         1 - (1 / (1 + (dataframe.pct_impuesto_vta / 100)))) - (
                                                    dataframe.imp_coste) * (
                                                    1 - (1 / (1 + (dataframe.pct_impuesto_cpa / 100))))))

    dataframe = dataframe.na.fill({'amount1': 0})
    dataframe = dataframe.na.fill({'amount2': 0})

    dataframe = dataframe.join(df_aux, [dataframe.seq_rec == df_aux.operative_incoming,
                                        dataframe.seq_reserva == df_aux.booking_id])

    dataframe = dataframe.withColumn("impuesto_canco1", udf_currency_exchange(dataframe.booking_currency,
                                                                             func.lit(EUR),
                                                                             dataframe.creation_date,
                                                                             dataframe.amount1))

    dataframe = dataframe.withColumn("impuesto_canco2", udf_currency_exchange(dataframe.booking_currency,
                                                                             func.lit(EUR),
                                                                             dataframe.creation_date,
                                                                             dataframe.amount2))

    dataframe = dataframe.withColumn("impuesto_canco", dataframe.impuesto_canco1 + dataframe.impuesto_canco2)

    dataframe = dataframe.na.fill({'impuesto_canco': 0})

    dataframe = dataframe.select("operative_incoming", "booking_id", "impuesto_canco")
    ######################################         
    #SHOULD I CACHE HERE dataframe AGAIN ?
    ######################################
    dataframe = dataframe.groupBy("operative_incoming", "booking_id").agg({'impuesto_canco': 'sum'}). \
        withColumnRenamed("SUM(impuesto_canco)", "impuesto_canco")

    return dataframe
11
Alezis

quand dois-je faire dataframe.cache () et quand c'est utile?

cache ce que vous allez utiliser dans toutes les requêtes (et tôt et souvent jusqu'à la mémoire disponible). Peu importe le langage de programmation que vous utilisez (Python ou Scala ou Java ou SQL ou R)), car la mécanique sous-jacente est la même.

Vous pouvez voir si un DataFrame a été mis en cache dans votre plan physique à l'aide de l'opérateur explain (où les entités InMemoryRelation reflètent les jeux de données mis en cache avec leur niveau de stockage):

== Physical Plan ==
*Project [id#0L, id#0L AS newId#16L]
+- InMemoryTableScan [id#0L]
      +- InMemoryRelation [id#0L], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
            +- *Range (0, 1, step=1, splits=Some(8))

Après avoir cache (ou persist) votre DataFrame la première requête peut ralentir, mais cela va payer pour les requêtes suivantes.

Vous pouvez vérifier si un ensemble de données a été mis en cache ou non à l'aide du code suivant:

scala> :type q2
org.Apache.spark.sql.Dataset[org.Apache.spark.sql.Row]

val cache = spark.sharedState.cacheManager
scala> cache.lookupCachedData(q2.queryExecution.logical).isDefined
res0: Boolean = false

De plus, dans mon code, dois-je mettre en cache les cadres de données dans les lignes commentées?

Oui et non. Mettez en cache ce qui représente les ensembles de données externes afin de ne pas payer le prix supplémentaire de la transmission de données sur le réseau (tout en accédant au stockage externe) chaque fois que vous interrogez sur eux.

Ne mettez pas en cache ce que vous utilisez une seule fois ou est facile à calculer. Sinon, cache.


Faites attention à ce que vous mettez en cache, c'est-à-dire ce que Dataset est mis en cache, car cela donne différentes requêtes mises en cache.

// cache after range(5)
val q1 = spark.range(5).cache.filter($"id" % 2 === 0).select("id")
scala> q1.explain
== Physical Plan ==
*Filter ((id#0L % 2) = 0)
+- InMemoryTableScan [id#0L], [((id#0L % 2) = 0)]
      +- InMemoryRelation [id#0L], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
            +- *Range (0, 5, step=1, splits=8)

// cache at the end
val q2 = spark.range(1).filter($"id" % 2 === 0).select("id").cache
scala> q2.explain
== Physical Plan ==
InMemoryTableScan [id#17L]
   +- InMemoryRelation [id#17L], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
         +- *Filter ((id#17L % 2) = 0)
            +- *Range (0, 1, step=1, splits=8)

Il y a une surprise avec la mise en cache dans Spark SQL. La mise en cache est paresseuse et c'est pourquoi vous payez le prix supplémentaire pour que les lignes soient mises en cache la toute première action, mais cela ne se produit qu'avec l'API DataFrame. En SQL, la mise en cache est impatient, ce qui fait une énorme différence dans les performances des requêtes car vous n'avez pas besoin d'appeler une action pour déclencher la mise en cache.

13
Jacek Laskowski

En fait, dans votre cas, .cache() n'aidera pas du tout. Vous n'exécutez aucune action sur votre trame de données (du moins pas dans votre fonction fournie). .cache() est une bonne idée si vous utiliserez plusieurs fois des données comme:

data = sub_tax_transfer_pricing_eur_aux(...).cache()
one_use_case = data.groupBy(...).agg(...).show()
another_use_case = data.groupBy(...).agg(...).show()

De cette façon, vous ne récupérerez les données qu'une seule fois (lorsque la première action est appelée .show(), puis la prochaine utilisation de data dataframe devrait être plus rapide. Cependant, utilisez ceci avec prudence - parfois, la récupération de données est toujours plus rapide. Aussi, je déconseille de nommer le même nom encore et encore votre trame de données. Les trames de données sont des objets immuables, après tout.

J'espère que cela vous sera utile.

9
Vaidas Armonas

Mise en cache des RDD dans Spark: il s'agit d'un mécanisme permettant d'accélérer les applications qui accèdent plusieurs fois au même RDD. Un RDD qui n'est ni mis en cache, ni point de contrôle, est réévalué à chaque fois qu'une action est invoquée sur ce RDD. Il existe deux appels de fonction pour mettre en cache un RDD: cache() et persist(level: StorageLevel). La différence entre eux est que cache() mettra en cache le RDD en mémoire, tandis que persist(level) peut mettre en cache en mémoire, sur disque ou hors mémoire en fonction de la stratégie de mise en cache spécifiée par niveau. persist() sans argument est équivalent à cache(). Nous discutons des stratégies de mise en cache plus loin dans cet article. La libération d'espace de la mémoire de stockage est effectuée par unpersist().

Quand utiliser la mise en cache: comme suggéré dans cet article, il est recommandé d'utiliser la mise en cache dans les situations suivantes:

  • Réutilisation de RDD dans des applications d'apprentissage automatique itératives
  • Réutilisation de RDD dans des applications autonomes Spark
  • Lorsque le calcul RDD est coûteux, la mise en cache peut aider à réduire le coût de la récupération en cas d'échec d'un exécuteur
2
Nandeesh