实时订单总额计算,及实时 top3
package com.daidai.caseanalysis;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.java.tuple.Tuple;
import org.apache.flink.api.java.tuple.Tuple1;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
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.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.triggers.ContinuousProcessingTimeTrigger;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
public class RealtimeMoneyCountAndCategoryTop {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
DataStreamSource<Tuple2<String, Double>> sourceDS = env.addSource(new MySource());
SingleOutputStreamOperator<CategoryPojo> tempAggResult = sourceDS
.keyBy(0)
.window(TumblingProcessingTimeWindows.of(Time.days(1), Time.hours(-8)))
.trigger(ContinuousProcessingTimeTrigger.of(Time.seconds(1)))
.aggregate(new PriceAggregate(), new WindowResult());
tempAggResult.print("初步聚合结果:");
tempAggResult
.keyBy("dateTime")
.window(TumblingProcessingTimeWindows.of(Time.seconds(1)))
.process(new WindowResultProcess());
env.execute();
}
public static class MySource implements SourceFunction<Tuple2<String, Double>> {
private boolean flag = true;
private String[] categorys = {"女装", "男装", "图书", "家电", "洗护", "美妆", "运动", "游戏", "户外", "家具", "乐器", "办公"};
private Random random = new Random();
@Override
public void run(SourceContext<Tuple2<String, Double>> ctx) throws Exception {
while (flag) {
int index = random.nextInt(categorys.length);
String category = categorys[index];
double price = random.nextDouble() * 100;
ctx.collect(Tuple2.of(category, price));
Thread.sleep(20);
}
}
@Override
public void cancel() {
flag = false;
}
}
private static class PriceAggregate implements AggregateFunction<Tuple2<String, Double>, Double, Double> {
@Override
public Double createAccumulator() {
return 0D;
}
@Override
public Double add(Tuple2<String, Double> value, Double accumulator) {
return value.f1 + accumulator;
}
@Override
public Double getResult(Double accumulator) {
return accumulator;
}
@Override
public Double merge(Double a, Double b) {
return a + b;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class CategoryPojo {
private String category;
private double totalPrice;
private String dateTime;
}
private static class WindowResult implements WindowFunction<Double, CategoryPojo, Tuple, TimeWindow> {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void apply(Tuple tuple, TimeWindow window, Iterable<Double> input, Collector<CategoryPojo> out) throws Exception {
String category = ((Tuple1<String>) tuple).f0;
Double price = input.iterator().next();
BigDecimal bigDecimal = new BigDecimal(price);
double roundPrice = bigDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
long currentTimeMillis = System.currentTimeMillis();
String dateTime = df.format(currentTimeMillis);
CategoryPojo categoryPojo = new CategoryPojo(category, roundPrice, dateTime);
out.collect(categoryPojo);
}
}
private static class WindowResultProcess extends ProcessWindowFunction<CategoryPojo, Object, Tuple, TimeWindow> {
@Override
public void process(Tuple tuple, Context context, Iterable<CategoryPojo> elements, Collector<Object> out) throws Exception {
String dateTime = ((Tuple1<String>) tuple).f0;
Queue<CategoryPojo> queue = new PriorityQueue<>(3,
(c1, c2) -> c1.getTotalPrice() >= c2.getTotalPrice() ? 1 : -1);
double totalPrice = 0D;
double roundPrice = 0D;
Iterator<CategoryPojo> iterator = elements.iterator();
for (CategoryPojo element : elements) {
double price = element.totalPrice;
totalPrice += price;
BigDecimal bigDecimal = new BigDecimal(totalPrice);
roundPrice = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
if (queue.size() < 3) {
queue.add(element);
} else {
CategoryPojo top = queue.peek();
if (element.totalPrice > top.totalPrice) {
queue.poll();
queue.add(element);
}
}
}
List<String> top3Result = queue.stream()
.sorted((c1, c2) -> c1.getTotalPrice() > c2.getTotalPrice() ? -1 : 1)
.map(c -> "(分类:" + c.getCategory() + " 销售总额:" + c.getTotalPrice() + ")")
.collect(Collectors.toList());
System.out.println("时间 : " + dateTime + " 总价 : " + roundPrice + "\ntop3:\n" + StringUtils.join(top3Result, ",\n"));
System.out.println("-------------");
}
}
}