当前位置: 首页 > 知识库问答 >
问题:

如何在Spark中将超过1000个元素的结构的所有元素连接起来

武睿
2023-03-14

我有一个spark数据帧,如下所示,带有一个<code>结构</code>字段。

val arrayStructData = Seq(
Row("James",Row("Java","XX",120)),
Row("Michael",Row("Java","",200)),
Row("Robert",Row("Java","XZ",null)),
Row("Washington",Row("","XX",120))
)

val arrayStructSchema = new StructType().add("name",StringType).add("my_struct", new StructType().add("name",StringType).add("author",StringType).add("pages",IntegerType))

val df = spark.createDataFrame(spark.sparkContext.parallelize(arrayStructData),arrayStructSchema)


df.printSchema()
root
 |-- name: string (nullable = true)
 |-- my_struct: struct (nullable = true)
 |    |-- name: string (nullable = true)
 |    |-- author: string (nullable = true)
 |    |-- pages: integer (nullable = true)

df.show(false)

+----------+---------------+
|name      |my_struct      |
+----------+---------------+
|James     |[Java, XX, 120]|
|Michael   |[Java, , 200]  |
|Robert    |[Java, XZ,]    |
|Washington|[, XX, 120]    |
+----------+---------------+

我想构造一个名为< code>final_list的输出列,显示结构中元素的存在与否。问题是,在这个例子中,struct元素只限于3个,但在实际数据中,struct中有1,000个元素,每个记录可能包含也可能不包含每个元素中的值。

以下是我想要构建列的方式 -

val cleaned_df = spark.sql(s"""select name, case when my_struct.name = "" then "" else "name" end as name_present
, case when my_struct.author = "" then "" else "author" end as author_present 
, case when my_struct.pages = "" then "" else "pages" end as pages_present 
from df""")
cleaned_df.createOrReplaceTempView("cleaned_df")
cleaned_df.show(false)
+----------+------------+--------------+-------------+
|name      |name_present|author_present|pages_present|
+----------+------------+--------------+-------------+
|James     |name        |author        |pages        |
|Michael   |name        |              |pages        |
|Robert    |name        |author        |pages        |
|Washington|            |author        |pages        |
+----------+------------+--------------+-------------+

因此,我为每个专栏编写一个案例陈述,以捕捉它的存在与否。然后我做如下操作以获得最终输出 -

val final_df = spark.sql(s"""
select name, concat_ws("," , name_present, author_present, pages_present) as final_html" target="_blank">list
from cleaned_df
""")
final_df.show(false)
+----------+-----------------+
|name      |final_list       |
+----------+-----------------+
|James     |name,author,pages|
|Michael   |name,,pages      |
|Robert    |name,author,pages|
|Washington|,author,pages    |
+----------+-----------------+

我无法编写一个巨大的case语句来捕获1000个元素的结构。有更聪明的方法吗?也许是UDF?

我正在使用火花 2.4.3。我不知道是否有任何高阶函数支持这一点。但是我的真实数据帧的模式如下所示 -

 |-- name: string (nullable = true)
 |-- my_struct: struct (nullable = true)
 |    |-- name: string (nullable = true)
 |    |-- author: string (nullable = true)
 |    |-- element3: integer (nullable = true)
 |    |-- element4: string (nullable = true)
 |    |-- element5: double (nullable = true)
 .....
 .....
 |    |-- element1000: string (nullable = true)

共有2个答案

翟嘉年
2023-03-14

没有 UDF

计划

scala> df.printSchema
root
 |-- name: string (nullable = true)
 |-- my_struct: struct (nullable = true)
 |    |-- name: string (nullable = true)
 |    |-- author: string (nullable = true)
 |    |-- pages: integer (nullable = true)

构造表达式

scala> 
val expr = df
    .select("my_struct.*") // Extracting struct columns.
    .columns
    .map(c => (c, trim(col(s"my_struct.${c}")))) // Constructing tupes ("name", trim(col("my_struct.name")))
    .map(c => when(c._2.isNotNull and c._2 =!= "",lit(c._1))) // Checking Not Null & Empty values.

