Spark懒惰的转型执行障碍

时间:2014-12-02 17:53:14

标签: apache-spark lazy-evaluation apache-spark-sql

我正在使用SparkSQL。我使用JavaPairRDD从HBase获取数据然后做了一个地图。在地图中,我将所有键保存到一个Set中。为了强制执行此映射,请遵循collect()。 在此之后,我使用Set中的值来执行其他操作。

此程序可以在我的本地PC上完美运行。但当我把它放到集群(2名工人)时,就会出现执行障碍。在地图转换之前,执行Set操作。

代码流如下: 从Hbase获取数据:

JavaPairRDD<ImmutableBytesWritable, Result> hBaseRDD =     jsc.newAPIHadoopRDD(hbase_conf,
                TableInputFormat.class, ImmutableBytesWritable.class,
                Result.class);

转换数据:

JavaRDD<Map<String, String>> data = hBaseRDD.map(
                new Function<Tuple2<ImmutableBytesWritable, Result>, Map<String, String>>(){
                    public Map<String, String> call(
                            Tuple2<ImmutableBytesWritable, Result> re)
                            throws Exception {
                        byte[] payload =re._2().getValue(Bytes.toBytes("ContentInfo"), Bytes.toBytes("Payload"));
                        Map<String, String> map = new ConcurrentHashMap<String, String>();

                        String primaryKey = new String(re._1().get());
                        map.put("primaryKey", primaryKey);

                        if(payload != null)
                            map.put("payload", new String(payload));

                        Map<byte[], byte[]> tmpMetaMap = re._2().getFamilyMap(Bytes.toBytes("MetaInfo"));
                        if(tmpMetaMap != null){
                            for(Entry<byte[], byte[]> entry : tmpMetaMap.entrySet()){

                                String tmpKey = Bytes.toString(entry.getKey());
                                String tmpValue = Bytes.toString(entry.getValue());

                                map.put(tmpKey, tmpValue);
    //save result to the set
                                keySet.add(tmpKey);
                            }
                        }
                        return map;
                    }
                });

强制上面的地图运行:

data.collect();

获取Set的结果:

StringBuilder sb = new StringBuilder();

        for(String fieldName: keySet){

            sb.append(fieldName).append(",");
        }

当我在本地运行代码时,我可以获得所有结果。但是当我在集群上运行它时,sb没有任何价值。

2 个答案:

答案 0 :(得分:0)

您如何定义键集?尝试将其定义为静态或以其他方式使用foreach而不是map,这将把所有数据带到DriverSide.Hope这回答你的问题

答案 1 :(得分:0)

此问题与操作顺序无关,而是集群中的 where 正在进行此类操作。

在Spark中,有两种类型的操作:转换和操作。

通过将一些函数应用于内容,将转换和RDD转换为另一个RDD。这是一种纯粹的功能性方法,并且没有副作用。 动作采用RDD并生成其他内容,如文件或本地数据结构:这些操作将RDD的数据实现为其他形式。

在这种情况下,转换函数:map正在使用副作用,因为keyset预计会在地图转换期间发生变异。 鉴于keyset被定义在转换函数的范围之外,它将被序列化并发送给执行者,但是远程发生的任何突变将不会在驱动程序中恢复。

如果我们考虑一下,每个执行者都会在数据分区上应用转换,所以无论内容“keyset”以什么结尾,都只是每个分区的部分视图。

对此进行建模的正确方法是根据RDD转换和操作重新定义操作。

从上面的代码看,我们想要将一些输入转换为RDD[Map[String,String]],我们有兴趣在驱动程序上收集所有非“主键”和“有效负载”条目的键集“从那个结果。

在Spark中,这可能是:

// data = RDD[Map[String, String]]
// first we get all the keys from all the maps
val keys = data.map{entry => entry.keys}
// now we collect that information on the driver
val allKeys = keys.collect
// we transform the resulting array into a set - this will remove duplicates by definition
val allKeySet = allKeys.toSet
// We need still to remove "primaryKey" and "payload"
val keySet = fullKeySet.diff(Set("primaryKey","payload"))

在Java中,代码有点冗长,但结构和想法是一样的。