在返回字典而不是数据帧的列上并行执行循环火花函数

时间:2019-08-06 13:55:50

标签: parallel-processing pyspark

我想使用pyspark在两个spark数据帧上执行验证功能。总而言之,每个df都应该相同,并且我们通过执行多项操作(例如通过索引进行联接并计算“外部”联接中的空值,检查总和,count(),空值,非空值,不同计数)来执行验证等等,然后比较字典中给定的2行(如果一个df的寄存器多于另一个,则在内部联接之后每个df的行)。

我全部使用了应用所有本机Spark函数的函数(例如regex_replace,withColumn(F.when ....)而不是udfs-ifs等),其思想是在每列上该函数返回3个字典问题是在一个步骤中我需要遍历各列,并且当此字典(键是一个数据框的列,而值是另一个应该相同的列)时,这会花费很长时间太长了,有没有办法并行化返回字典的for循环(我不能使用df.select(....)解决方案)。

例如,用于“验证”字符串列的函数是:

def check_string(df,column):
    '''
    df: (pySpark dataframe) dataframe a analizar
    column: (string) nombre de la columna a analizar

    Returns: Diccionary with the following key:value >
        total: Cantidad de registros en la columna.
        nulos: Cantidad de nulos en la columna.
        no_nulos: Cantidad de No nulos en la columna
        distinct_count: Cantidad de valores diferentes en la columna
        len_3 : cantidad de registro con Len < 3
        len_3_10: Cantidad de registros con 3 < len < 10
        len_10: Cantidad de registros con 10 < len
        max_len: max len
        min_len: min len
        max_len_count: qty registros con max len
        min_len_count: qty registros con min len
    '''
    #sqlContext.registerFunction("stringLengthString", lambda x: len(x))
    total = df.count()
    nulos = df.filter(F.col(column).isNull()).count()
    no_nulos= total - nulos
    distinct_count = df.select(column).distinct().count()

    df = df.withColumn(column+'_len',F.length(column))
    len_3 = df.filter(F.col(column+'_len') < 3).count()
    len_3_10 = df.filter((F.col(column+'_len') > 3) & (F.col(column+'_len') <10)).count()
    len_10 = df.count() - (len_3 + len_3_10)

    max_len = df.select(F.max(column+'_len')).collect()[0][0]
    min_len = df.select(F.min(column+'_len')).collect()[0][0]

    max_len_count = df.filter(F.col(column+'_len') == max_len).count()
    min_len_count = df.filter(F.col(column+'_len') == min_len).count()

    return_dict = ({'columna':column,'total':total,'nulos':nulos, 'no_nulos':no_nulos, 'distinct_count':distinct_count,
                   'len_3':len_3,'len_3_10':len_3_10,
                    'len_10':len_10,'max_len':max_len,'min_len':min_len
                    ,'max_len_count':max_len_count,'min_len_count':min_len_count})
    return (return_dict)

如果列为字符串,则为十进制或日期,则存在另一个函数。

要比较我使用的列:

def comparo_columnas(df,col_1,col_2):
    if df.select(col_1).dtypes[0][1] in ('string','date','int'):
        df = df.withColumn('comparison_'+col_1,F.when(F.col(col_1)==F.col(col_2),1).otherwise(0))
    else:
        df = df.withColumn('comparison_'+col_1,F.when(abs(F.col(col_1)-F.col(col_2))<0.05,1).otherwise(0))
    total_igual = df.filter(F.col('comparison_'+col_1)==1).count()
    tot_dif = df.filter(F.col('comparison_'+col_1)==0).count()
    return({'columna':col_1,'registros_iguales':total_igual,'registros_diferentes':tot_dif})

这个想法是只有一个函数占用2 df的空间,并且有一个字典列,执行几个这样的函数,然后保存这些字典。有没有一种方法可以优化列的for循环?我看过类似的页面 https://medium.com/@mrpowers/performing-operations-on-multiple-columns-in-a-pyspark-dataframe-36e97896c378 但是它们都优化了返回数据帧的函数,我不知道如何应用它们。

先谢谢您,如果我的英语不是最好的话!

0 个答案:

没有答案