Python 在具有非恒定帧大小的Spark中应用窗口功能
我的问题 我目前在使用Spark窗口功能时遇到困难。我正在使用Spark(通过pyspark)版本Python 在具有非恒定帧大小的Spark中应用窗口功能,python,apache-spark,pyspark,window-functions,Python,Apache Spark,Pyspark,Window Functions,我的问题 我目前在使用Spark窗口功能时遇到困难。我正在使用Spark(通过pyspark)版本1.6.3(关联的Python版本2.6.6)。我运行一个pyspark shell实例,该实例自动将HiveContext初始化为我的sqlContext 我想用窗口函数进行滚动求和。我的问题是窗框不是固定的:这取决于我们考虑的观察结果。更具体地说,我通过一个名为rank\u id的变量对数据进行排序,并希望对索引$x+1$和$2x-1$之间的任何索引为$x$的观测值进行滚动求和。因此,我的范围必
1.6.3
(关联的Python版本2.6.6
)。我运行一个pyspark shell实例,该实例自动将HiveContext
初始化为我的sqlContext
我想用窗口
函数进行滚动求和。我的问题是窗框不是固定的:这取决于我们考虑的观察结果。更具体地说,我通过一个名为rank\u id
的变量对数据进行排序,并希望对索引$x+1$和$2x-1$之间的任何索引为$x$的观测值进行滚动求和。因此,我的范围必须取决于rank\u id
变量值
重要的一点是,我不想收集数据,因此不能使用任何类似于numpy
(我的数据有很多观察值)
可复制示例
from pyspark.mllib.random import RandomRDDs
import pyspark.sql.functions as psf
from pyspark.sql.window import Window
# Reproducible example
data = RandomRDDs.uniformVectorRDD(sc, 15, 2)
df = data.map(lambda l: (float(l[0]), float(l[1]))).toDF()
df = df.selectExpr("_1 as x", "_2 as y")
#df.show(2)
#+-------------------+------------------+
#| x| y|
#+-------------------+------------------+
#|0.32767742062486405|0.2506351566289311|
#| 0.7245348534550357| 0.597929853274274|
#+-------------------+------------------+
#only showing top 2 rows
# Finalize dataframe creation
w = Window().orderBy("x")
df = df.withColumn("rank_id", psf.rowNumber().over(w)).sort("rank_id")
#df.show(3)
#+--------------------+--------------------+-------+
#| x| y|rank_id|
#+--------------------+--------------------+-------+
#|0.016536160706045577|0.009892450530381458| 1|
#| 0.10943843181953838| 0.6478505849227775| 2|
#| 0.13916818312857027| 0.24165348228464578| 3|
#+--------------------+--------------------+-------+
#only showing top 3 rows
固定宽度累积和:没问题
使用window
函数,我能够在给定数量的索引上运行一个累积和(我在这里使用rangeBetween
,但在本例中,rowBetween
可以不加区别地使用)
累计总宽度不固定
我想在索引x+1和2x-1之间求和,其中x是我的行索引。当我尝试将其传递给Spark时(与我们对orderBy
所做的方式类似,可能这就是问题所在),我得到了以下错误
# Now if I want to make rangeBetween size depend on a variable
w = Window.orderBy('rank_id').rangeBetween('rank_id'+1,2*'rank_id'-1)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:无法连接'str'和'int'对象
我尝试了其他方法,使用SQL语句
# Using SQL expression
df.registerTempTable('tempdf')
df2 = sqlContext.sql("""
SELECT *, SUM(y)
OVER (ORDER BY rank_id
RANGE BETWEEN rank_id+1 AND 2*rank_id-1) AS cumsum
FROM tempdf;
""")
这一次给了我以下的错误
回溯(最近一次呼叫最后一次):
文件“”,第6行,在
文件“/opt/application/Spark/current/python/pyspark/sql/context.py”,第580行,sql格式
返回数据帧(self.\u ssql\u ctx.sql(sqlQuery),self)
文件“/opt/application/Spark/current/python/lib/py4j-0.9-src.zip/py4j/java_gateway.py”,第813行,调用
文件“/opt/application/Spark/current/python/pyspark/sql/utils.py”,第51行,deco格式
引发分析异常(s.split(“:”,1)[1],stackTrace)
pyspark.sql.utils.AnalysisException:u“无法识别windowframeboundary中'rank_id'+'1'附近的输入;第3行位置15”
我还注意到,当我使用sqlover
子句尝试一个更简单的语句时,我得到了一个类似的错误,这可能意味着我没有正确地将SQL语句传递给Spark
df2 = sqlContext.sql("""
SELECT *, SUM(y)
OVER (ORDER BY rank_id
RANGE BETWEEN -1 AND 1) AS cumsum
FROM tempdf;
""")
回溯(最近一次呼叫最后一次):
文件“”,第6行,在
文件“/opt/application/Spark/current/python/pyspark/sql/context.py”,第580行,sql格式
返回数据帧(self.\u ssql\u ctx.sql(sqlQuery),self)
文件“/opt/application/Spark/current/python/lib/py4j-0.9-src.zip/py4j/java_gateway.py”,第813行,调用
文件“/opt/application/Spark/current/python/pyspark/sql/utils.py”,第51行,deco格式
引发分析异常(s.split(“:”,1)[1],stackTrace)
pyspark.sql.utils.AnalysisException:u“无法识别windowframeboundary中'-''1''和''附近的输入;第3行位置15”
如何在Spark中使用window
或SQL
语句来解决问题
如何在Spark中使用window或SQL语句来解决问题
TL;DR您不能,或者至少不能以可扩展的方式,满足当前的需求。您可以尝试类似于在RDD上滑动的方法:
我还注意到,当我尝试使用SQLOVER子句执行更简单的语句时,我遇到了一个类似的错误,这可能意味着我没有正确地将SQL语句传递给Spark
df2 = sqlContext.sql("""
SELECT *, SUM(y)
OVER (ORDER BY rank_id
RANGE BETWEEN -1 AND 1) AS cumsum
FROM tempdf;
""")
这是不正确的。范围规格要求(前面的
|后面的
|当前行
)规格。此外,不应使用分号:
SELECT *, SUM(x)
OVER (ORDER BY rank_id
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS cumsum
FROM tempdf
我想在索引x+1和2x-1之间求和,其中x是我的行索引。当我尝试将其传递给Spark时(类似于我们对orderBy所做的方式,可能这就是问题所在),我得到了以下错误
TypeError:无法连接'str'和'int'对象
正如异常所说-您不能对字符串和整数调用+
。您可能想要专栏:
from pyspark.sql.functions import col
.rangeBetween(col('rank_id') + 1, 2* col('rank_id') - 1)
但这是不受支持的。范围必须具有固定大小,并且不能用表达式定义
重要的一点是,我不想收集数据
不带分区的窗口定义
w = Window.orderBy('rank_id').rangeBetween(-1,3)
和收集一样糟糕。所以,即使有解决“动态框架”(带有条件和无界窗口)问题的变通方法,它们在这里也帮不了你