SSS-Spark Structured Streaming divide una sola columna en varias columnas

Prólogo:
desde que hizo clic en este artículo, significa que tiene la necesidad de dividir una columna en varias columnas, porque en la introducción anterior del blogger a Spark Structured Streaming, ya dijimos que en la programación de flujo estructurado, hemos recibido Hay muchas limitaciones, como muchos métodos de DataFrame estáticos que no se pueden usar en esto, lo que genera mucha confusión en el desarrollo. El artículo de hoy hablará sobre cómo convertir una columna en varias columnas.

1. Función dividida

Dado que tiene que ser más, la función split es definitivamente indispensable. Existe una función split (str, pattern) en Spark SQL. La introducción en el código fuente es así:

@since(1.5)
@ignore_unicode_prefix
def split(str, pattern):
    """
    Splits str around pattern (pattern is a regular expression).

    .. note:: pattern is a string represent the regular expression.

    >>> df = spark.createDataFrame([('ab12cd',)], ['s',])
    >>> df.select(split(df.s, '[0-9]+').alias('s')).collect()
    [Row(s=[u'ab', u'cd'])]
    """
    sc = SparkContext._active_spark_context
    return Column(sc._jvm.functions.split(_to_java_column(str), pattern))

En el código fuente, puede ver que la función de esta función sigue siendo muy poderosa y admite la segmentación mediante expresiones regulares.
Después de dividir la cadena, se convierte en una lista de cadenas.
Hagamos una prueba a continuación (se omite algún código irrelevante) ):

from pyspark.sql import functions as f

source_df的结构是这样的:
source_df.show()
'''
+------------------+
|       value      |
+------------------+
|      a,b,c,d     |
+------------------+
'''
split_df = f.split(source.value,",")
type(split_df)
# 查看分割后得到的这个结果是什么类型:
# <class pyspark.sql.Column >
# 可以看到返回的是一个列类型,我们要把他合并在DataFrame中才能显示
# 利用下面这种方式就可以了:
append_split_column = source_df.withColumn("split_value",split_df)
append_split_column.show()
'''
+------------------+-------------------+
|       value      |    split_value    |
+------------------+-------------------+
|      a,b,c,d     | ['a','b','c','d'] |
+------------------+-------------------+
'''

2. Obtenga los elementos de la lista

Arriba, simplemente dividimos la cadena de la columna en una lista por el separador, o la almacenamos en una columna como una lista, pero lo que queremos es separar cada elemento en una columna. Entre las funciones integradas de Pyspark, hay Una función se llama explosión explosiva. Puede dividir una lista en varias filas, lo que obviamente no es lo que necesitamos. No hay un método integrado para dividir una lista en varias columnas. Spark no tiene un método integrado de este tipo. Solo podemos implementarlo nosotros mismos:
Primer vistazo:

add_one_column = split_df.getItem(0)
source_df.withColumn("one",add_one_column).show()

'''
+------------------+-------------+
|       value      |     one     |
+------------------+-------------+
|      a,b,c,d     |      a      |
+------------------+-------------+
'''

Del código anterior, podemos ver que se extrajo una columna separada de la lista y luego se agregó a la parte posterior del DataFrame original a través del método withColumn. A continuación, dibujaremos una calabaza y llamaremos al resto de forma encadenada, todo pacíficamente. Levántate

merge_df = source_df.withColumn("1",split_df.getItem(0)) \
					.withColumn("2",split_df.getItem(1)) \
					.withColumn("3",split_df.getItem(2)) \
					.withColumn("4",split_df.getItem(3)) \
					.drop("value")
merge_df.show()
'''
+-------+-------+-------+-------+
|   1   |   2   |   3   |   4   |
+-------+-------+-------+-------+
|   a   |   b   |   c   |   d   |
+-------+-------+-------+-------+
'''

Finalmente, eliminamos la columna original, de modo que hayamos completado una columna en varias columnas.

3. Divida la cadena JSON en varias columnas

Hablé sobre la cadena de separación fija más simple, dividida y dividida en varias columnas. A continuación, se explica cómo analizar la columna JSON en el DataFrame y dividirla en varias columnas.
Como quiero hablar de ello, simplemente vaya directamente Una cadena JSON más compleja también puede hacer frente a diferentes escenarios:
ahora el formato de datos de la columna original es así:

{
    
    
    "name":"zs",
    "age":19,
    "interests":[
        "basketball",
        "football",
        "tennis"
    ],
    "edu":{
    
    
        "primary":{
    
    
            "name":"ttt",
            "graduation":1587880706
        }
    }
}

Veamos cómo analizar dicho formato:

# 首先还是需要SpparkSQL中内置的函数方法
from pyspark.sql import functions as f

