我写了一些代码来更新for循环中的数据框,但结果却很奇怪:
def _simulate_walks(self):
# sample starting nodes
aprox_sample_rate = 1.0 * self._num_of_walks / self._vertices.count()
starting_nodes = self._vertices.sample(True, aprox_sample_rate)
starting_nodes.show()
# iterate over walks
alias_draw_udf = F.udf(Node2Vec._alias_draw, T.StringType())
single_list_udf = F.udf(lambda e: [e], T.ArrayType(T.StringType()))
append_list_udf = F.udf(lambda l,e: l+[e], T.ArrayType(T.StringType()))
for i in range(self._walk_length):
if i == 0:
chosen_path = starting_nodes.join(self._nodes_alias, F.col(self._src_col) == F.col('NODE'))\
.withColumn('CHOSEN_NODE', alias_draw_udf('ALIAS'))\
.withColumn('PATH', single_list_udf('NODE'))\
.selectExpr('NODE as LAST_NODE', 'CHOSEN_NODE', 'PATH').persist()
#chosen_path.show()
else:
chosen_path = chosen_path.join(self._edges_alias, (F.col('LAST_NODE') == F.col(self._src_col)) &
(F.col('CHOSEN_NODE') == F.col(self._dst_col)))\
.withColumn('NEW_CHOSEN_NODE', alias_draw_udf('ALIAS'))
#chosen_path.show()
chosen_path = chosen_path\
.selectExpr('CHOSEN_NODE as LAST_NODE', 'NEW_CHOSEN_NODE as CHOSEN_NODE', 'PATH')
#chosen_path.show()
chosen_path = chosen_path.withColumn('NEW_PATH', append_list_udf('PATH', 'CHOSEN_NODE'))\
.selectExpr('LAST_NODE', 'CHOSEN_NODE', 'NEW_PATH as PATH')
chosen_path.show(5, False)
但是,当我在循环中添加persist命令时:
chosen_path = chosen_path.withColumn('NEW_PATH', append_list_udf('PATH', 'CHOSEN_NODE'))\
.selectExpr('LAST_NODE', 'CHOSEN_NODE', 'NEW_PATH as PATH').persist()
代码可以完美运行。
我知道一个事实,即在执行动作之前,代码会被懒惰地评估,但是我无法想象这会导致意外的结果。
不用说,由于高内存消耗,在每次迭代中保持持久状态不是一个很好的解决方案,我想知道解决该问题的最佳实践是什么(也许不持久化所有内存并在持久存储新数据帧之后立即使用?)。
谢谢。
答案 0 :(得分:0)
为什么不使用functools.reduce()? 示例:
from functools import reduce
def join_all_dataframes(dfs: List[DataFrame], on_columns: List[str]) -> DataFrame
return reduce(lambda x, y: x.join(y, on_columns, 'outer'),
dfs).dropDuplicates()