我的问题
我目前面临Spark窗口功能的困难。我正在使用Spark(通过pyspark)版本1.6.3
(关联的Python版本2.6.6
)。我运行了一个pyspark shell实例,它自动将HiveContext
初始化为sqlContext
。
我想用window
函数进行滚动求和。我的问题是窗框没有固定:它取决于我们考虑的观察。更具体地说,我通过名为rank_id
的变量对数据进行排序,并希望对索引$ x + 1 $和$ 2x-1 $之间的任何索引$ x $进行滚动求和。因此,我的rangeBetween
必须依赖于rank_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
可以无差别地使用)。
w = Window.orderBy('rank_id').rangeBetween(-1,3)
df1 = df.select('*', psf.sum(df['y']).over(w).alias('roll1'))
#df1.show(3)
#+--------------------+--------------------+-------+------------------+
#| x| y|rank_id| roll1|
#+--------------------+--------------------+-------+------------------+
#|0.016536160706045577|0.009892450530381458| 1|0.9698521852602887|
#| 0.10943843181953838| 0.6478505849227775| 2|1.5744700156326066|
#| 0.13916818312857027| 0.24165348228464578| 3|2.3040547273760392|
#+--------------------+--------------------+-------+------------------+
#only showing top 3 rows
累计和宽不固定
我想在索引 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行,in 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行,in 在sql中输入文件“/opt/application/Spark/current/python/pyspark/sql/context.py”,行> 580 返回DataFrame(self._ssql_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行,装饰 提升AnalysisException(s.split(':',1)[1],stackTrace) pyspark.sql.utils.AnalysisException:你“无法识别windowframeboundary中'rank_id''+''1'附近的输入;第3行pos 15”
我还注意到,当我使用SQL OVER
子句尝试更简单的语句时,我得到了类似的错误,这可能意味着我没有正确地将SQL语句传递给Spark
df2 = sqlContext.sql("""
SELECT *, SUM(y)
OVER (ORDER BY rank_id
RANGE BETWEEN -1 AND 1) AS cumsum
FROM tempdf;
""")
追踪(最近一次通话): 文件“”,第6行,in 在sql中输入文件“/opt/application/Spark/current/python/pyspark/sql/context.py”,第580行 返回DataFrame(self._ssql_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行,装饰 提升AnalysisException(s.split(':',1)[1],stackTrace) pyspark.sql.utils.AnalysisException:你“无法识别' - ''''附近的输入'和'在windowframeboundary中;'第3行pos 15”
如何在Spark中使用window
或SQL
语句来解决我的问题?
答案 0 :(得分:0)
如何在Spark中使用窗口或SQL语句来解决我的问题?
TL; DR 您不能,或者至少不能以可扩展的方式使用当前要求。您可以尝试类似于在RDD上滑动的内容:How to transform data with sliding window over time series data in Pyspark
我还注意到,当我使用SQL OVER子句尝试更简单的语句时,我得到了类似的错误,这可能意味着我没有正确地将SQL语句传递给Spark
这是不正确的。范围规范要求(PRECEDING
| FOLLOWING
| CURRENT_ROW
)规范。也应该没有分号:
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)
但不支持此功能。范围必须是固定大小,不能用表达式定义。
重点是我不想收集数据
没有partitionBy
的窗口定义:
w = Window.orderBy('rank_id').rangeBetween(-1,3)
和收集一样糟糕。所以,即使有“动态框架”(有条件和无界窗口)问题的解决方法,它们也无法帮到你。