【问题标题】:Mask field of column(struct type) in Spark DataFrameSpark DataFrame中列(结构类型)的掩码字段
【发布时间】:2017-10-10 20:22:19
【问题描述】:

我从 XML 文件创建了一个 DataFrame。创建的 DataFrame 具有以下方案。

val df = hiveContext.read.format("com.databricks.spark.xml").option("rowTag", row_tag_name).load(data_dir_path_xml)

df.printSchema()

            root
             |-- samples: struct (nullable = true)
             |    |-- sample: array (nullable = true)
             |    |    |-- element: struct (containsNull = true)
             |    |    |    |-- abc: string (nullable = true)
             |    |    |    |-- def: long (nullable = true)
             |    |    |    |-- type: string (nullable = true)
             |-- abc: string (nullable = true)

我想屏蔽数据框中的 abc/def。

我能够到达我想使用的领域:

val abc = df.select($"samples.sample".getField("abc"))

但我想屏蔽数据帧 df 中的字段 abc/def(用 XXXX 替换 abc 字段)。请帮我解决这个问题

【问题讨论】:

  • 掩码 abc/def 是什么意思?是你想用 def 值屏蔽 abc 吗?
  • 我想将字段 'abc' 和 'def' 替换为值 'xxxxx'。这些字段是敏感数据。
  • 你想替换列值对吗?
  • 没错,我想替换整列的值,@RameshMaharjan

标签: xml scala apache-spark dataframe masking


【解决方案1】:

databricks xml 库中似乎没有太多支持(如果有的话)来处理基于 XML 的数据帧的内容(能够使用 XSLT 不是很酷吗?!)。但是您始终可以直接操作推断的行,例如

val abc = df.map(row => {
  val samples = row.getStruct(0).getSeq(0)
  val maskedSamples = samples.map(sample => {
     Row("xxxxx", sample.getLong(1), sample.getString(2))
  }
  Row(Row(maskedSamples), row.getString(1))
}

上面的代码可能与您想要的转换不完全匹配,因为它有些不清楚,但您明白了。

【讨论】:

    【解决方案2】:

    我建议您将 samples array structType 拆分为单独的 columns (StructFields),以便您可以根据需要屏蔽/替换它们。如果您愿意,您也可以稍后申请 dataframe functions
    下面是分成三列的代码

    df.withColumn("abcd", lit($"samples.sample.abc"))
          .withColumn("def", lit($"samples.sample.def"))
          .withColumn("type", lit($"samples.sample.type"))
    

    如果需要,您可以删除samples column

    .drop("samples")
    

    既然你想用 XXXX 屏蔽 abcdef,你可以这样做

    df.withColumn("abcd", lit("XXXX"))
          .withColumn("def", lit("XXXX"))
          .withColumn("type", lit($"samples.sample.type"))
          .drop("samples")
    

    注意:abcd column name 已被使用,因为您的架构中已经存在另一个 column abc

    为满足以下@Raj cmets 而编辑:

    如果要保留 original schema 并且不需要单独的 columns,则创建 case classudf 函数应该可以解决问题

    def mask = udf((typ: mutable.WrappedArray[String]) => Raj("XXXXX", Option(0L), typ(0)))
    

    Case class 需要Raj

    case class Raj(abc : String,
                   dfe : Option[Long],
                   typ: String)
    

    最后通过在withColumn中传递type来调用udf函数

    df.withColumn("samples", struct(array(mask(col("samples.sample.type"))) as "sample"))
    

    这应该可以为您提供工作输出

    【讨论】:

    • 我尝试使用 df.withColumn。这样做将创建一个带有模式根的数据框 |-- abcd: string (nullable = true) |-- def: long (nullable = true) |-- type: string (nullable = true) |-- abc: string (nullable = true) 但我想要与原始 df 相同的架构。
    • @Raj,我已经用你想要的输出更新了帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多