SSS-Spark Structured Streamingは、単一の列を複数の列に分割します

はじめに:
この記事をクリックしてから、1つの列を複数の列に分割する必要があることを意味します。これは、ブロガーが以前にSpark Structured Streamingを紹介したときに、構造化ストリームプログラミングで次のように述べているためです。これには使用できない多くの静的DataFrameメソッドなど、多くの制限があり、開発に多くの混乱をもたらします。今日の記事では、1つの列を複数の列に変換する方法について説明します。

1.分割機能

もっと大きくする必要があるので、split関数は絶対に不可欠です。SparkSQLにはそのような関数split(str、pattern)があります。ソースコードの紹介は次のようになります。

@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))

ソースコードから、この関数の機能は依然として非常に強力であり、正規式によるセグメンテーションをサポートしていることがわかります。
文字列が分割されると、文字列のリストになります。
以下のテストを実行してみましょう(いくつかの無関係なコードは省略されています) ):

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.リスト内のアイテムを取得します

上記では、列の文字列を区切り文字でリストに分割するか、リストとして列に格納しますが、各要素を列に分割する必要があります。Pysparkの組み込み関数には、次のものがあります。関数は爆発爆発と呼ばれます。リストを複数の行に分割できますが、これは明らかに必要なことではありません。リストを複数の列に分割するための組み込みメソッドはありません。Sparkにはそのような組み込みメソッドはありません。自分で実装することしかできませ
ん。

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

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

上記のコードから、別の列がリストから抽出され、withColumnメソッドを使用して元のDataFrameの後ろに追加されていることがわかります。以下では、ひょうたんを描画し、残りをチェーン方式ですべて平和的に呼び出します。起きる

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   |
+-------+-------+-------+-------+
'''

最後に、元の列を削除して、1つの列から複数の列を完成させます。

3.JSON文字列を複数の列に分割します

最も単純な固定セパレータ文字列について説明しました。分割して複数の列に分割します。DataFrameのJSON列を解析して複数の列に分割する方法は次のとおりです。説明し
たいので、直接アクセスしてください。より複雑なJSON文字列もさまざまなシナリオに対応できます。
元の列のデータ形式は次のようになります。

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

そのようなフォーマットを解析する方法を見てみましょう:

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

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

'''


関数でfrom_json(col、schema、options =())関数のソースコードを使用する必要があります。

@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)

関数のドキュメントによると、その使用方法がすぐにわかります。
最初に、JSON文字列に対応するスキーマ(スキーマ)が必要です。

# 导入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())
        ]))
    ]))
])

パターンが作成されたら、対応するjson文字列の列とパターンを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 |
+------+-----+--------------+--------------------+------------+
'''

これで、Spark Structured Streamingの単一の列から複数の列への変更が完了しました。コアは、実際には、入力テーブルであるこのsource_dfとストリーミングテーブルを中心に動作するため、多くの静的DataFrameメソッドを使用できます。

おすすめ

転載: blog.csdn.net/qq_42359956/article/details/105766771