ApacheSpark:JavaRDD中特定字段的记录计数
我想在对象的字段中以Java RDD为基础计算不同类型的记录。 我有一个实体类,它将ApacheSpark:JavaRDD中特定字段的记录计数,java,apache-spark,rdd,Java,Apache Spark,Rdd,我想在对象的字段中以Java RDD为基础计算不同类型的记录。 我有一个实体类,它将名称和状态作为该类的成员变量。实体类如下所示: import java.io.Serializable; import lombok.AllArgsConstructor; import lombok.Getter; @Getter @AllArgsConstructor public class Entity implements Serializable { private final Strin
名称
和状态
作为该类的成员变量。实体类如下所示:
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Entity implements Serializable {
private final String name;
private final String state;
}
我有一个实体对象的javaRDD。我想确定此RDD中每个状态存在多少对象
我目前使用的方法是使用LongAccumulator。其思想是迭代RDD中的每个记录,解析状态字段,并增加相应累加器的计数。到目前为止,我尝试的代码是:
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.util.LongAccumulator;
import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CountRDD {
public static void main(String[] args) {
String applicationName = CountRDD.class.getName();
SparkConf sparkConf = new SparkConf().setAppName(applicationName).setMaster("local");
JavaSparkContext javaSparkContext = new JavaSparkContext(sparkConf);
javaSparkContext.setLogLevel("INFO");
Entity entity1 = new Entity("a1", "s1");
Entity entity2 = new Entity("a2", "s2");
Entity entity3 = new Entity("a3", "s1");
Entity entity4 = new Entity("a4", "s2");
Entity entity5 = new Entity("a5", "s1");
List<Entity> entityList = new ArrayList<Entity>();
entityList.add(entity1);
entityList.add(entity2);
entityList.add(entity3);
entityList.add(entity4);
entityList.add(entity5);
JavaRDD<Entity> entityJavaRDD = javaSparkContext.parallelize(entityList, 1);
LongAccumulator s1Accumulator = javaSparkContext.sc().longAccumulator("s1");
LongAccumulator s2Accumulator = javaSparkContext.sc().longAccumulator("s2");
entityJavaRDD.foreach(entity -> {
if (entity != null) {
String state = entity.getState();
if ("s1".equalsIgnoreCase(state)) {
s1Accumulator.add(1);
} else if ("s2".equalsIgnoreCase(state)) {
s2Accumulator.add(1);
}
}
});
log.info("Final values for input entity RDD are following");
log.info("s1Accumulator = {} ", s1Accumulator.value());
log.info("s2Accumulator = {} ", s2Accumulator.value());
}
}
import org.apache.spark.SparkConf;
导入org.apache.spark.api.java.JavaRDD;
导入org.apache.spark.api.java.JavaSparkContext;
导入org.apache.spark.util.org;
导入java.util.ArrayList;
导入java.util.List;
导入lombok.extern.slf4j.slf4j;
@Slf4j
公共类CountRDD{
公共静态void main(字符串[]args){
字符串applicationName=CountRDD.class.getName();
SparkConf SparkConf=new SparkConf().setAppName(applicationName).setMaster(“本地”);
JavaSparkContext JavaSparkContext=新的JavaSparkContext(sparkConf);
setLogLevel(“INFO”);
实体实体1=新实体(“a1”、“s1”);
实体实体2=新实体(“a2”、“s2”);
实体实体3=新实体(“a3”、“s1”);
实体实体4=新实体(“a4”、“s2”);
实体实体5=新实体(“a5”、“s1”);
List entityList=新建ArrayList();
entityList.add(entity1);
entityList.add(entity2);
entityList.add(entity3);
entityList.add(entity4);
entityList.add(entity5);
JavaRDD entityJavaRDD=javaSparkContext.parallelize(entityList,1);
LongAccumulator s1Accumulator=javaSparkContext.sc().LongAccumulator(“s1”);
LongAccumulator s2Accumulator=javaSparkContext.sc().LongAccumulator(“s2”);
entityJavaRDD.foreach(实体->{
如果(实体!=null){
字符串状态=entity.getState();
如果(“s1”。相等信号情况(状态)){
s1.添加(1);
}else if(“s2”。相等信号情况(状态)){
22.添加(1);
}
}
});
log.info(“输入实体RDD的最终值如下”);
log.info(“s1acculator={}”,s1acculator.value());
log.info(“s2Accumulator={}”,s2Accumulator.value());
}
}
上述代码工作并产生此输出s1acculator=3
和s2acculator=2
上述代码的限制是:我们应该在执行前知道状态的所有允许值,并维护相应的累加器。这只会使代码对于更大的状态值来说太大
我可以想到的另一种方法是创建一对新的字符串(state)和整数(count)RDD。对输入RDD应用mapToPair
转换,并从新创建的RDD中获取计数
关于如何处理这个问题的任何其他想法 如注释中所述,您可以在状态字段上调用
groupBy
,然后在其上调用count
,这将为您提供每个状态的计数。你不需要累加器
作为补充说明,如果您避免使用lambda函数并使用数据帧(即DataSet
),则作业的运行性能会显著提高。数据帧提供了比RDD更好的查询优化和代码生成功能,并且对于大多数处理用例具有向量化(意思是:非常快)功能
DataSet API javadoc在描述中有一个DataFrame groupBy示例:
首先最好将数据读取为数据帧,但您可以使用
SparkSession.createDateFrame
转换RDD和JavaRDD。如注释中所述,您可以在state字段上调用groupBy
,然后在其上调用count
,这将为您提供每个状态的计数。你不需要累加器
作为补充说明,如果您避免使用lambda函数并使用数据帧(即DataSet
),则作业的运行性能会显著提高。数据帧提供了比RDD更好的查询优化和代码生成功能,并且对于大多数处理用例具有向量化(意思是:非常快)功能
DataSet API javadoc在描述中有一个DataFrame groupBy示例:
首先最好将数据读取为数据帧,但是可以使用
SparkSession.createDateFrame
转换RDD和JavaRDD。您应该使用groupBy方法。请参见此处的示例:您应该使用groupBy方法。请参见此处的示例: