scala数据如: 14,2,,3,,,23 查找出值为null值的字段 填充固定的数字

package emg.branchs.test


import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

/**
  * @Auther: sss
  * @Date: 2018/12/19 17:34
  * @Description: 数据如: 14,2,,3,,,23  查找出值为null值的字段  填充固定的数字
  */
object RepuaceNull {

  def main(args: Array[String]): Unit = {


    val conf = new SparkConf().setMaster("local[*]").setAppName(this.getClass.getSimpleName)
    val session = SparkSession.builder().config(conf).getOrCreate()
    import session.implicits._
    
    var files = session.read.textFile("C:\\Users\\sss\\Desktop\\asd.txt")

    /** *
      * 方法一 :
      *
      * @param args
      */
    files.collect().map(str => {
      val ls = str.split(",")
      val lss = ls.map(x => {
        if (x == null || x == "") {
          (123)
        } else
          (x)
      })
      (lss(0), lss(1), lss(2), lss(3), lss(4), lss(5))
    }).foreach(println)

    /** *
      * 方法二 :   na.fill
      *
      * @param args 根据网上的资料  没实现 也不知道怎么回事
      */


  }
}

 

<think>我们面对的问题是在Spark任务中遇到了NullPointerException,具体错误信息是"Null valueappeared innon-nullablefield:..."。根据引用[1][2][3][4]中的信息,这个错误通常发生在尝试将空null)赋给一个非空(non-nullable)的字段时。在Spark中,当我们从Scala的caseclass或元组推断模式(schema)时,如果某个字段定义为非空类型(如scala.Int, scala.Long等),但实际数据现了null,就会抛此异常。解决方案的核心是确保在非空字段中不null。具体可以从以下几个方面入手:1.**修改数据结构,使用可空类型**:将case class中非空字段的类型改为Option[...]或者使用Java的包装类型(如java.lang.Integer代替Int)。这样,当数据中确实可能存在空时,Spark能够正确处理。2. **数据清洗**:在数据进入Spark之前,检查数据源,确保那些被定义为非空的字段没有空。如果数据源中存在空,可以采取填充默认、删除含有空的记录等策略。3. **显式定义Schema**:如果使用caseclass推断模式,那么caseclass的字段默认都是非空的(除非使用Option)。我们可以通过编程方式定义Schema,将可能为空的字段设置为nullable=true。4.**检查数据源**:有时候数据源本身就有问题,比如某些字段预期非空但实际有空。需要检查数据源(如文件、数据库等)的数据质量。根据错误信息中的字段类型(scala.Double)和字段名(Seq),我们可以推断问题可能现在一个包含Double类型且非空字段的序(Seq)中。错误信息指,在某个顶层Product输入对象中,一个非空字段现了空。具体步骤:步骤1:检查定义的数据结构(case class或元组)。例如,如果有一个case class定义如下:caseclass MyRecord(field1: Double, field2:Seq[Double])那么,field1和field2中的每一个元素(因为Seq中的元素类型为Double,也是非空的)都不能为null。如果数据中这些字段可能为null,则应改为:caseclass MyRecord(field1: Option[Double], field2:Seq[Option[Double]])但是注意:Seq[Double]本身允许为null(即整个Seq为null),但Seq中的元素不能为null。如果Seq中的元素可能为null,那么应该使用Seq[Option[Double]]。然而,在Spark中处理Seq[Option[Double]]可能会比较麻烦,通常我们会选择将空转换为一个默认(如0.0)或者过滤掉空。步骤2:如果无法修改数据结构,那么可以在读取数据后使用map操作对数据进行清洗,将null转换为默认或过滤掉。例如:val cleanData =rawData.map {record =>//假设record是一个MyRecord实例,我们确保field1和field2中的元素不为null//但注意:整个record不能为null,因为caseclass实例本身非空//如果field2(一个Seq)为null,我们将其转换为空序valcleanField2= if(record.field2== null) Seq.empty elserecord.field2.map(Option(_).getOrElse(0.0))MyRecord(record.field1, cleanField2)}但是,这种方法可能会改变数据结构,且需要根据具体业务逻辑处理。步骤3:显式定义Schema。如果我们是从文件(如CSV、JSON)读取数据,可以显式定义一个StructType,并将可能为空的字段设置为nullable=true。例如:importorg.apache.spark.sql.types._valschema =StructType(Array(StructField("field1",DoubleType, nullable= false),//如果确实非空,设为false;如果可能为空,则设为trueStructField("field2",ArrayType(DoubleType,containsNull= false), nullable= true)//整个数组可以为空,但数组内的元素不能为空))valdf =spark.read.schema(schema).json("path/to/file")注意:在定义ArrayType时,containsNull=false表示数组中的元素不能为null。如果数据中数组元素有null,那么读取时会报错。因此,我们需要确保数据中数组元素没有null,或者将containsNull设为true(但这样数组元素就可以为null,然后我们再用步骤2的方法清洗)。步骤4:检查数据源。如果数据源是外部系统,比如数据库,那么查询时可能返回了空。需要检查数据源,确保非空字段确实没有空。根据引用[4]中给的例子,报错信息中会明确指示哪个字段现了空(例如:f_cell_id,window,linkId等)。因此,在错误日志中查找具体的字段名,然后针对该字段进行处理。总结:根据错误日志定位到具体的字段,然后选择以下一种或多种方法:-修改数据结构,使用Option或可为空的类型。-清洗数据,确保非空字段没有空。-显式定义Schema,并正确设置字段的可空性。-检查数据源,修复数据质量问题。下面是一个示例代码,展示如何定义一个包含可为空字段的caseclass:caseclass MyRecord(field1: Option[Double], field2:Seq[Option[Double]])但是,使用Seq[Option[Double]]在后续处理中可能不够方便。另一种做法是,在读取数据后立即进行数据清洗,将空替换掉:val df= spark.read.json(...)//读取原始数据valcleanedDF= df.na.fill(0.0, Seq("field1"))//将field1字段的空填充为0.0.withColumn("field2",expr("transform(field2, x-> coalesce(x,0.0))")) //将field2数组中的空替换为0.0注意:上面的清洗代码假设field2是一个数组类型。使用SparkSQL的函数`transform`和`coalesce`来替换数组中的空。如果问题仍然存在,请检查Spark任务的日志,确定具体是哪个字段现了空,然后针对该字段进行处理。相关问题:1.在Spark中,如何定义可为空的Schema?2.如何清洗SparkDataFrame中的空3.为什么在Spark中使用case class时,字段默认是非空的?4.在Scala中,Option类型和Java包装类型有什么区别?在Spark中如何选择?</think>### 华为云 Scala Spark 空指针异常解决方案 #### 错误原因分析 该错误的核心是**尝试将空null)赋给定义为非空(non-nullable)的字段**。具体到您的场景: ```scala Caused by: java.lang.NullPointerException: Null value appeared in non-nullable field: scala.Double Seq ``` 根本原因: 1. **数据结构定义问题**:Schema 中的 `scala.Double` 字段被定义为非空(`nullable=false`),但实际数据中存在 null 2. **数据源质量问题**:输入数据中的 `Seq[Double]` 序包含 null 元素或整个序null 3. **类型不匹配**:使用 Scala 原生类型(如 `Double`)而非可空类型(如 `Option[Double]`) #### 解决方案 ##### 方法 1:修改数据结构(推荐) ```scala // 修改前(非空类型) case class InputData( id: Long, // 非空 values: Seq[Double] // 非空字段 ) // 修改后(使用Option处理可空字段) case class InputData( id: Long, values: Option[Seq[Double]] = None // 允许为空 ) ``` **关键修改**: - 将 `Seq[Double]` 改为 `Option[Seq[Double]]` - 使用 `getOrElse` 处理空: ```scala val safeValues = inputData.values.getOrElse(Seq.empty[Double]) ``` ##### 方法 2:数据清洗 在数据读取阶段处理空: ```scala import org.apache.spark.sql.functions._ val rawDF = spark.read.parquet("hdfs://path/to/data") val cleanedDF = rawDF .withColumn("values", when(col("values").isNull, array()) // 替换null为空数组 .otherwise(col("values")) ) .na.fill(0.0, Seq("double_field")) // 填充Double类型空 ``` ##### 方法 3:显式定义Schema 强制指定字段可空性: ```scala import org.apache.spark.sql.types._ val customSchema = StructType(Array( StructField("id", LongType, nullable = false), StructField("values", ArrayType(DoubleType), nullable = true) // 允许数组为空 )) spark.read.schema(customSchema).json("data.json") ``` ##### 方法 4:华为云数据源特殊处理 当使用华为云数据连接器时: ```scala // 在读取配置中启用空检测 val hwConf = Map( "fs.obs.access.key" -> "your_key", "fs.obs.nullable" -> "true" // 允许空 ) spark.read .format("org.apache.spark.sql.execution.datasources.parquet") .options(hwConf) .load("obs://bucket/path") ``` #### 验证步骤 1. **空检测**: ```scala df.select(df.columns.map(c => sum(col(c).isNull.cast("int")).alias(c)): _*).show() ``` 2. **Schema 检查**: ```scala df.printSchema() // 确认目标字段 nullable=true ``` 3. **单元测试**: ```scala val testData = Seq(InputData(1, null)).toDF assert(testData.filter("values is null").count() == 1) ``` #### 预防措施 1. 在 Case Class 中始终对可能为空的字段使用 `Option[]` 2. 华为云 DLI 作业中配置参数: ```sql SET spark.sql.parquet.mergeSchema=true; SET spark.sql.caseSensitive=true; ``` 3. 数据接入时添加校验层: ```scala val validatedDF = sourceDF.transform { df => df.withColumn("values_valid", when(size(col("values")) > 0, col("values")) .otherwise(lit(Seq.empty[Double])) ) } ``` > **关键原则**:在分布式计算中,数据质量保证应前置于计算过程。华为云环境下建议结合[数据湖探索(DLI)的数据校验功能](https://support.huaweicloud.com/dli_faq/dli_03_0027.html)进行预处理[^4]。 --- ### 相关问题 1. 如何在华为云 Spark 作业中调试 Schema 推断错误? 2. Scala 中 `Option[T]` 与 Java 包装类型(如 `java.lang.Double`)在 Spark 中有何性能差异? 3. 华为云 DLI 如何处理 Parquet/ORC 文件中的复杂数据类型(Array/Map)? 4. 当 Spark 作业同时现 `NullPointerException` 和 `Serialization` 错误时,应如何排查? 5. 在华为云 MRS 集群中,如何通过 Spark UI 定位导致空指针的具体数据分区?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值