私は新人ですspark and pythonそして、データファイルに適用できるメタデータファイルからスキーマを構築するこの困難に直面しています。シナリオ:メタデータファイルデータファイル(csv形式)には、列とそのタイプが含まれます。例:
id,int,10,"","",id,"","",TRUE,"",0
created_at,timestamp,"","","",created_at,"","",FALSE,"",0
これを次のようなデータフレームに正常に変換しました。
+--------------------+---------------+
| name| type|
+--------------------+---------------+
| id| IntegerType()|
| created_at|TimestampType()|
| updated_at| StringType()|
しかし、これを使用してこれをStructField形式に変換しようとすると
fields = schemaLoansNew.map(lambda l:([StructField(l.name, l.type, 'true')]))
OR
schemaList = schemaLoansNew.map(lambda l: ("StructField(" + l.name + "," + l.type + ",true)")).collect()
そして、後でそれを使用してStructTypeに変換します
schemaFinal = StructType(schemaList)
次のエラーが表示されます。
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/mapr/spark/spark-1.4.1/python/pyspark/sql/types.py", line 372, in __init__
assert all(isinstance(f, DataType) for f in fields), "fields should be a list of DataType"
AssertionError: fields should be a list of DataType
データフレームに関する知識が不足しているため、これに固執しています。これを進める方法を教えてください。スキーマの準備ができたら、createDataFrameを使用してデータファイルに適用します。このプロセスは多くのテーブルで実行する必要があるため、型をハードコーディングするのではなく、メタデータファイルを使用してスキーマを構築し、RDDに適用します。
前もって感謝します。
引数を持つフィールドは、DataType
オブジェクトのリストでなければなりません。この:
.map(lambda l:([StructField(l.name, l.type, 'true')]))
collect
(list
of lists
of tuples
(Rows
)of DataType
(list[list[Tuple[DataType]]]
)nullable
引数が文字列ではなくブール値であることは言うまでもありません。
2回目の試行:
.map(lambda l: ("StructField(" + l.name + "," + l.type + ",true)")).
collect
の後にlist
オブジェクトのstr
を生成します。
表示したレコードの正しいスキーマは、次のようになります。
from pyspark.sql.types import *
StructType([
StructField("id", IntegerType(), True),
StructField("created_at", TimestampType(), True),
StructField("updated_at", StringType(), True)
])
このようなタスクに分散データ構造を使用することは、効率が悪いことは言うまでもなく、深刻なやり過ぎですが、最初のソリューションを次のように調整してみてください。
StructType([
StructField(name, eval(type), True) for (name, type) in df.rdd.collect()
])
しかし、それは特に安全ではありません(eval
)。 JSON /辞書からスキーマを構築する方が簡単かもしれません。型の説明から標準的な型名にマッピングする関数があると仮定します。
def get_type_name(s: str) -> str:
"""
>>> get_type_name("int")
'integer'
"""
_map = {
'int': IntegerType().typeName(),
'timestamp': TimestampType().typeName(),
# ...
}
return _map.get(s, StringType().typeName())
次の形の辞書を作成できます。
schema_dict = {'fields': [
{'metadata': {}, 'name': 'id', 'nullable': True, 'type': 'integer'},
{'metadata': {}, 'name': 'created_at', 'nullable': True, 'type': 'timestamp'}
], 'type': 'struct'}
StructType.fromJson
:
StructType.fromJson(schema_dict)
val columns: Array[String] = df1.columns
val reorderedColumnNames: Array[String] = df2.columns //or do the reordering you want
val result: DataFrame = dataFrame.select(reorderedColumnNames.head, reorderedColumnNames.tail: _*)
以下の手順に従って、データ型オブジェクトを変更できます
data_schema=[
StructField("age", IntegerType(), True),
StructField("name", StringType(), True)
]
final_struct=StructType(fields=data_schema)
df=spark.read.json('/home/abcde/Python-and-Spark-for-Big-Data-master/Spark_DataFrames/people.json', schema=final_struct)
df.printSchema()
root
|-- age: integer (nullable = true)
|-- name: string (nullable = true)