根据给定条件从数组<struct>中选择一行

时间:2017-10-28 07:21:10

标签: scala apache-spark spark-dataframe user-defined-functions

我有一个具有以下架构的数据框 -

|-- ID: string (nullable = true)
|-- VALUES: array (nullable = true)
|    |-- element: struct (containsNull = true)
|    |    |-- _v1: string (nullable = true)
|    |    |-- _v2: string (nullable = true)

VALUES就像 -

[["ABC","a"],["PQR","c"],["XYZ","b"],["TUV","d"]]
[["PQR","g"]]
[["TUV","f"],["ABC","e"]]

我根据_v1的值从这个数组中选择一个结构。这些值中有一个层次结构,如 -

&#34; ABC&#34; - &GT; &#34; XYZ&#34; - &GT; &#34; PQR&#34; - &GT; &#34; TUV&#34;

现在,如果&#34; TUV&#34;如果存在,我们将选择&#34; TUV&#34;在它的_v1。否则,我们将检查&#34; PQR&#34;。如果&#34; PQR&#34;走了,走了。否则检查&#34; XYZ&#34;等等。

结果df应该看起来像 - (现在是StructType,而不是Array [Struct])

["TUV","d"]
["PQR","g"]
["TUV","f"]

有人可以指导我如何通过创建一个udf来解决这个问题? 提前谢谢。

2 个答案:

答案 0 :(得分:1)

你可以做类似下面的事情

$array = ['PromotionIds' => Array (
    'PromotionId' => Array (
        0 => 'Amazon PLCC Free-Financing Universal Merchant MP-rachmit-1507891499711',
        1 => 'Amazon PLCC Free-Financing Universal Merchant Script-1507895115492'
        )
    )];
$result = [];

foreach ($array['PromotionIds'] as $key => $value) {
    $result[$key]=implode(',', $value);
}

echo "<pre>";
print_r($result);
echo "</pre>";
exit;

您应该有以下输出

import org.apache.spark.sql.functions._
def getIndex = udf((array : mutable.WrappedArray[String]) => {
  if(array.contains("TUV")) array.indexOf("TUV")
  else if(array.contains("PQR")) array.indexOf("PQR")
  else if(array.contains("XYZ")) array.indexOf("XYZ")
  else if(array.contains("ABC")) array.indexOf("ABC")
  else 0
})

df.select($"VALUES"(getIndex($"VALUES._v1")).as("selected"))

我希望答案很有帮助

<强>更新

您可以使用+--------+ |selected| +--------+ |[TUV,d] | |[PQR,g] | |[TUV,f] | +--------+ 表示法选择struct列的元素。此处.正在选择$"VALUES._v1"的所有_v1,并按相同的顺序将其struct传递给udf

例如:对于Array[["ABC","a"],["PQR","c"],["XYZ","b"],["TUV","d"]]会返回$"VALUES._v1",并传递给["ABC","PQR","XYZ","TUV"]函数

udf函数内部,返回字符串匹配的数组的索引。例如:for [&#34; ABC&#34;,&#34; PQR&#34;,&#34; XYZ&#34;,&#34; TUV&#34;],&#34; TUV&#34;匹配所以它将返回3.

对于第一行,udf将返回getIndex($"VALUES._v1"),因此3相当于$"VALUES"(getIndex($"VALUES._v1"),这是$"VALUES"(3)的第四个元素,即{{1} }。

我希望解释清楚。

答案 1 :(得分:1)

只要每行最多只包含一个_v1值一次,这就应该有效。 UDF将返回hierarchy列表中最佳值的索引。然后,将选择_v1中包含此值的stuct并将其放入“select”列。

val hierarchy = List("TUV", "PQR", "XYZ", "ABC")

val findIndex = udf((rows: Seq[String]) => {
  val s = rows.toSet
  val best = hierarchy.filter(h => s contains h).head
  rows.indexOf(best)
})

df.withColumn("select", $"VALUES"(findIndex($"VALUES._v2")))

订单使用了一个列表,可以很容易地扩展到4个以上的值。