在spark中过滤KeyValueGrouped数据集

时间:2018-10-01 12:53:20

标签: java apache-spark apache-spark-sql apache-spark-2.0

我有一个自定义类的类型化数据集,并在其上使用groupbykey方法。您知道它会产生一个KeyValueGroupedDataset。我想过滤这个新的数据集,但是这种类型的数据集没有过滤方法。因此,我的问题是:如何过滤这种类型的数据集? (需要Java解决方案。spark版本:2.3.1)。

sampleData:

"id":1,"fname":"Gale","lname":"Willmett","email":"gwillmett0@nhs.uk","gender":"Female"
"id":2,"fname":"Chantalle","lname":"Wilcher","email":"cwilcher1@blinklist.com","gender":"Female"
"id":3,"fname":"Polly","lname":"Grandisson","email":"pgrandisson2@linkedin.com","gender":"Female"
"id":3,"fname":"Moshe","lname":"Pink","email":"mpink3@twitter.com","gender":"Male"
"id":2,"fname":"Yorke","lname":"Ginnelly","email":"yginnelly4@apple.com","gender":"Male"

我做了什么

    Dataset<Person> peopleDS = spark.read().format("parquet").load("\path").as(Encoders.bean(Person.class));
    KeyValueGroupedDataset<String, Person> KVDS = peopleDS.groupByKey( (MapFunction<Person, String> ) f -> f.getGender() , Encoders.STRING());
//How Can I filter on KVDS's id field? 

Update1 (使用flatMapGroups):

Dataset<Person> persons = KVDS.flatMapGroups((FlatMapGroupsFunction <String,Person,Person>) (f,k) -> (Iterator<Person>) k ,  Encoders.bean(Person.class));

Update2 (使用地图组)

Dataset<Person> peopleMap = KVDS.mapGroups((MapGroupsFunction <String,Person,Person>) (f,g) -> {
        while (g.hasNext()) {
        //What can I do here?       
    }
},Encoders.bean(Person.Class); 

Update3 :我要过滤其ID差异大于1的那些组。例如,在下图中:我只希望女性组,因为其ID差异大于1(第一个栏位是ID,其他栏位则是[姓氏,名字,电子邮件和性别]。 enter image description here

Update4:我用“ RDD”做了我想做的事,但是我想用“ Dataset”来做这部分代码:

List<Tuple2<String, Iterable<Person>>> f = PersonRDD
        .mapToPair(s -> new Tuple2<>(s.getGender(), s)).groupByKey()
        .filter(t -> ((Collection<Person>) t._2()).stream().mapToInt(e -> e.getId).distinct().count() > 1)
        .collect();

2 个答案:

答案 0 :(得分:0)

分组用于聚合函数,您可以在“ KeyValueGroupedDataset”类中找到类似“ agg”的函数。如果您对ex应用汇总功能。 “计数”,您将获得“数据集”,并且“过滤器”功能将可用。

没有聚集功能的“ groupBy”看起来很奇怪,例如其他功能。可以使用“ distinct”。

使用“ FlatMapGroupsFunction”进行过滤的示例:

                .flatMapGroups(
                    (FlatMapGroupsFunction<String, Person, Person>) (f, k) -> {
                        List<Person> result = new ArrayList<>();
                        while (k.hasNext()) {
                            Person value = k.next();
                            // filter condition here
                            if (value != null) {
                                result.add(value);
                            }
                        }
                        return result.iterator();
                    },
                    Encoders.bean(Person.class))

答案 1 :(得分:0)

为什么在分组之前不对ID进行过滤? GroupByKey是一项昂贵的操作,应该先进行过滤才能更快。

如果您真的要先分组,则可能必须使用具有身份功能的.flatMapGroups。

不确定Java代码,但scala版本如下:

peopleDS
.groupByKey(_.gender)
.mapGroups { case (gender, persons) => persons.filter(your condition) }

但是同样,您应该先过滤:)。特别是因为您的ID字段在分组前已经可用。