Building a StructType from a dataframe in pyspark

后端 未结 4 1030
后悔当初
后悔当初 2021-02-04 06:45

I am new spark and python and facing this difficulty of building a schema from a metadata file that can be applied to my data file. Scenario: Metadata File for the Data file(csv

4条回答
  •  心在旅途
    2021-02-04 07:32

    Fields have argument have to be a list of DataType objects. This:

    .map(lambda l:([StructField(l.name, l.type, 'true')]))
    

    generates after collect a list of lists of tuples (Rows) of DataType (list[list[tuple[DataType]]]) not to mention that nullable argument should be boolean not a string.

    Your second attempt:

    .map(lambda l: ("StructField(" + l.name + "," + l.type + ",true)")).
    

    generates after collect a list of str objects.

    Correct schema for the record you've shown should look more or less like this:

    from pyspark.sql.types import *
    
    StructType([
        StructField("id", IntegerType(), True),
        StructField("created_at", TimestampType(), True),
        StructField("updated_at", StringType(), True)
    ])
    

    Although using distributed data structures for task like this is a serious overkill, not to mention inefficient, you can try to adjust your first solution as follows:

    StructType([
        StructField(name, eval(type), True) for (name, type) in  df.rdd.collect()
    ])
    

    but it is not particularly safe (eval). It could be easier to build a schema from JSON / dictionary. Assuming you have function which maps from type description to canonical type name:

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

    You can build dictionary of following shape:

    schema_dict = {'fields': [
        {'metadata': {}, 'name': 'id', 'nullable': True, 'type': 'integer'},
        {'metadata': {}, 'name': 'created_at', 'nullable': True, 'type': 'timestamp'}
    ], 'type': 'struct'}
    

    and feed it to StructType.fromJson:

    StructType.fromJson(schema_dict)
    

提交回复
热议问题