如何在Spark中使用嵌套地图RDD

时间:2017-11-15 10:39:27

标签: java scala apache-spark collections rdd

我有一个文本文件,如: -

ID,Hour,Ratio
100775,0.0,1.0
100775,1.0,1.0560344797302321
100775,2.0,1.1333317975785973
100775,3.0,1.1886133302168074
100776,4.0,1.2824427440125867

我希望像MAP{Hour,MAP{ID,Ratio}}这样的结构存储为RDD。我能找到的最接近的结构是JavaPairRDD。我尝试实现像JavaPairRDD{Hour,MAP{ID,Ratio}}这样的结构,但是,这个结构提供lookup()功能,返回LIST{MAP{ID,RATIO}},这不能解决我的用例,因为我基本上想做

ratio = MAP.get(Hour).get(ID)

有关如何最好地完成此任务的任何指示。

更新: -

在Ramesh的回答之后,我尝试了以下方法: -

JavaRDD<Map<String,Map<String,String>>> mapRDD =  data.map(line -> line.split(",")).map(array-> Collections
              .singletonMap(array[0],
                Collections
                .singletonMap
                (array[1],array[2])));

但是,这里没有像lookup()这样的功能,对吗?

3 个答案:

答案 0 :(得分:0)

这是你可以做的事情

scala> val rdd = sc.textFile("path to the csv file")
rdd: org.apache.spark.rdd.RDD[String] = path to csv file MapPartitionsRDD[7] at textFile at <console>:24

scala> val maps = rdd.map(line => line.split(",")).map(array => (array(1), Map(array(0) -> array(2)))).collectAsMap()
maps: scala.collection.Map[String,scala.collection.immutable.Map[String,String]] = Map(1.0 -> Map(100775 -> 1.0560344797302321), 4.0 -> Map(100776 -> 1.2824427440125867), 0.0 -> Map(100775 -> 1.0), 3.0 -> Map(100775 -> 1.1886133302168074), 2.0 -> Map(100775 -> 1.1333317975785973))

如果您需要RDD[Map[String, Map[String, String]]],则可以执行以下操作。

scala> val rddMaps = rdd.map(line => line.split(",")).map(array => Map(array(1) -> Map(array(0) -> array(2)))).collect
rddMaps: Array[scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]]] = Array(Map(0.0 -> Map(100775 -> 1.0)), Map(1.0 -> Map(100775 -> 1.0560344797302321)), Map(2.0 -> Map(100775 -> 1.1333317975785973)), Map(3.0 -> Map(100775 -> 1.1886133302168074)), Map(4.0 -> Map(100776 -> 1.2824427440125867)))

我希望答案很有帮助

答案 1 :(得分:0)

对于我的用例,我决定采用以下方法: -

我创建了 JavaPairRDD {Hour,MAP {ID,Ratio}} 。在任务运行的任何时候,我都会要求只对应于该小时的地图。 所以我做了以下几点: -

Map<String, Double> result = new HashMap<>();
 javaRDDPair.lookup(HOUR).stream().forEach(map ->{
            result.putAll(map.entrySet().stream().collect(Collectors.toMap(entry-> entry.getKey(), entry-> entry.getValue())));
        });

现在可以进一步将其用作广播变量。

答案 2 :(得分:-1)

使用spark中的数据集是一个常见问题。通常有一个数据集,其中包含一些样本作为其中的每一行,每列代表每个样本的一个特征。 但常见问题的一个常见解决方案是定义一个实体来支持每个列作为其属性,每个样本都是一个RDD对象。 要访问rdd中的每个对象,可以使用javapairrdd并设置例如在此示例中,HOUR作为其键,结果将类似于:

   Javapairrdd<INTEGER,Entity>