Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.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
如何计算Spark JavaRDD中当前行和前一行之间的差异_Java_Apache Spark_Rdd - Fatal编程技术网

如何计算Spark JavaRDD中当前行和前一行之间的差异

如何计算Spark JavaRDD中当前行和前一行之间的差异,java,apache-spark,rdd,Java,Apache Spark,Rdd,我将.log文件解析为JavaRDD,在对这个JavaRDD进行排序之后,现在我有了,例如oldJavaRDD: 2016-03-28 | 11:00 | X | object1 | region1 2016-03-28 | 11:01 | Y | object1 | region1 2016-03-28 | 11:05 | X | object1 | region1 2016-03-28 | 11:09 | X | object1 | region1 2016-03-28 | 11:00 |

我将
.log
文件解析为JavaRDD,在对这个JavaRDD进行排序之后,现在我有了,例如
oldJavaRDD

2016-03-28 | 11:00 | X | object1 | region1

2016-03-28 | 11:01 | Y | object1 | region1

2016-03-28 | 11:05 | X | object1 | region1

2016-03-28 | 11:09 | X | object1 | region1

2016-03-28 | 11:00 | X | object2 | region1

2016-03-28 | 11:01 | Z | object2 | region1

如何获取
newJavaRDD
以将其保存到DB?
新的JavaRDD结构必须是:
2016-03-28 | 9 | object1 | region1

2016-03-28 | 1 |对象2 |区域1

因此,我必须计算当前行和前一行之间的时间(在某些情况下还使用标志
X,Y,Z
来定义,是否将时间添加到结果中),并在更改
日期、objectName
objectRegion
后向JavaRDD添加新元素

我可以使用这种类型的代码(map),但我认为这不是好的,也不是最快的方法

    JavaRDD<NewObject> newJavaRDD = oldJavaRDD.map { r -> 
      String datePrev[] = ...
        if (datePrev != dateCurr ...) {
          return newJavaRdd;
        } else {
          return null;
        }
    }
JavaRDD newJavaRDD=oldJavaRDD.map{r->
字符串datePrev[]=。。。
如果(datePrev!=dateCurr…){
返回newJavaRdd;
}否则{
返回null;
}
}

首先,您的代码示例从创建
newJavaRDD
的转换中引用了
newJavaRDD
——这在几个不同的级别上是不可能的:

  • 您不能引用变量声明右侧的变量
  • 您不能在RDD上的转换中使用RDD(相同的一个或另一个-这无关紧要)-转换中的任何内容都必须由Spark序列化,Spark不能序列化其自己的RDD(这毫无意义)
那么,你应该怎么做呢

