APP市场推广渠道统计分析

水善利万物而不争,处众人之所恶,故几于道

文章目录

      • 前言:
      • 1. 数据源准备:
          • 市场用户行为实体类
          • 自定义数据源:直接用内部类
      • 2. 核心代码
      • 3. 完整程序
      • 4. 复盘总结


前言:

我们要对如下数据进行统计分析,其中每列分别代表的含义是用户id(userId)、行为(behavior)、来源渠道(channel)、时间戳(timestamp)
APP市场推广渠道统计分析_第1张图片

  本案例主要是模拟各大App应用市场的下载、安装、更新、卸载的行为统计分析。我们对每个渠道下的各种行为进行统计,比如vivo应用市场的下载是15,oppo应用市场的更新是23 …

1. 数据源准备:

  本案例中没有文本文件,而是用自定义数据源实现的(为了复习自定义数据源),我们将上面的数据封装成一个市场用户行为实体,来进行处理。这个实体的属性包括:用户id(userId)、行为(behavior)、来源渠道(channel)、时间戳(timestamp)属性。

市场用户行为实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MarketingUserBehavior {
    private Long userId;
    private String behavior;
    private String channel;
    private Long timestamp;
}
自定义数据源:直接用内部类

  直接使用random随机生成一些用户行为数据,然后封装到一个对象中,最后收集起来就行了。注意来个睡眠,要不然顶不住。

public static class AppSource implements SourceFunction<MarketingUserBehavior> {
    // 在这里把source读到的数据放入到流中
    @Override
    public void run(SourceContext<MarketingUserBehavior> ctx) throws Exception {

        Random random = new Random();
        String [] behaviors = {"download","install","update","uninstall"};
        String [] channels = {"Appstore","huawei","vivo","oppo","xiaomi"};

        while (true){
            Long userId = (long)(random.nextInt(2000) + 1);
            String behavior = behaviors[random.nextInt(behaviors.length)];
            String channel = channels[random.nextInt(channels.length)];
            Long timestame = System.currentTimeMillis();

            ctx.collect(
                    new MarketingUserBehavior(
                            userId,
                            behavior,
                            channel,
                            timestame
                    ));
            // 1秒生成5条数据
            Thread.sleep(200);
        }
    }
    // 取消source读取数据
    // 这个方法不会自动执行, 可以在外面条用这个方法
    @Override
    public void cancel() {

    }
}

2. 核心代码

  因为数据源我们返回的是市场用户行为对象,所以我们第一步将这个对象映射为元组类型,并标记,便于后期统计,然后通过keyBy分组,分组的key直接用元组的第一个元素,也就是来源和行为作为分组依据,然后进行sum求和,求出各种渠道下不同行为的的统计值。

// 统计不同的渠道不同的行为的个数
env
        // 从自定义数据源读取数据
        .addSource(new AppSource())
        // 将市场用户行为映射为元组 (oppo_install,1)
        .map(new MapFunction<MarketingUserBehavior, Tuple2<String,Long>>() {
            @Override
            public Tuple2<String, Long> map(MarketingUserBehavior value) throws Exception {
                return Tuple2.of(value.getChannel()+"_"+value.getBehavior(),1L);
            }
        })
        // 以渠道和行为进行分组
        .keyBy(new KeySelector<Tuple2<String, Long>, String>() {
            @Override
            public String getKey(Tuple2<String, Long> value) throws Exception {
                return value.f0;
            }
        })
        // 求和
        .sum(1)
        .print();

try {
    env.execute();
} catch (Exception e) {
    e.printStackTrace();
}

3. 完整程序

public class Flink04_Project_App {
    public static void main(String[] args) {
        Configuration conf = new Configuration();
        conf.setInteger("rest.port",1000);
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(conf);
        env.setParallelism(2);

        // 统计不同的渠道不同的行为的个数
        env
                // 从自定义数据源读取数据
                .addSource(new AppSource())
                // 将市场用户行为映射为元组 (oppo_install,1)
                .map(new MapFunction<MarketingUserBehavior, Tuple2<String,Long>>() {
                    @Override
                    public Tuple2<String, Long> map(MarketingUserBehavior value) throws Exception {
                        return Tuple2.of(value.getChannel()+"_"+value.getBehavior(),1L);
                    }
                })
                // 以渠道和行为进行分组
                .keyBy(new KeySelector<Tuple2<String, Long>, String>() {
                    @Override
                    public String getKey(Tuple2<String, Long> value) throws Exception {
                        return value.f0;
                    }
                })
                // 求和
                .sum(1)
                .print();

        try {
            env.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class AppSource implements SourceFunction<MarketingUserBehavior> {

        @Override
        public void run(SourceContext<MarketingUserBehavior> ctx) throws Exception {

            Random random = new Random();
            String [] behaviors = {"download","install","update","uninstall"};
            String [] channels = {"Appstore","huawei","vivo","oppo","xiaomi"};


            while (true){

                Long userId = (long)(random.nextInt(2000) + 1);
                String behavior = behaviors[random.nextInt(behaviors.length)];
                String channel = channels[random.nextInt(channels.length)];
                Long timestame = System.currentTimeMillis();

                ctx.collect(
                        new MarketingUserBehavior(
                                userId,
                                behavior,
                                channel,
                                timestame
                        ));
                Thread.sleep(200);
            }
        }

        @Override
        public void cancel() {

        }
    }
}

4. 复盘总结

  自定义数据源要实现SourceFunction接口,然后实现接口中的两个抽象方法runcancel,其中run方法是把source读到的数据放入到流中,他一般会有一个while循环去不断的读数据,而cancel方法是终止读数据的方法,他不会主动调用,可以在外面调用这个方法。

  然后处理的逻辑比较简单,首先addSource(new AppSource())就可以读到数据,读到数据后,因为我们的数据流中的数据是一个个的对象,所以我们直接来个map映射,将对象映射为元组并打上计数标记,然后用keyBy分组进行sum求和就可以了

你可能感兴趣的:(Flink,Flink编程基础练习,APP市场推广渠道统计分析,自定义数据源,Flink基础算子编程,流处理)