选择以特定模式开头的字段:Spark XML Parsing

Posted

技术标签:

【中文标题】选择以特定模式开头的字段:Spark XML Parsing【英文标题】:Select Fields that start with a certain pattern: Spark XML Parsing 【发布时间】:2018-06-12 23:14:49 【问题描述】:

我不得不解析一些非常大的 xml 文件。我想提取这些 xml 文件中的一些字段,然后对它们执行一些工作。但是,我需要遵循一些规则,即我只能选择遵循某种模式的字段。

这是我想要实现的一个示例:

// Some made up data
val schema = new StructType()
      .add("devices", 
        new StructType()
          .add("thermostats", MapType(StringType,
            new StructType()
              .add("device_id", StringType)
              .add("locale", StringType)
              .add("E2EDK1000", StringType)
              .add("E2EDK2000", StringType)
              .add("E2EDK3000", StringType))))

val nestDataDS2 = Seq("""
    "devices": 
      "thermostats": 
          "peyiJNo0IldT2YlIVtYaGQ": 
            "device_id": "peyiJNo0IldT2YlIVtYaGQ",
            "locale": "en-US",
            "E2EDK1000": "4.0",
            "E2EDK2000": "VqFabWH21nwVyd4RWgJgNb292wa7hG_dUwo2i2SG7j3-BOLY0BA4sw",
            "E2EDK3000": "Hallway Upstairs"""").toDS
val nestDF2 = spark
            .read
            .schema(nestSchema2)
            .json(nestDataDS2.rdd)

root
 |-- devices: struct (nullable = true)
 |    |-- thermostats: map (nullable = true)
 |    |    |-- key: string
 |    |    |-- value: struct (valueContainsNull = true)
 |    |    |    |-- device_id: string (nullable = true)
 |    |    |    |-- locale: string (nullable = true)
 |    |    |    |-- E2EDK1000: string (nullable = true)
 |    |    |    |-- E2EDK2000: string (nullable = true)
 |    |    |    |-- E2EDK3000: string (nullable = true)

鉴于此,我想进入值字段,因此我执行以下操作

val tmp = nestDF2.select($"devices.thermostats.value")
root
 |-- value: struct (nullable = true)
 |    |-- device_id: string (nullable = true)
 |    |-- locale: string (nullable = true)
 |    |-- E2EDK1000: string (nullable = true)
 |    |-- E2EDK2000: string (nullable = true)
 |    |-- E2EDK3000: string (nullable = true)

这是我的问题:我想选择 value 中以以下模式 E2EDK1 开头的所有字段。但是,我坚持如何做到这一点。这是我想要的最终结果:

root
 |-- E2EDK1000: string (nullable = true)

我知道我可以直接选择该字段,但在我处理的数据中,E2EDK1000 并不总是存在。永远存在的是 E2EDK1。

我尝试过使用 startsWith() 但这似乎不起作用,例如

val tmp2 = tmp
  .select($"value".getItem(_.startsWith("E2EDK1")))

【问题讨论】:

【参考方案1】:

您可以使用.*将value列的所有元素选择到单独的列中,过滤所有以E2EDK1开头的元素名称,最后只选择那些列,如下所示

//flattens the struct value column to separate columns
val tmp = nestDF2.select($"devices.thermostats.value.*")
//filter in the column names that starts with E2EDK1
val e2edk1Columns = tmp.columns.filter(_.startsWith("E2EDK1"))
//select only the columns that starts with E2EDK1
tmp.select(e2edk1Columns.map(col):_*)

它应该为您提供以E2EDK1 开头的 value struct column 的所有元素作为单独的列。对于您给定的示例,您应该将输出为

+---------+
|E2EDK1000|
+---------+
|null     |
+---------+

root
 |-- E2EDK1000: string (nullable = true)

如果您愿意,可以将它们组合回struct

【讨论】:

以上是关于选择以特定模式开头的字段:Spark XML Parsing的主要内容,如果未能解决你的问题,请参考以下文章

如何选择以公共标签开头的所有列

oracle 如何查找特定字母开头的某个字段?

查找以特定模式开头的属性名称

Spark UDF:如何在每一行上编写一个 UDF 以提取嵌套结构中的特定值?

JSON 字段名称可以以数字开头吗?

如何选择仅以特定前缀开头的字符串