zoukankan      html  css  js  c++  java
  • ValueError: Some of types cannot be determined by the first 100 rows, please try again with sampling

    ValueError: Some of types cannot be determined by the first 100 rows, please try again with sampling

    在spark中试图将RDD转换成DataFrame时,有时会提示ValueError: Some of types cannot be determined by the first 100 rows, please try again with sampling,此时有2种解决方案:一是提高数据采样率(sampling ratio),二是显式声明要创建的DataFrame的数据结构,即schema。

    第一种方案具体做法如下:

    sqlContext.createDataFrame(rdd, samplingRatio=0.2)

    其中的samplingRatio参数就是数据采样率,可以先设置为0.2试试,如果不行,可以继续增加。

    其原理在于,RDD中元素的内部结构是未知的、不明确的,也就是说每个元素里面有哪些字段,每个字段是什么类型,这些都是不知道的,而DataFrame则要求对元素的内部结构有完全的知情权。

    比如有一个RDD,其中的元素是dict类型,在使用sqlContext.createDataFrame()方法将该RDD转换成DataFrame的时候,如果括号中没有传入schema参数,那么spark会根据RDD中的前N个元素去猜测元素的内部结构,猜出里面都有哪些字段,每个字段是什么数据类型的。至于N是多少,取决于samplingRatio参数的值,如果不设该参数,则默认取前100个元素。上面代码中设置的samplingRatio是0.2,意味着spark将会取RDD中前20%的元素作为样本去推断元素中各个字段的数据类型。假如运气好,这20%的元素中各个字段都是齐备的,并且能根据字段值判断出该字段的类型,像下图这样:

    ['name':'Tom', 'age':23, 'gender':'M', 'is_married':False]
    ['name':'Jerry', 'age':31, 'gender':'F', 'is_married':True]
    ['name':'John', 'age':27, 'gender':'M', 'is_married':False]

    那么spark就能根据上图中的这么多样本元素推断出元素内部有name、age、gender、is_married这几个字段,且字段类型分别是String,Int,String,Boolean,那就不会报任何错误。

    但是,如果这20%的元素都缺失了某个字段,像下图这样:

    ['name':'Tom', 'age':23, 'gender':'M']
    ['name':'Jerry', 'age':31, 'gender':'F']
    ['name':'John', 'age':27, 'gender':'M']

    本来元素中其实有4个字段的,但是抽样的20%数据里面都缺失了is_married字段,这样就会导致spark误以为元素中只有3个字段,然而当真的按照3个字段来处理时,却又发现后面有其他元素不止这3个字段,这就尴尬了,然后spark觉得自己被耍了,就罢工了。

    还有一种情况也会导致spark报错,像下图这样:

    ['name':'Tom', 'age':23, 'gender':'M', 'is_married':None]
    ['name':'Jerry', 'age':31, 'gender':'F', 'is_married':None]
    ['name':'John', 'age':27, 'gender':'M', 'is_married':None]

    这种情况下,由于抽样的20%的元素中is_married字段值全都是None,导致spark误以为该字段就是None类型的,当按照None处理时,如果发现后面有元素的is_married字段的值是True或者False,然后spark就崩溃了,不是说好了是None类型拉钩上吊一百年不许变吗?你给我来个True和False是个什么意思?

    看到这里,智商超群的你可能已经想到,我主动告诉spark每个RDD元素内部结构是什么样的不就行了吗?没错,这就是我说的第二种方案,显式声明schema。在sqlContext.createDataFrame()方法中,有个参数叫schema,这个参数就是用来告诉spark每个RDD元素的结构的。具体做法是这样的:

    from pyspark.sql.types import *
    schema = StructType([
        StructField("column_1", StringType(), True),
        StructField("column_2", IntegerType(), True)
        .
        .
        .
    ])
    df = sqlContext.createDataFrame(rdd, schema=schema)

    当你显式声明schema并应用到createDataFrame方法中后,就不再需要samplingRatio参数了。实际开发工程中建议使用显式声明schema的方案,这样可以避免出现因奇葩数据导致的错误。

  • 相关阅读:
    java方式实现堆排序
    java方式实现归并排序
    用java方式实现快速排序
    Linux中crontab定时任务
    TCP/IP网络协议初识
    github设置添加ssh
    IDM下载工具使用
    Java程序在内存中运行详解
    GitHub的高级搜索方式
    深入理解JavaScript中的堆与栈 、浅拷贝与深拷贝
  • 原文地址:https://www.cnblogs.com/xzjf/p/9296278.html
Copyright © 2011-2022 走看看