我正在使用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没有任何价值。
答案 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中,代码有点冗长,但结构和想法是一样的。