java 数据分组_Flink DataStream数据转换(2):keyBy

有一些转换(如join、coGroup、keyBy、groupBy)要求在元素集合上定义一个key。还有一些转换(如reduce、groupReduce、aggregate、windows)可以应用在按key分组的数据上。

ebb9d41cc34e3af43c48ef4e08e1d5be.png

Flink的数据模型不是基于key-value对的。因此,不需要将数据集类型物理打包为键和值。key是“虚拟的”:它们被定义为指导分组操作符的实际数据上的函数。

按元组的元素位置分组

最简单的情况是对元组的一个或多个字段进行分组。请看下面的示例代码:

package com.xueai8.ch03;

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;

/**
 * Created by www.xueai8.com
  * 
  * keyBy转换
 */
public class TransformerKeyBy {
    public static void main(String[] args) throws Exception {
        // 设置流执行环境
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 加载数据源,并执行flatMap转换
        DataStream<String> ds = env.fromElements("good good study","day day up")
                .flatMap(new FlatMapFunction<String, String>() {
                    @Override
                    public void flatMap(String value, Collector<String> out)
                            throws Exception {
                        for(String word: value.split("W+")){
                            out.collect(word);
                        }
                    }
                });

        // 通过map转换,将事件流中事件的数据类型变换为(word,1)元组形式
        DataStream<Tuple2<String,Integer>> ds_map =
                ds.map(new MapFunction<String, Tuple2<String,Integer>>() {
                    @Override
                    public Tuple2<String, Integer> map(String s) throws Exception {
                        return new Tuple2<>(s,1);
                    }
                });

        // keyBy转换,按key重分区
        KeyedStream<Tuple2<String,Integer>,Tuple> ds_keyed = ds_map.keyBy(0);

        // 输出 
        ds_keyed.print();

        // 执行
        env.execute("flink keyBy transformatiion");
    }
}

执行以上代码,输出结果如下:

(up,1)
(study,1)
(day,1)
(day,1)
(good,1)
(good,1)

按字段表达式来定义key

也可以使用字段表达式来定义key。可以使用基于字符串的字段表达式来引用嵌套的字段,并为分组、排序、连接或联合分组定义key。字段表达式使得在(嵌套的)复合类型(如Tuple和POJO类型)中选择字段变得非常容易。例如,在下面的代码中,我们按成员性别分区。

package com.xueai8.ch03;

import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * Created by www.xueai8.com
 */

public class TransformerKeyBy2 {

    // POJO类,用来表示事件流中的事件
    public static class Person {
        public String name;        	// 姓名
        public String gender;      	// 性别

        public Person() {}

        public Person(String name, String gender) {
            this.name = name;
            this.gender = gender;
        }

        @Override
        public String toString() {
            return this.name + ": 性别 " + this.gender;
        }
    }

    public static void main(String[] args) throws Exception {
        // 设置流执行环境
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 加载数据源
        DataStream<Person> personDS = env.fromElements(
                new Person("张三", "男"),
                new Person("李四", "女"),
                new Person("小多米", "男"));

        // 执行keyBy转换,按性别(gender)分区
        personDS.keyBy("gender").print();

        // 执行
        env.execute("flink keyBy transformatiion");
    }
}

执行程序,输出结果如下:

6> 李四: 性别 女
1> 张三: 性别 男
1> 小多米: 性别 男

注意到,相同的key在同一分区内被计算。另外要特别注意的是,对于要充当key的POJO类,必须满足以下条件:

  • 字段名必须声明为public的;
  • 必须有默认的无参构造器;
  • 所有构造器必须声明为public的。

使用“key selector”函数定义key

定义key的另一种方法是“key selector”函数。一个key selector函数接受单个元素作为输入,并返回该元素的key。返回的key可以是任何类型的,可以从确定性计算中得到。例如,在下面的示例中,我们根据成员的年龄,分为两组:成年人和未成年人。

package com.xueai8.ch03;

import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

/**
 * Created by www.xueai8.com
 * 
 * keyBy转换,使用 key selector
 */

public class TransformerKeyBy3 {

    // POJO类,用来表示事件流中的事件
    public static class Person {
        public String name;         	// 姓名
        public Integer age;             // 年龄

        public Person() {}

        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return this.name + ": 年龄 " + this.age;
        }
    }

    public static void main(String[] args) throws Exception {
        // 设置流执行环境
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // 加载数据源
        DataStream<Person> personDS = env.fromElements(
                new Person("张三", 16),
                new Person("李四", 18),
                new Person("王老五", 35),
                new Person("赵小六", 23),
                new Person("小多米", 12));

        // 执行keyBy转换,按年龄分区(成年人和未成年人)
        KeyedStream<Person,String> keyed = personDS.keyBy(new KeySelector<Person, String>() {
            @Override
            public String getKey(Person person) throws Exception {
                return person.age>=18 ? "adult" : "young";
            }
        });

        // 输出结果流
        keyed.print();

        // 执行
        env.execute("flink keyBy transformatiion");
    }
}

执行以下代码,输出结果如下:

6> 李四: 年龄 18
1> 张三: 年龄 16
6> 王老五: 年龄 35
1> 小多米: 年龄 12
6> 赵小六: 年龄 23
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值