我有 2 个数据帧:
用户(~29.000.000 个条目(
|-- userId: string (nullable = true)
展示次数(~1000 个条目(
|-- modules: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- content: array (nullable = true)
| | | |-- element: string (containsNull = true)
| | |-- id: string (nullable = true)
我想遍历所有用户,并从这 ~1000 个条目中附加到每个用户 1 个印象。因此,实际上在每个 ~1000 个用户处,展示次数将是相同的,然后展示次数的循环将从头开始,并为接下来的 ~1000 个用户分配相同的 ~1000 次展示。最后,我想拥有一个包含组合数据的数据帧。此外,用户数据帧可以通过添加展示次数的列来重复使用,或者新创建的数据框也可以因此工作。
您有任何想法,哪个是这里的好解决方案?
我要做的是使用向两个数据帧添加一个单递增 ID 的旧技巧,然后在您的 LARGER 数据帧(用户(上创建一个新列,其中包含每行 ID 的模数和较小数据帧的大小。
然后,此新列会针对"展示次数"数据框中的项目提供滚动匹配键。
这是一个最小的示例(经过测试(,可以为您提供想法。显然,如果您有 1000 次展示要加入,这将起作用:
var users = Seq("user1", "user2", "user3", "user4", "user5", "user6", "user7", "user8", "user9").toDF("users")
var impressions = Seq("a", "b", "c").toDF("impressions").withColumn("id", monotonically_increasing_id())
var cnt = impressions.count
users=users.withColumn("id", monotonically_increasing_id())
.withColumn("mod", $"id" mod cnt)
.join(impressions, $"mod"===impressions("id"))
.drop("mod")
users.show
+-----+---+-----------+---+
|users| id|impressions| id|
+-----+---+-----------+---+
|user1| 0| a| 0|
|user2| 1| b| 1|
|user3| 2| c| 2|
|user4| 3| a| 0|
|user5| 4| b| 1|
|user6| 5| c| 2|
|user7| 6| a| 0|
|user8| 7| b| 1|
|user9| 8| c| 2|
+-----+---+-----------+---+
想法草图:
-
通过以下方式向数据帧用户和展示次数添加单调递增的 id
val indexedUsersDF = usersDf.withColumn("index", monotonicallyIncreasingId) val indexedImpressionsDF = impressionsDf.withColumn("index", monotonicallyIncreasingId)
(请参阅Spark数据帧:如何添加索引列(
-
通过
count
确定展示次数中的行数并存储为 int,例如val numberOfImpressions = ...
-
将 UDF 应用于
indexedUsersDF
中的索引列,该索引列在单独的列中计算模数(例如 moduloIndex(val moduloIndexedUsersDF = indexedUsersDF.select(...)
-
加入
moduloIndexedUsersDF
并indexedImperessionsDF
moduloIndexedUsersDF("moduloIndex")===indexedImpressions("index")