JavaSpark-编程进阶-数值RDD管道基于分区操作

来源:互联网 发布:战舰世界 战列舰 知乎 编辑:程序博客网 时间:2024/05/22 17:49

数值RDD的操作
Spark对包含数值数据的RDD提供了一些描述性的统计操作
Spark的数值操作是通过流式算法实现的,允许每次一个元素的方式构建模型。这些统计数据都会在调用stats()时通过一次遍历数据计算出来,并以StatsCounter对象返回
count()
mean():平均数
sum()
max()
min()
variance():方差
sampleVariance():采样中计算方差
stdev():标准差
sampleStdev():采样的标准差

//从数据中,移除异常数据        SparkConf conf = new SparkConf().setMaster("local").setAppName("test");        JavaSparkContext sc = new JavaSparkContext(conf);        List<String> data = new ArrayList<String>();        data.add("122.1");        data.add("123.1");        data.add("125.2");        data.add("121.1");        data.add("22.1");        JavaRDD<String> t = sc.parallelize(data);        JavaDoubleRDD testr1 = t.mapToDouble(x -> Double.parseDouble(x));        StatCounter stats = testr1.stats();        Double stddev = stats.stdev();        Double mean = stats.mean();        JavaDoubleRDD result1 = testr1.filter(x -> Math.abs(x-mean)> stddev);           System.out.println(StringUtils.join(result1.collect(),","));        sc.close();

基于分区进行操作
基于分区对数据进行操作可以让我们避免为每一个数据进行重复的配置工作(如,打开数据库连接或创建随机数生成器)
Spark提供基于分区的map和foreach,让部分代码只对RDD的每个分区运行一次,可降低这些操作的代价(相对一个分区运行多次)

通过使用基于分区的操作,可以在每一个分区内共享一个数据库连接池,避免太多连接,同时重用JSON解析器。
使用mapPartitions函数获得输入RDD的分区中的元素迭代器,而返回得失执行结果的序列的迭代器。

......

mapPartitions() 分区元素的迭代器 返回迭代器 RDD
mapPartitionsWithIndex() 分区序号和分区元素的迭代器 返回迭代器
foreachPartitions() 元素迭代器 无

  RDD<integer,Iterator[]> test=x.mapPartitionsWithIndex()

除了避免重复的配置工作,还可以使用mapPartitions避免创建对象开销。有时需要创建一个对象来将不同类型的数据聚合起来
在计算平均值时,一种方法是将数值RDD转为二元组RDD,以在归约过程中追踪所处理的元素个数。现在,可以为每个分区只创建一次二元组,而不用为每一个元素都执行这个操作

public class mean {    public static void main(String[] args) {        // TODO 自动生成的方法存根        SparkConf conf = new SparkConf().setMaster("local").setAppName("test");        JavaSparkContext sc = new JavaSparkContext(conf);           List<Double> list = new ArrayList<Double>();        list.add(14.5);        list.add(12.5);        list.add(3.5);        list.add(15.5);        JavaRDD<Double> test = sc.parallelize(list,2);        //mapPartitions会为每一个分区的所有元素使用同一个解析器        //解析器是RDD中元素的操作模式        //reduce将每一个分区的结果再进行归约        avg j = test.mapPartitions(new avg(0.0,0)).reduce((avg x,avg y)->{            x.num1+=y.num1;            x.num2+=y.num2;            return x;        });                  System.out.println(j.num1+"   "+j.num2);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          sc.close();     }}//mappartitions需要的解析器实现mappartitions要求的接口就行class avg implements FlatMapFunction<Iterator<Double>,avg>{    Double num1;    int num2;    public avg(Double num1,int num2){        this.num1=num1;        this.num2=num2;    }    @Override    public Iterator<avg> call(Iterator<Double> arg0) throws Exception {        // TODO 自动生成的方法存根        avg t = new avg(0.0,0);        arg0.forEachRemaining(x->{            t.num1+=x;            t.num2+=1;        });        return Arrays.asList(t).iterator();    }}

与外部程序间的管道
总的来说就是使用别的语言编写逻辑运用于Spark程序中

Spark的pipe()方法可以让我们使用任意一种语言实现Spark作业中的部分逻辑,只要它能读写Unix标准流就行。通过pipe(),可以将RDD中的各元素从标准输入流中以字符串形式读出,并对这些元素执行任何你需要的操作,然后把结果以字符串的形式写入标准输出。

以后使用时补充

原创粉丝点击