Python 基于数据帧的火花重叠算法

Python 基于数据帧的火花重叠算法,python,apache-spark,pyspark,apache-spark-sql,Python,Apache Spark,Pyspark,Apache Spark Sql,给定具有以下字段的数据源:product\u id-product-start\u time-end\u time 我正在尝试使用Dataframe函数,基于开始时间和结束时间构建捕获同一产品重叠记录的逻辑 ------------------------------------------------ | product_id | product | start_time | end_time | ------------------------------------------------

给定具有以下字段的数据源:product\u id-product-start\u time-end\u time

我正在尝试使用Dataframe函数,基于开始时间和结束时间构建捕获同一产品重叠记录的逻辑

------------------------------------------------
| product_id | product | start_time | end_time |
------------------------------------------------
|      1     | bottle  |     2      |    4     |
|      2     | bottle  |     3      |    5     |
|      3     | bottle  |     2      |    3     |
|      4     | bottle  |     6      |    7     |
|      1     |   can   |     2      |    4     |
|      2     |   can   |     5      |    6     |
|      3     |   can   |     2      |    4     |
我想接收输出

-------------------------------------------------------------------------------------------------
| product_id_a | product_id_b | product | start_time_a | end_time_a | start_time_b | end_time_b |
-------------------------------------------------------------------------------------------------
|       1      |       2      | bottle  |      2       |     4      |      3       |     5      |
|       1      |       3      | bottle  |      2       |     4      |      2       |     3      |
因为瓶子_1与瓶子_2和瓶子_3有重叠时间,如果满足以下条件,则两条记录重叠:

最大a.开始时间,b.开始时间<最小a.结束时间,b.结束时间 !a、 开始时间==b.开始时间和a.结束时间==b.结束时间 a、 开始时间!=b、 开始| |结束|时间!=b、 结束时间 其中,最后两个条件仅规定我对开始时间和结束时间相等的情况不感兴趣,例如,can_1和can_3不在预期结果中,即使它们具有相同的开始时间和结束时间

因为问题的结构很容易想到使用RDD的MapReduce解决方案,但我对使用Dataframes的解决方案感兴趣

提示:使用groupBy.agg是否有可能指定达到所述逻辑的有趣条件

如需进一步解释,请随时询问

不重复


不幸的是,在报告的答案中使用了F.lag,在我的情况下,这不是一个足够好的条件:F.lag仅使用与先前记录的比较,但在报告的示例中,由于瓶_1不是连续记录,因此不会报告为与瓶_3重叠,因此无法按预期工作

每个条件都可以直接转换为SQL

从pyspark.sql.functions导入列、最小列、最大列 条件1= 最棒的可乐开始时间,可乐开始时间< 最短时间,最短时间 条件2=~ cola.start_time==colb.start_time& cola.end_time==colb.end_time 条件3= 可乐。开始时间!=colb.开始时间| 可乐。结束时间!=结束时间 所以你可以加入并过滤

(df.alias("a").join(df.alias("b"), ["product"]).filter(cond1 & cond2 & cond3))
试试这个:

df.joincloneDf,$label.where$label!==$标签1.其中$min<$max1.其中$min1<$max.show 您需要对数据帧进行笛卡尔积来检查,如果行重叠,您可以根据需要映射它们。当然,您需要省略self-两个相同的行重叠

整个代码:

val df=SparkEmbedded.ss.createDataFrameSeq 1, 2, 5, 2, 4, 7, 3, 6, 9 .toDFproduct_id,最小值,最大值 导入SparkEmbedded.ss.implicits_ val cloneDf=df.selectdf.columns.mapcol:_* .使用列重命名的产品标识,产品标识1 .withColumnRenamedmin,min1 .withColumnRenamedmax,max1 交叉连接 。其中$product\U id<$product\U id1 。其中$min<$max1 。其中$min1<$max.show 为了清楚起见,我将where子句拆分

结果是:

+-----+---+---+------+----+----+
|label|min|max|label1|min1|max1|
+-----+---+---+------+----+----+
|    1|  2|  5|     2|   4|   7|
|    2|  4|  7|     3|   6|   9|
+-----+---+---+------+----+----+
这个例子在Scala中,但是Python有类似的API。

基于@Andronicus,我在纯Python中提出了这种方法

有必要将数据帧与他自己连接起来,以检查行是否重叠。当然,您需要省略self,条件为df.product\u id 整个代码:

从pyspark.sql导入函数为F df=spark.createDataFrame [1,瓶子,2,4, 2瓶,3瓶,5瓶, 3瓶,2瓶,3瓶, 4瓶,6瓶,7瓶, 1,can,2,4, 2,can,5,6, 3,can,2,4], [‘产品id’、‘产品’、‘开始时间’、‘结束时间’] 重复_df=df 条件=[df.product==重复的df.product, df.product\u id<重复的df.product\u id, df.start\u time!=重复的df.start\u time, df.end\u time!=重复的df.end\u time, F.leastdf.end\u时间,重复df.end\u时间> F.greatestdf.start\u time,复制\u df.start\u time] df.joinduplication_df,条件
谢谢!您的解决方案和@user11013893都帮助我解决了问题!您的解决方案中的where$label<$label1帮助我避免了重复的结果,而另一个提供了更有趣的函数。可能交叉连接不是必需的:基于产品的普通内部连接(参见示例)就足够了。我不明白为什么我的问题被否决了,我对你的答案投了赞成票。但我认为您的答案在使用<条件where$label<$label1时更有用。我接受你的建议。为了提高答案的可读性,你能编辑你的帖子,让它更接近我报道的例子吗?因此,将where$label<$label1更改为where$product\u id<$product\u id1,基于产品的连接。。。因此我建议将python代码放在单独的答案中,因为它完全改变了编程风格。Scala是我用Java专业开发的完美之选;>