Spark在读取原始日志信息时,有时会遇到一些脏数据导致某些算子无法正常使用。
过滤错误数据
如果过滤掉脏数据对总体计算并没有多大影响的情况下,通常可以直接过滤掉错误格式的数据。
val schema=spark.read.json(hdfsPath).schema
spark.read.schema(schema).option("mode", "DROPMALFORMED").json(hdfsPath)
ex:
//原数据
val origin_data="""{"a": 1, "b":2, "c":3}|{"a": 1, "b":2, "c":3}""".split('|')
//包含脏数据的数据
val error_data = """{"a": 1, "b":2, "c":3}|{"a": 1, "b":2, "c":3}|{aaaaa}""".split('|')
//指定数据源的StructType
val schema=spark.read.json(sc.parallelize(origin_data)).schema
//option("mode", "DROPMALFORMED") 过滤schema不同的数据
val result = spark.read.schema(schema).option("mode", "DROPMALFORMED")
.json(sc.parallelize(error_data)).show()
+---+---+---+
| a| b| c|
+---+---+---+
| 1| 2| 3|
| 1| 2| 3|
+---+---+---+
结果会过滤掉不符合StructType的数据{aaaaa}
捕捉错误数据
除了上述情况,我们有时候还需要对这些脏数据进行比对,亦或者是对这些脏数据进行再处理。
import org.apache.spark.sql.types._
//原数据
val origin_data="""{"a": 1, "b":2, "c":3}|{"a": 1, "b":2, "c":3}""".split('|')
//包含脏数据的数据
val error_data = """{"a": 1, "b":2, "c":3}|{"a": 1, "b":2, "c":3}|{aaaaa}""".split('|')
//指定数据源的StructType
val schema=spark.read.json(sc.parallelize(origin_data)).schema
val newSchema=schema.add(StructField("error_record",StringType, true))
val corruptDf = spark.read.schema(newSchema)
//option("mode", "PERMISSIVE")通常为spark默认的读取模式,可以省略
.option("mode", "PERMISSIVE")
//指定存放错误数据的字段名
.option("columnNameOfCorruptRecord", "error_record")
.json(sc.parallelize(error_data)).filter($"error_record".isNotNull).show()
+----+----+----+------------+
| a| b| c|error_record|
+----+----+----+------------+
|null|null|null| {aaaaa}|
+----+----+----+------------+
结果会将整行的脏数据显示在error_record列中