使用嵌套结构字段进行过滤

时间:2017-09-27 15:42:33

标签: scala apache-spark apache-spark-sql spark-dataframe

|-- data: struct (nullable = true)
 |    |-- keyNote: struct (nullable = true)
 |    |    |-- key: string (nullable = true)
 |    |    |-- note: string (nullable = true)

通过上面的示例结构,我如何选择结构数据和keyNote下的音符字段?

我需要使用两个不同的数据框进行过滤,但似乎无法选择嵌套字段。我正在使用 Spark 1.6.2 ,其中左反不可用,所以我使用了以下过滤器。以下是我尝试过的两种方法。

val dataFrame = esData.join(broadcastDataFrame, esData.select(esData.col("data.keyNote")).col("note") !== broadcastDataFrame("id")) 

Error: Cannot resolve column name "note" among (keyNote)


val dataFrame = esData.join(broadcastDataFrame, esData.select(esData.col("data.keyNote.*")).col("note") !== broadcastDataFrame("id")) 

Error: No such struct field * in key, note


val dataFrame = esData.join(broadcastDataFrame, esData("data.keyNote.note") !== broadcastDataFrame("id")) 

java.lang.IllegalArgumentException: Field "note" does not exist.(..)


val dataFrame = esData.join(broadcastDataFrame, esData.select($"data.keyNote.note").col("note") !== broadcastDataFrame("id")) 

Error: resolved attribute(s) note#9 missing from data#1,id#3 in operator !Join Inner, Some(NOT (note#9 = id#3))

使用的dataFrame是从弹性搜索创建的(工件: elastic-spark-13_2.10,版本:5.1.1

val dataFrameES = context.read.format("org.elasticsearch.spark.sql")
   .options(Map("es.read.field.exclude" ->
    "<Excluding All the fields except those I need>"))
   .load("<Index>/<Type>") 

现在我尝试使用es.read.field.include但我尝试过的任何东西都无法检索嵌套项目,除了排除其他所有内容。我试图包括以下内容; data,data.keyNote,data.keyNote.key,以及每个之后的每个排列加上*的通配符。我不确定这是一个火花的东西还是一个弹性搜索的东西。

我认为在我排除所有不需要的字段并成功检索到我想要的字段之前,架构被读错了。

我认为现在它是连接,因为我能够在这样的过滤器中抓取该字段而没有错误;

 esData.filter(esData("data.keyNote.key").equalTo("x")) 

当我尝试完成上面的连接时,我只是继续遇到错误,这需要我有两个数据集。当我在创建弹性搜索数据框后立即运行上面的过滤器所需的时间比运行卷曲要长得多。

1 个答案:

答案 0 :(得分:1)

正确的语法是:

df1.join(df2, df1("x.y.z") !== df2("v"))

df1.join(df).where(df1("x.y.z") !== df2("v")

完整示例

scala> :paste
// Entering paste mode (ctrl-D to finish)

val esData = sqlContext.read.json(sc.parallelize(Seq(
  """{"data": {"keyNote": {"key":   "foo", "note": "bar"}}}""")))

val broadcastDataFrame = Seq((1L, "foo"), (2L, "bar")).toDF("n", "id")

esData.join(
  broadcastDataFrame, esData("data.keyNote.note") !== broadcastDataFrame("id")
).show

// Exiting paste mode, now interpreting.

+-----------+---+---+
|       data|  n| id|
+-----------+---+---+
|[[foo,bar]]|  1|foo|
+-----------+---+---+

esData: org.apache.spark.sql.DataFrame = [data: struct<keyNote:struct<key:string,note:string>>]
broadcastDataFrame: org.apache.spark.sql.DataFrame = [n: bigint, id: string]

如果您需要antijoin,最好使用外部联接并过滤掉nulls