我尝试在PySpark中编写一个函数,该函数可以在一定范围内进行组合搜索和查找值。以下是详细说明。
我有两个数据集。
一个数据集,例如D1
,基本上是一个查找表,如下所示:
MinValue MaxValue Value1 Value2
---------------------------------
1 1000 0.5 0.6
1001 2000 0.8 0.1
2001 4000 0.2 0.5
4001 9000 0.04 0.06
另一个数据集,例如D2,是一个包含数百万条记录的表,例如:
ID InterestsRate Days
----------------------------------
1 19.99 29
2 11.99 49
对于每个ID
,我需要根据可能的值为500, 1000, 2000, 3000, 5000
的不同信用额度来计算最大收益。
返回值的计算方式例如
f(x)= InterestsRate *天数* Value1 * Value2。
Value1
和Value2
通过在D1
中查找信用额度来确定。例如,如果信用额度为3000,则将返回查询D1
,0.2和0.5。
对于D2
中的每条记录,我想计算不同信用额度的收益,并找出信用额度和收益,这给了我最大的收益。
到目前为止,我已经完成了两个功能:
我将查找功能定义为
def LookUp(value):
filter_str = "MinValue <=" + str(value) + " and MaxValue >=" + str(value)
return D1.filter(filter_str)
我还将搜索功能定义为
def Search(rate, day):
credit_limit = [500, 1000, 2000, 3000, 5000]
max=0;
cl=-1;
for i in range(1: len(credit_limit)):
v1 = lookup(credit_limit[i]).select("value1")
v2 = lookup(credit_limit[i]).select("value2")
tmp = rate*day*value1*value2
if max < tmp:
max=tmp
cl=credit_limit[i]
return (cl, max)
我将在D2上调用以下转换:
res = D2.mapValues(lambda row: Search(row[1], row[2]))
出乎意料的是,我遇到了错误,并且搜寻到我无法在RDD(D1
)上进行转换时使用数据框(D2
)。
我还用Google搜索可能的解决方案是广播D1
。但是,我不知道如何使其工作。
请您谈谈如何在PySpark中实现此功能?
谢谢!
答案 0 :(得分:1)
在使用spark
时,您应该考虑SQL
和表连接,而不是遍历列表。
所以我要做的第一件事是将您的信用额度列表变成一张表,我们称它为D3
:
credit_limit = [500, 1000, 2000, 3000, 5000]
D3 = spark.createDataFrame([[x] for x in credit_limit], ["CreditLimit"])
D3.show()
#+-----------+
#|CreditLimit|
#+-----------+
#| 500|
#| 1000|
#| 2000|
#| 3000|
#| 5000|
#+-----------+
现在,您可以将此表加入D1
和D2
来计算每个信用额度的收益,然后使用Window
函数选择最大收益来对每个收益进行排名。在您stated in the comments时,如果有平局,我们将选择最高信用额度。
import pyspark.sql.functions as f
from pyspark.sql import Window
w = Window.partitionBy("ID").orderBy(f.desc("Return"), f.desc("CreditLimit"))
D2.alias("D2").crossJoin(D3.alias("D3"))\
.crossJoin(D1.alias("D1"))\
.where("D3.CreditLimit BETWEEN D1.MinValue AND D1.MaxValue")\
.withColumn("Return", f.expr("D2.InterestsRate*D2.Days*D1.Value1*D1.Value2"))\
.withColumn("Rank", f.rank().over(w))\
.where("Rank = 1")\
.drop("Rank")\
.show()
#+---+-------------+----+-----------+--------+--------+------+------+------------------+
#| ID|InterestsRate|Days|CreditLimit|MinValue|MaxValue|Value1|Value2| Return|
#+---+-------------+----+-----------+--------+--------+------+------+------------------+
#| 1| 19.99| 29| 1000| 1| 1000| 0.5| 0.6|173.91299999999998|
#| 2| 11.99| 49| 1000| 1| 1000| 0.5| 0.6| 176.253|
#+---+-------------+----+-----------+--------+--------+------+------+------------------+
我们在这里做2种笛卡尔积,因此可能无法很好地扩展,但是请尝试一下。