expr: Array[org.apache.spark.sql.Column] = Array(CASE WHEN ((trim(my_struct.name) IS NOT NULL) AND (NOT (trim(my_struct.name) = ))) THEN name END, CASE WHEN ((trim(my_struct.author) IS NOT NULL) AND (NOT (trim(my_struct.author) = ))) THEN author END, CASE WHEN ((trim(my_struct.pages) IS NOT NULL) AND (NOT (trim(my_struct.pages) = ))) THEN pages END)

将表达式应用于数据帧

scala> df.withColumn("final_list",concat_ws(",",expr:_*)).show
+----------+---------------+-----------------+
|      name|      my_struct|       final_list|
+----------+---------------+-----------------+
|     James|[Java, XX, 120]|name,author,pages|
|   Michael|  [Java, , 200]|       name,pages|
|    Robert|    [Java, XZ,]|      name,author|
|Washington|    [, XX, 120]|     author,pages|
+----------+---------------+-----------------+

咸亦
2023-03-14

您已经提到了UDF。使用UDF,您可以遍历my_struct的所有字段并收集标志:

def availableFields = (in:Row) => {
  val ret = scala.collection.mutable.ListBuffer.empty[String]
  for( i <- Range(0, in.size)) {
    if( !in.isNullAt(i) && in.get(i) != "") {
      ret += in.schema.fields(i).name
    }
  }
  ret.mkString(",")
}
val availableFieldsUdf = udf(availableFields)

df.withColumn("final_list", availableFieldsUdf(col("my_struct")) ).show(false)

指纹

+----------+---------------+-----------------+
|name      |my_struct      |final_list       |
+----------+---------------+-----------------+
|James     |[Java, XX, 120]|name,author,pages|
|Michael   |[Java, , 200]  |name,pages       |
|Robert    |[Java, XZ,]    |name,author      |
|Washington|[, XX, 120]    |author,pages     |
+----------+---------------+-----------------+
 类似资料:
  • 假设我有这样的html: 我只想获得之前的 。有没有办法用JSOUP做到这一点呢?我知道我可以把所有的宠物都弄成这样: 但这也包括额外的宠物。我想知道我是只能选择上面的宠物还是只是删除下面的宠物然后使用那个代码?

  • 问题内容: 我有一个元素。如何将CSS样式应用于此元素的所有子元素?我只想将样式应用于子元素。不是它的大孩子。 我可以用 这对所有孩子都有效,但我想对所有孩子都适用的解决方案。我以为我可以用,但是 不起作用。 编辑 该选择不使用Firefox 26应用规则,并有根据萤火没有其他规则的保证金。如果我替换为,它会起作用。 问题答案: 这些子元素的后代将(可能)继承分配给那些子元素的大多数样式。 您需要

  • 如何选择js中元素的所有li子元素 我想选择这个项目的所有li元素(直接子元素,盛大子元素)

  • DocBook 中的一些元素,在发布的时候会作为条目被收进目录。它们表示的是文档内部的结构,所以它们是结构元素,如下: <set> <book><part><chapter> <sect1> <sect2> ………… </sect2> </sect1></chapter> </part> </book> </set> 如果 DocBook 的根元素是art

  • 问题内容: 我对如何在Java中执行此操作有一般的想法,但是我正在学习Python,但不确定如何执行。 我需要实现一个函数,该函数返回一个包含列表中所有其他元素的列表,从第一个元素开始。 到目前为止,我不确定从这里开始该怎么做,因为我只是在学习Python中的for循环是如何不同的: 问题答案:

  • 我是冬眠新手,不会RTFM,所以我希望有人能帮我节省很多时间。 我的数据库中的对象之间有多对多的关系。假设员工和工作。 我想选择分配给给定员工的所有作业。我的对象乔布斯有一个正在处理它的所有员工的列表。所以,在java中,它应该是:作业job.employees.contains(员工)。除了我需要把它变成一个Hibernate查询什么的。 现在,我在选择所有东西后,正在Java中使用蛮力。 如何