连接中的嵌套对象

时间:2019-07-13 09:01:13

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

我有两个要连接在一起的数据框。左侧是俄语文本中的单词列表(单词,结尾,id),右边包含这些单词的所有可能加重形式的列表。这个想法本质上是为每个单词获取建议列表。

联接将导致以下数据框。 ID为2和5的单词每个都有多个建议:

+------------+----+---+----------+------+----+-----------------+-------+
|        word|tail| id|  stressed|  form|type|        word_name|word_id|
+------------+----+---+----------+------+----+-----------------+-------+
|Преступление|    |  0|      null|  null|null|             null|   null|
|           и|    |  1|         и́|Custom|null|                и| 213777|
|   наказание|    |  2| наказа́ние| VinSg|  No|        наказание| 293260|
|   наказание|    |  2| наказа́ние| ImeSg|  No|        наказание| 293260|
|       Роман|    |  3|     Рома́н| ImeSg|  No|            Роман|  46020|
|           в|    |  4|         в|Custom|null|                в| 112374|
|       шести|    |  5|     шести́|   Rod|  Nu|            шесть| 545203|
|       шести|    |  5|     шести́|   Dat|  Nu|            шесть| 545203|
|       шести|    |  5|     шести́|   Pre|  Nu|            шесть| 545203|

我想要的是,而不是为每个建议(经典的左外部联接)输出额外的一行,而是保留右侧表中带有嵌套对象数组的原始行数(即“建议”列)

我可以通过使用collect_list聚合器来接近这一点,它产生以下结果:

+---+------------+----------------------+---------------------+
| id|        word|collect_list(stressed)|collect_list(word_id)|
+---+------------+----------------------+---------------------+
|  0|Преступление|                    []|                   []|
|  1|           и|                   [и́]|             [213777]|
|  2|   наказание|   [наказа́ние, нака...|     [293260, 293260]|
|  3|       Роман|               [Рома́н]|              [46020]|
|  4|           в|                   [в]|             [112374]|
|  5|       шести|    [шести́, шести́, ...| [545203, 545203, ...|

我知道从结构上讲这是可能的,但是我正在努力寻找一种惯用的实现方式(即没有UDF)。

1 个答案:

答案 0 :(得分:0)

经过更多研究,我发现了我在寻找的here

技巧是在连接之前选择要聚合为结构的列:

val dfAccentsGrouped = {
    dfAccentPairs.select($"unstressed", struct("word_id", "stressed", "form", "type"))
}

然后,与我之前的经历类似:

val dfWithSuggestions = {
    dfWords
    .join(dfAccentsGrouped, $"word" === $"unstressed","left_outer").drop("unstressed")
    .groupBy("id", "word", "tail").agg(collect_list("suggestion") as "suggestions")
}

然后准确地得出我想要的结果:

+---+------------+----+------------------------------------------------------------------------------------------+
|id |word        |tail|suggestions                                                                               |
+---+------------+----+------------------------------------------------------------------------------------------+
|0  |Преступление|    |[]                                                                                        |
|1  |и           |    |[[213777, и́, Custom,]]                                                                   |
|2  |наказание   |    |[[293260, наказа́ние, ImeSg, No], [293260, наказа́ние, VinSg, No]]                        |
|3  |Роман       |    |[[46020, Рома́н, ImeSg, No]]                                                              |
|4  |в           |    |[[112374, в, Custom,]]                                                                    |
|5  |шести       |    |[[545203, шести́, Rod, Nu], [545203, шести́, Dat, Nu], [545203, шести́, Pre, Nu]]         |