source_df.show()
# 由于篇幅原因所以自动截断了
'''
+--------------------------------------------------------------------+
|                               value                                |
+--------------------------------------------------------------------+
| {"name": "zs", "age": 19, "interests": ["basketball", "footba....  | 
+--------------------------------------------------------------------+

'''

Necesitamos usar
el código fuente de la función from_json (col, schema, options = ()) en las funciones:

@ignore_unicode_prefix
@since(2.1)
def from_json(col, schema, options={
    
    }):
    """
    Parses a column containing a JSON string into a :class:`MapType` with :class:`StringType`
    as keys type, :class:`StructType` or :class:`ArrayType` with
    the specified schema. Returns `null`, in the case of an unparseable string.

    :param col: string column in json format
    :param schema: a StructType or ArrayType of StructType to use when parsing the json column.
    :param options: options to control parsing. accepts the same options as the json datasource

    .. note:: Since Spark 2.3, the DDL-formatted string or a JSON format string is also
              supported for ``schema``.

    >>> from pyspark.sql.types import *
    >>> data = [(1, '''{"a": 1}''')]
    >>> schema = StructType([StructField("a", IntegerType())])
    >>> df = spark.createDataFrame(data, ("key", "value"))
    >>> df.select(from_json(df.value, schema).alias("json")).collect()
    [Row(json=Row(a=1))]
    >>> df.select(from_json(df.value, "a INT").alias("json")).collect()
    [Row(json=Row(a=1))]
    >>> df.select(from_json(df.value, "MAP<STRING,INT>").alias("json")).collect()
    [Row(json={u'a': 1})]
    >>> data = [(1, '''[{"a": 1}]''')]
    >>> schema = ArrayType(StructType([StructField("a", IntegerType())]))
    >>> df = spark.createDataFrame(data, ("key", "value"))
    >>> df.select(from_json(df.value, schema).alias("json")).collect()
    [Row(json=[Row(a=1)])]
    >>> schema = schema_of_json(lit('''{"a": 0}'''))
    >>> df.select(from_json(df.value, schema).alias("json")).collect()
    [Row(json=Row(a=1))]
    >>> data = [(1, '''[1, 2, 3]''')]
    >>> schema = ArrayType(IntegerType())
    >>> df = spark.createDataFrame(data, ("key", "value"))
    >>> df.select(from_json(df.value, schema).alias("json")).collect()
    [Row(json=[1, 2, 3])]
    """

    sc = SparkContext._active_spark_context
    if isinstance(schema, DataType):
        schema = schema.json()
    elif isinstance(schema, Column):
        schema = _to_java_column(schema)
    jc = sc._jvm.functions.from_json(_to_java_column(col), schema, options)
    return Column(jc)

Según la documentación de la función, rápidamente sabremos cómo usarla.
Primero debemos tener un esquema correspondiente a la cadena JSON (Schema)

# 导入SparkSql中所有的类型
from pyspark.sql.types import *
# 根据上面的json字符串创建一个对应模式
my_schema = StructType([
    StructField("name", StringType()),
    StructField("age", IntegerType()),
    StructField("interests", ArrayType(StringType())),
    StructField("edu", StructType([
        StructField("primary", StructType([
            StructField("name", StringType()),
            StructField("graduation", TimestampType())
        ]))
    ]))
])

Una vez creado el patrón, solo necesita pasar la columna de cadena json y el patrón correspondientes a la función from_json ().

json_column = f.from_json(source_df,my_schema)
# 和前面分割字符串一样,这里得到的也只是一个json结构的单独的列
# 我们还是需要手动将这些字段提取出来
# 因为我这里是演示,就提几个重要的字段,明白方法即可
# 我们这里换一种方法来添加列,用select的方式来提取
merge_df = source_df.select(
	json_column.getItem("name").alias("student_name"),
	json_column.getItem("age").alias("age"),
	json_column.getItem("edu").getItem("primary").getItem("name").alias("primary_name"),
	json_column.getItem("edu").getItem("primary").getItem("graduation").alias("primary_graduation"),
	json_column.getItem("interests").getItem(0).alias("interests1")
)
merge_df.show()
'''
+------+-----+--------------+--------------------+------------+
| name | age | primary_name | primary_graduation | interests1 |
+------+-----+--------------+--------------------+------------+
|  zs  | 19  |     ttt      |     1587880706     | basketball |
+------+-----+--------------+--------------------+------------+
'''

Esto completa el cambio de una sola columna a varias columnas en Spark Structured Streaming. El núcleo es realmente operar alrededor de este source_df, que es la tabla de entrada, y la tabla de transmisión, de modo que pueda usar muchos métodos de DataFrame estáticos.

Supongo que te gusta

Origin blog.csdn.net/qq_42359956/article/details/105766771
Recomendado
Clasificación