镶木地板的spark2 sql深度嵌套数组结构

时间:2019-11-16 05:50:07

标签: apache-spark apache-spark-sql parquet spark2

给出这样一个深层嵌套的实木复合地板结构

|-- bet: struct (nullable = true)
|    |-- sides: array (nullable = true)
|    |    |-- element: struct (containsNull = true)
|    |    |    |-- side: string (nullable = true)
|    |    |    |-- betID: string (nullable = true)
|    |    |    |-- secondarybetID: string (nullable = true)
|    |    |    |-- parties: struct (nullable = true)
|    |    |    |    |-- partyIDs: array (nullable = true)
|    |    |    |    |    |-- element: struct (containsNull = true)
|    |    |    |    |    |    |-- partyID: string (nullable = true)
|    |    |    |    |    |    |-- partyRole: integer (nullable = true)
|    |    |    |    |    |    |-- partySubGrp: struct (nullable = true)
|    |    |    |    |    |    |    |-- partySubIDs: array (nullable = true)
|    |    |    |    |    |    |    |    |-- element: struct (containsNull = true)
|    |    |    |    |    |    |    |    |    |-- partySubID: string (nullable = true)
|    |    |    |    |    |    |    |    |    |-- partySubIDType: integer (nullable = true)

考虑到一个投注有多个方面,我们只对sides数组的第一方面感兴趣。  如何找到partyRole为10的一方所涉及的各方?

在prestosql中,我可以做类似

的操作
 SELECT 
        filter(bet.sides[1].parties.partyids, x -> x.partyrole=10)[1] as party10
    FROM 
        parquetbets
    WHERE 
        cardinality(filter(bet.sides[1].parties.partyids, x -> x.partyrole=10))>0

如何在spark2 sql中执行相同的操作?

 SELECT bet.sides[1] from parquetbets 

在spark2 sql中,上述返回的数组没有对嵌套结构进行进一步修剪的范围?

 SELECT bet.sides[1].parties from parquetbets

返回null。我已经尝试了一些组合,但是结果返回WrappedArrayElements,它们不提供查询嵌套数据的机制。 在prestosql中,返回的结果包含字段名称,以便轻松继续并更深入地探究结构。

有人可以指出我如何使用spark2 sql吗? 而且如果spark2 sql无法执行,那么spark数据帧如何做到这一点?

1 个答案:

答案 0 :(得分:0)

傻问题:您是否考虑过将DataSet API与编码器一起使用?它提供了一个功能性API来对您的问题进行推理(这是一种更容易解决功能性的方法)。

否则,请考虑分解数组以对扁平化数据进行推理(请参阅org.apache.spark.sql.functions.explode)。

scala中的示例:

  case class PartyId(partyID: String, partyRole: Int)
  case class Party(partyIDs: Seq[PartyId])
  case class Side(side: String, betId: String, parties: Party)
  case class Bet(sides: Seq[Side])

  import spark.implicits._
  val ds = spark.read.load("my-bets.parquet").as[Bet]

  val firstSidesDS = ds.flatMap(_.sides.headOption) //take the first side if exists

  val result: Dataset[Side] = firstSidesDS.filter(_.parties.partyIDs.exists(_.partyRole == 10)) //Here I return sides for which there is at least a partyRole = 10