Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java apachespark在Dataframe中查找第一个不同的前一行_Java_Sql_Apache Spark_Apache Spark Sql_Gaps And Islands - Fatal编程技术网

Java apachespark在Dataframe中查找第一个不同的前一行

Java apachespark在Dataframe中查找第一个不同的前一行,java,sql,apache-spark,apache-spark-sql,gaps-and-islands,Java,Sql,Apache Spark,Apache Spark Sql,Gaps And Islands,我有以下格式的ApacheSpark数据帧 | ID | groupId | phaseName | |----|-----------|-----------| | 10 | someHash1 | PhaseA | | 11 | someHash1 | PhaseB | | 12 | someHash1 | PhaseB | | 13 | someHash2 | PhaseX | | 14 | someHash2 | PhaseY | 每一行代表一个由几个

我有以下格式的ApacheSpark数据帧

| ID |  groupId  | phaseName |
|----|-----------|-----------|
| 10 | someHash1 | PhaseA    |
| 11 | someHash1 | PhaseB    |
| 12 | someHash1 | PhaseB    |
| 13 | someHash2 | PhaseX    |
| 14 | someHash2 | PhaseY    |
每一行代表一个由几个阶段组成的过程中发生的阶段。
ID
列表示阶段的顺序,
groupId
列显示哪些阶段属于一起

我想向dataframe添加一个新列:previousPhaseName。此列应指明同一程序的上一个不同阶段。流程的第一阶段(具有最小ID的阶段)将具有
null
作为前一阶段。当一个阶段出现两次或两次以上时,第二次(第三次…)出现将具有相同的previousPhaseName,例如:

df = 
| ID |  groupId  | phaseName | prevPhaseName |
|----|-----------|-----------|---------------|
| 10 | someHash1 | PhaseA    | null          |
| 11 | someHash1 | PhaseB    | PhaseA        |
| 12 | someHash1 | PhaseB    | PhaseA        |
| 13 | someHash2 | PhaseX    | null          |
| 14 | someHash2 | PhaseY    | PhaseX        |
我不知道如何实施这一点。我的第一个办法是:

  • 创建第二个空数据帧df2
  • 对于df中的每一行:
    查找groupId=row.groupId、ID
  • 将此行添加到df2
  • 连接df1和df2
使用窗口函数的部分解 我使用
窗口函数
聚合前一阶段的名称、组中当前阶段的前一次出现次数(不一定是一行)以及当前和前一阶段名称是否相等的信息:

WindowSpec windowSpecPrev = Window
  .partitionBy(df.col("groupId"))
  .orderBy(df.col("ID"));
WindowSpec windowSpecCount = Window
  .partitionBy(df.col("groupId"), df.col("phaseName"))
  .orderBy(df.col("ID"))
  .rowsBetween(Long.MIN_VALUE, 0);

df
  .withColumn("prevPhase", functions.lag("phaseName", 1).over(windowSpecPrev))
  .withColumn("phaseCount", functions.count("phaseId").over(windowSpecCount))
  .withColumn("prevSame", when(col("prevPhase").equalTo(col("phaseName")),1).otherwise(0))

df = 
| ID |  groupId  | phaseName | prevPhase   | phaseCount | prevSame |
|----|-----------|-----------|-------------|------------|----------|
| 10 | someHash1 | PhaseA    | null        |  1         |  0       |
| 11 | someHash1 | PhaseB    | PhaseA      |  1         |  0       |
| 12 | someHash1 | PhaseB    | PhaseB      |  2         |  1       |
| 13 | someHash2 | PhaseX    | null        |  1         |  0       |
| 14 | someHash2 | PhaseY    | PhaseX      |  1         |  0       |
这仍然不是我想要实现的目标,但现在已经足够好了

进一步的想法 为了获得前一个不同阶段的名称,我看到了三种可能性,但我没有彻底调查:

  • 实现自己的
    lag
    函数,该函数不采用偏移量,而是递归检查前一行,直到找到与给定行不同的值。(尽管我认为在Spark SQL中不可能使用自己的分析窗口函数)
  • 找到一种方法,根据
    phaseCount
    的值动态设置
    lag
    函数的偏移量。(如果相同相位名称的先前出现未在单个序列中出现,则可能会失败)
  • 在存储第一个给定输入的ID和phaseName的窗口上使用
    UserDefinedAggregateFunction
    ,并查找具有不同phaseName的最高ID

我想您可以使用Spark窗口(行帧)功能。检查api文档和下面的帖子


我可以通过以下方式解决此问题:

  • 获取(普通)上一阶段
  • 引入一个新id,将按顺序发生的阶段分组。(借助于此)。这需要两个步骤。首先检查当前和以前的阶段名称是否相等,并相应地分配groupCount值。第二步计算该值的累积和
  • 将序列组第一行的前一阶段分配给其所有成员
  • 实施 结果
    任何建议,特别是关于这些操作效率的建议,我们都将不胜感激。

    谢谢您的建议。我还没有解决这个问题,但它确实把我推向了正确的方向。我找不到其他方法来解决这个问题,你有没有找到更好的方法?顺便说一句,非常聪明地获得了第一个(上一个…)的改变,无论何时发生。我没有进一步研究它,很酷,它帮助了你
    WindowSpec specGroup = Window.partitionBy(col("groupId"))  
                                 .orderBy(col("ID"));
    WindowSpec specSeqGroupId = Window.partitionBy(col("groupId")) 
                                      .orderBy(col("ID"))
                                      .rowsBetween(Long.MIN_VALUE, 0);
    WindowSpec specPrevDiff = Window.partitionBy(col("groupId"), col("seqGroupId"))
                                    .orderBy(col("ID"))
                                    .rowsBetween(Long.MIN_VALUE, 0);
    
    df.withColumn("prevPhase", coalesce(lag("phaseName", 1).over(specGroup), lit("NO_PREV"))) 
      .withColumn("seqCount", when(col("prevPhase").equalTo(col("phaseName")).or(col("prevPhase").equalTo("NO_PREV")),0).otherwise(1))
      .withColumn("seqGroupId", sum("seqCount").over(specSeqGroupId))
      .withColumn("prevDiff", first("prevPhase").over(specPrevDiff));
    
    df = 
    | ID |  groupId  | phaseName | prevPhase | seqCount | seqGroupId | prevDiff |
    |----|-----------|-----------|-----------|----------|------------|----------|
    | 10 | someHash1 | PhaseA    | NO_PREV   |  0       |  0         | NO_PREV  |
    | 11 | someHash1 | PhaseB    | PhaseA    |  1       |  1         | PhaseA   |
    | 12 | someHash1 | PhaseB    | PhaseA    |  0       |  1         | PhaseA   |
    | 13 | someHash2 | PhaseX    | NO_PREV   |  0       |  0         | NO_PREV  |
    | 14 | someHash2 | PhaseY    | PhaseX    |  1       |  1         | PhaseX   |