Apache spark 如何通过自定义行分组来简化PySpark中的EbyKey?

Apache spark 如何通过自定义行分组来简化PySpark中的EbyKey?,apache-spark,pyspark,apache-spark-sql,rdd,Apache Spark,Pyspark,Apache Spark Sql,Rdd,我有一个如下所示的数据框: items_df ====================================================== | customer item_type brand price quantity | |====================================================| | 1 bread reems 20 10 | |

我有一个如下所示的数据框:

items_df
======================================================
| customer   item_type    brand    price    quantity |  
|====================================================|
|  1         bread        reems     20         10    |  
|  2         butter       spencers  10         21    |  
|  3         jam          niles     10         22    |
|  1         bread        marks     16         18    |
|  1         butter       jims      19         12    |
|  1         jam          jills     16         6     |
|  2         bread        marks     16         18    |
======================================================
我创建了一个rdd,将上述内容转换为dict:

rdd = items_df.rdd.map(lambda row: row.asDict())
结果如下:

[ {客户:1,商品类型:面包,品牌:reems,价格:20,数量:10}, {客户:2,商品类型:黄油,品牌:斯宾塞,价格:10,数量:21}, {客户:3,商品类型:果酱,品牌:尼尔斯,价格:10,数量:22}, {客户:1,商品类型:面包,品牌:商标,价格:16,数量:18}, {客户:1,商品类型:黄油,品牌:吉姆斯,价格:19,数量:12}, {客户:1,商品类型:果酱,品牌:吉尔,价格:16,数量:6}, {客户:2,商品类型:面包,品牌:商标,价格:16,数量:18} ] 我想先按客户对上述行进行分组。然后,我想介绍定制的新钥匙面包、黄油、果酱,并为该客户分组所有这些行。因此,我的rdd从7行减少到3行

输出如下所示:

items_df
======================================================
| customer   item_type    brand    price    quantity |  
|====================================================|
|  1         bread        reems     20         10    |  
|  2         butter       spencers  10         21    |  
|  3         jam          niles     10         22    |
|  1         bread        marks     16         18    |
|  1         butter       jims      19         12    |
|  1         jam          jills     16         6     |
|  2         bread        marks     16         18    |
======================================================
[ { 顾客:1,, 面包:[ {项目类型:面包,品牌:reems,价格:20,数量:10}, {项目类型:面包,品牌:标记,价格:16,数量:18}, ], 黄油:[ {项目类型:黄油,品牌:吉姆斯,价格:19,数量:12} ], 堵塞:[ {项目类型:果酱,品牌:吉尔,价格:16,数量:6} ] }, { 顾客:2,, 面包:[ {项目类型:面包,品牌:标记,价格:16,数量:18} ], 黄油:[ {项目类型:黄油,品牌:斯宾塞,价格:10,数量:21} ], 堵塞:[] }, { 顾客:3,, 面包:[], 巴特斯:[], 堵塞:[ {项目类型:果酱,品牌:尼尔斯,价格:10,数量:22} ] } ] 有人知道如何使用PySpark实现上述功能吗?我想知道是否有使用reduceByKey或类似的解决方案。如果可能的话,我希望避免使用groupByKey。

首先向pivot dataframe添加一个列项类型

items_df=items_df.带有列'item_types',F.concatF.列'item_types',F.lit's' 展品 +----+-----+----+---+----+-----+ |客户|项目|类型|品牌|价格|数量|项目|类型| +----+-----+----+---+----+-----+ |1 |面包|里姆斯| 20 | 10 |面包| |2 |黄油|斯宾塞| 10 | 21 |黄油| |3 |果酱|尼尔斯| 10 | 22 |果酱| |1 |面包|标记| 16 | 18 |面包| |1 |黄油|吉姆| 19 | 12 |黄油| |1 |果酱|吉尔| 16 | 6 |果酱| |2 |面包|标记| 16 | 18 |面包| +----+-----+----+---+----+-----+ 然后,您可以使用customer group透视表,并使用F.collect_list同时聚合其他列

items_df=items_df.groupby['customer'].pivotitem_types.agg F.collect\u listF.structF.colitem\u type、F.colbrand、F.colprice、F.colquantity .将“客户”分类 展品 +----+----------+----------+----------+ |顾客|面包|黄油|果酱| +----+----------+----------+----------+ |面包,里姆斯,黄油,吉姆斯,果酱,吉尔斯,16| |面包,马克,黄油,斯宾塞| |果酱,尼尔斯,10| +----+----------+----------+----------+ 最后,需要设置recursive=True以将嵌套行转换为dict

rdd=items\u df.rdd.maplambda行:行。asDictrecursive=True printrdd.take10 [{'客户]:1, “面包”:[{'item_type':u'bread','brand':u'reems','price':20','quantity':10}, {'item_type':u'bread','brand':u'marks','price':16,'quantity':18}], “黄油”:[{'item_type':u'butter','brand':u'jims','price':19,'quantity':12}], “果酱”:[{'item_type':u'jam','brand':u'jills','price':16','quantity':6}]}, {'customer':2, “面包”:[{'item_type':u'bread','brand':u'marks','price':16','quantity':18}], “黄油”:[{'item_type':u'butter','brand':u'spencers','price':10,'quantity':21}], “堵塞”:[]}, {'customer':3, “面包”:[], “黄油”:[], “果酱”:[{'item_type':u'jam','brand':u'niles','price':10','quantity':22}]]
我还使用了另一种方法在rdd中使用reduceByKey。给定dataframe项_df,首先将其转换为rdd:

rdd = items_df.rdd.map(lambda row: row.asDict())
将每一行转换为tuple customer,[row_obj]其中row_obj位于列表中:

rdd = rdd.map(lambda row: ( row["customer"], [row] ) )
使用reduceByKey按客户分组,其中列表为给定客户连接:

rdd = rdd.reduceByKey(lambda x,y: x+y)
将元组转换回dict,其中键是customer,值是所有关联行的列表:

rdd = rdd.map(lambda tup: { tup[0]: tup[1] } )
由于每个客户数据现在都是一行,我们可以使用自定义函数将数据分离为面包、黄油、果酱:

def在客户视图中组织项目: cust_id=listrow.keys[0] 项目=行[客户id] new_cust_obj={客户:客户id,面包:[],黄油:[],果酱:[] } 复数={面包:面包,黄油:黄油,果酱:果酱} 对于项目中的项目: 项目类型=项目[项目类型] 键=复数[项目类型] 新建客户对象[key]。追加项 返回新的客户对象 调用上述函数转换rdd:

rdd = rdd.map(organize_items_in_customer)

非常感谢@giser_yugang!这是一个很好的解释