flink案例之统计每隔一段时间内url的访问量

需求:每隔10s统计每个url的访问量。

需求分析

1.每隔10s 那么需要开窗

2.每个url 需要key by

3.统计访问量 需要reduceFunction 或者aggregateFunction还是process

注意 我们要的结果肯定是url1->10  url2->15

reduce的话要变成tuple 其余的aggere和process都可以。

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Random;


public class UrlViewCountExample {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        SingleOutputStreamOperator<Event> stream = env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forMonotonousTimestamps()
                        .withTimestampAssigner(new SerializableTimestampAssigner<Event>() {
                            @Override
                            public long extractTimestamp(Event element, long recordTimestamp) {
                                return element.timestamp;
                            }
                        }));
        stream.map(event-> Tuple2.of(event.url,1)).returns(Types.TUPLE(Types.STRING, Types.INT))
                .keyBy(data -> data.f0)
                .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                .reduce(new ReduceFunction<Tuple2<String, Integer>>() {
                    @Override
                    public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) throws Exception {
                        return Tuple2.of(value1.f0,value1.f1+1);
                    }
                }).print("reduce");
        // 需要按照url分组,开滑动窗口统计
        stream.keyBy(data -> data.url)
                .window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
                // 同时传入增量聚合函数和全窗口函数
                .aggregate(new UrlViewCountAgg(), new UrlViewCountResult())
                .print();

        env.execute();
    }

    // 自定义增量聚合函数,来一条数据就加一
    public static class UrlViewCountAgg implements AggregateFunction<Event, Long, Long> {
        @Override
        public Long createAccumulator() {
            return 0L;
        }

        @Override
        public Long add(Event value, Long accumulator) {
            return accumulator + 1;
        }

        @Override
        public Long getResult(Long accumulator) {
            return accumulator;
        }

        @Override
        public Long merge(Long a, Long b) {
            return null;
        }
    }

    // 自定义窗口处理函数,只需要包装窗口信息
    public static class UrlViewCountResult extends ProcessWindowFunction<Long, UrlViewCount, String, TimeWindow> {

        @Override
        public void process(String url, Context context, Iterable<Long> elements, Collector<UrlViewCount> out) throws Exception {
            // 结合窗口信息,包装输出内容
            Long start = context.window().getStart();
            Long end = context.window().getEnd();
            // 迭代器中只有一个元素,就是增量聚合函数的计算结果
            out.collect(new UrlViewCount(url, elements.iterator().next(), start, end));
        }
    }
    static class ClickSource implements SourceFunction<Event> {
        // 声明一个布尔变量,作为控制数据生成的标识位
        private Boolean running = true;
        @Override
        public void run(SourceContext<Event> ctx) throws Exception {
            Random random = new Random();    // 在指定的数据集中随机选取数据
            String[] users = {"Mary", "Alice", "Bob", "Cary"};
            String[] urls = {"./home", "./cart", "./fav", "./prod?id=1", "./prod?id=2"};

            while (running) {
                ctx.collect(new Event(
                        users[random.nextInt(users.length)],
                        urls[random.nextInt(urls.length)],
                        Calendar.getInstance().getTimeInMillis()
                ));
                //这里也可以发送水位线
                //           ctx.collectWithTimestamp();
//            ctx.emitWatermark(new Watermark(1));
                // 隔1秒生成一个点击事件,方便观测
                Thread.sleep(1000);
            }
        }
        @Override
        public void cancel() {
            running = false;
        }

    }
   static class Event {
       public String user;
       public String url;
       public Long timestamp;

       public Event() {
       }

       public Event(String user, String url, Long timestamp) {
           this.user = user;
           this.url = url;
           this.timestamp = timestamp;
       }

       @Override
       public String toString() {
           return "Event{" +
                   "user='" + user + '\'' +
                   ", url='" + url + '\'' +
                   ", timestamp=" + new Timestamp(timestamp) +
                   '}';
       }
   }
   static public class UrlViewCount {
        public String url;
        public Long count;
        public Long windowStart;
        public Long windowEnd;

        public UrlViewCount() {
        }

        public UrlViewCount(String url, Long count, Long windowStart, Long windowEnd) {
            this.url = url;
            this.count = count;
            this.windowStart = windowStart;
            this.windowEnd = windowEnd;
        }

        @Override
        public String toString() {
            return "UrlViewCount{" +
                    "url='" + url + '\'' +
                    ", count=" + count +
                    ", windowStart=" + new Timestamp(windowStart) +
                    ", windowEnd=" + new Timestamp(windowEnd) +
                    '}';
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了在Flink中处理一段时间的数据,可以使用时间窗口。时间窗口是将数据流分成固定大小的时间段,并在每个时间段内对数据进行聚合操作的一种机制。Flink支持两种类型的时间窗口:滚动窗口和滑动窗口。 滚动窗口是将数据流分成固定大小的、不重叠的时间段,并在每个时间段内对数据进行聚合操作。例如,如果我们将数据流分成大小为5的滚动窗口,则第一个窗口将包含第0到第5的数据,第二个窗口将包含第5到第10的数据,以此类推。可以使用以下代码在Flink中定义一个滚动窗口: ```python from pyspark.streaming import StreamingContext ssc = StreamingContext(sparkContext, 5) # 创建一个5的滚动窗口 ``` 滑动窗口是将数据流分成固定大小的、可能重叠的时间段,并在每个时间段内对数据进行聚合操作。例如,如果我们将数据流分成大小为5、滑动步长为2的滑动窗口,则第一个窗口将包含第0到第5的数据,第二个窗口将包含第2到第7的数据,第三个窗口将包含第4到第9的数据,以此类推。可以使用以下代码在Flink中定义一个滑动窗口: ```python from pyspark.streaming import StreamingContext ssc = StreamingContext(sparkContext, 5) # 创建一个5的滑动窗口 windowedStream = ssc.window(windowDuration=15, slideDuration=5) # 创建一个大小为15、滑动步长为5的滑动窗口 ``` 在定义了时间窗口后,可以使用Flink提供的各种聚合函数对窗口内的数据进行处理,例如sum、count、max等。可以使用以下代码对窗口内的数据进行求和操作: ```python windowedStream.sum().pprint() ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值