假设

  • 这里的目的是为
    日期
    +
    对象
    +
    区域
  • 对于每个这样的组合,不应该有太多的记录,因此可以安全地将这些字段作为键
  • 您可以
    groupBy
    关键字段,然后
    mapValues
    获取第一条记录和最后一条记录之间的“分钟距离”(如果我没有正确理解,传递到
    mapValues
    的函数可以更改为包含您的确切逻辑)。我将使用Joda Time库进行时间计算:

    public static void main(String[] args) {
        // some setup code for this test:
        JavaSparkContext sc = new JavaSparkContext("local", "test");
    
        // input:
        final JavaRDD<String[]> input = sc.parallelize(Lists.newArrayList(
                //              date        time     ?    object     region
                new String[]{"2016-03-28", "11:00", "X", "object1", "region1"},
                new String[]{"2016-03-28", "11:01", "Y", "object1", "region1"},
                new String[]{"2016-03-28", "11:05", "X", "object1", "region1"},
                new String[]{"2016-03-28", "11:09", "X", "object1", "region1"},
                new String[]{"2016-03-28", "11:00", "X", "object2", "region1"},
                new String[]{"2016-03-28", "11:01", "Z", "object2", "region1"}
        ));
    
        // grouping by key:
        final JavaPairRDD<String, Iterable<String[]>> byObjectAndDate = input.groupBy(new Function<String[], String>() {
            @Override
            public String call(String[] record) throws Exception {
                return record[0] + record[3] + record[4]; // date, object, region
            }
        });
    
        // mapping each "value" (all record matching key) to result
        final JavaRDD<String[]> result = byObjectAndDate.mapValues(new Function<Iterable<String[]>, String[]>() {
            @Override
            public String[] call(Iterable<String[]> records) throws Exception {
                final Iterator<String[]> iterator = records.iterator();
                String[] previousRecord = iterator.next();
                int diffMinutes = 0;
    
                for (String[] record : records) {
                    if (record[2].equals("X")) {  // if I got your intention right...
                        final LocalDateTime prev = getLocalDateTime(previousRecord);
                        final LocalDateTime curr = getLocalDateTime(record);
                        diffMinutes += Period.fieldDifference(prev, curr).toStandardMinutes().getMinutes();
                    }
                    previousRecord = record;
                }
    
                return new String[]{
                        previousRecord[0],
                        Integer.toString(diffMinutes),
                        previousRecord[3],
                        previousRecord[4]
                };
            }
        }).values();
    
        // do whatever with "result"...
    }
    
    // extracts a Joda LocalDateTime from a "record"
    static LocalDateTime getLocalDateTime(String[] record) {
        return LocalDateTime.parse(record[0] + " " + record[1], formatter);
    }
    
    static final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm");
    
    publicstaticvoidmain(字符串[]args){
    //此测试的一些设置代码:
    JavaSparkContext sc=新的JavaSparkContext(“本地”、“测试”);
    //输入:
    最终JavaRDD输入=sc.parallelize(Lists.newArrayList(
    //日期时间?对象区域
    新字符串[]{“2016-03-28”、“11:00”、“X”、“object1”、“region1”},
    新字符串[]{“2016-03-28”、“11:01”、“Y”、“object1”、“region1”},
    新字符串[]{“2016-03-28”、“11:05”、“X”、“object1”、“region1”},
    新字符串[]{“2016-03-28”、“11:09”、“X”、“object1”、“region1”},
    新字符串[]{“2016-03-28”、“11:00”、“X”、“object2”、“region1”},
    新字符串[]{“2016-03-28”、“11:01”、“Z”、“object2”、“region1”}
    ));
    //按键分组:
    final javapairdd byObjectAndDate=input.groupBy(新函数(){
    @凌驾
    公共字符串调用(字符串[]记录)引发异常{
    返回记录[0]+记录[3]+记录[4];//日期、对象、区域
    }
    });
    //将每个“值”(所有记录匹配键)映射到结果
    最终JavaRDD结果=byObjectAndDate.mapValues(新函数(){
    @凌驾
    公共字符串[]调用(Iterable记录)引发异常{
    final Iterator Iterator=records.Iterator();
    String[]previousRecord=iterator.next();
    int diffMinutes=0;
    for(字符串[]记录:记录){
    如果(记录[2].equals(“X”){//如果我没有弄错你的意图。。。
    final LocalDateTime prev=getLocalDateTime(previousRecord);
    最终LocalDateTime curr=getLocalDateTime(记录);
    diffMinutes+=Period.fieldDifference(上一个,当前).toStandardMinutes().getMinutes();
    }
    以前的记录=记录;
    }
    返回新字符串[]{
    以前的记录[0],
    整数.toString(diffMinutes),
    以前的记录[3],
    以前的记录[4]
    };
    }
    }).values();
    //用“结果”做任何事。。。
    }
    //从“记录”中提取Joda LocalDateTime
    静态LocalDateTime getLocalDateTime(字符串[]记录){
    返回LocalDateTime.parse(记录[0]+“”+记录[1],格式化程序);
    }
    静态最终DateTimeFormatter格式化程序=DateTimeFormat.forPattern(“yyyy-MM-dd-HH:MM”);
    

    另外,在Scala中,这大约需要8行/

    首先,您的代码示例从创建
    newJavaRDD
    的转换中引用
    newJavaRDD
    ——这在几个不同的级别上是不可能的:

    • 您不能引用变量声明右侧的变量
    • 您不能在RDD上的转换中使用RDD(相同的一个或另一个-这无关紧要)-转换中的任何内容都必须由Spark序列化,Spark不能序列化其自己的RDD(这毫无意义)
    那么,你应该怎么做呢

    假设

  • 这里的目的是为
    日期
    +
    对象
    +
    区域
  • 对于每个这样的组合,不应该有太多的记录,因此可以安全地将这些字段作为键
  • 您可以
    groupBy
    关键字段,然后
    mapValues
    获取