Java数据聚合案例如何实现

wen java案例 32

本文目录导读:

Java数据聚合案例如何实现

  1. 使用Stream API进行聚合
  2. 使用数据库SQL进行聚合
  3. 使用MapReduce思维进行聚合
  4. 使用并发聚合提升性能
  5. 自定义聚合器
  6. 实战建议

我来详细介绍Java中几种常见的数据聚合实现方案。

使用Stream API进行聚合

基础数据模型

public class Order {
    private Long id;
    private String category;
    private String product;
    private double amount;
    private LocalDate orderDate;
    private String status;
    // 构造函数、getter/setter省略
    public Order(Long id, String category, String product, double amount, LocalDate orderDate, String status) {
        this.id = id;
        this.category = category;
        this.product = product;
        this.amount = amount;
        this.orderDate = orderDate;
        this.status = status;
    }
    // getter方法
    public String getCategory() { return category; }
    public String getProduct() { return product; }
    public double getAmount() { return amount; }
    public LocalDate getOrderDate() { return orderDate; }
    public String getStatus() { return status; }
}

示例数据

public class DataGenerator {
    public static List<Order> generateOrders() {
        return Arrays.asList(
            new Order(1L, "电子产品", "手机", 5000.0, LocalDate.of(2024, 1, 15), "已完成"),
            new Order(2L, "电子产品", "电脑", 8000.0, LocalDate.of(2024, 1, 20), "已完成"),
            new Order(3L, "食品", "水果", 200.0, LocalDate.of(2024, 2, 5), "已完成"),
            new Order(4L, "食品", "零食", 150.0, LocalDate.of(2024, 2, 10), "已完成"),
            new Order(5L, "电子产品", "手机", 5200.0, LocalDate.of(2024, 2, 15), "已完成"),
            new Order(6L, "服装", "T恤", 200.0, LocalDate.of(2024, 3, 1), "已取消"),
            new Order(7L, "服装", "裤子", 300.0, LocalDate.of(2024, 3, 10), "已完成"),
            new Order(8L, "电子产品", "平板", 3500.0, LocalDate.of(2024, 3, 15), "已完成")
        );
    }
}

1 按类别分组统计销售总额

public class CategoryAggregationDemo {
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        // 按类别分组统计销售额
        Map<String, Double> categorySales = orders.stream()
            .filter(o -> "已完成".equals(o.getStatus()))  // 只统计已完成订单
            .collect(Collectors.groupingBy(
                Order::getCategory,
                Collectors.summingDouble(Order::getAmount)
            ));
        System.out.println("各品类销售额:");
        categorySales.forEach((category, total) -> 
            System.out.printf("%s: %.2f元\n", category, total));
    }
}

2 多维度聚合统计

public class MultiDimensionAggregationDemo {
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        // 按月份和类别统计
        Map<Object, Map<String, Double>> monthlyCategorySales = orders.stream()
            .filter(o -> "已完成".equals(o.getStatus()))
            .collect(Collectors.groupingBy(
                order -> order.getOrderDate().getMonth(),
                Collectors.groupingBy(
                    Order::getCategory,
                    Collectors.summingDouble(Order::getAmount)
                )
            ));
        System.out.println("月度品类销售统计:");
        monthlyCategorySales.forEach((month, categoryMap) -> {
            System.out.println(month + ":");
            categoryMap.forEach((category, total) -> 
                System.out.printf("  %s: %.2f元\n", category, total));
        });
    }
}

3 复杂的聚合统计

public class ComplexAggregationDemo {
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        // 聚合统计结果类
        class CategoryStats {
            long count;
            double totalAmount;
            double avgAmount;
            double maxAmount;
            double minAmount;
            @Override
            public String toString() {
                return String.format("订单数=%d, 总额=%.2f, 均价=%.2f, 最高=%.2f, 最低=%.2f",
                    count, totalAmount, avgAmount, maxAmount, minAmount);
            }
        }
        // 按类别进行综合统计
        Map<String, CategoryStats> stats = orders.stream()
            .filter(o -> "已完成".equals(o.getStatus()))
            .collect(Collectors.groupingBy(
                Order::getCategory,
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    list -> {
                        CategoryStats s = new CategoryStats();
                        s.count = list.size();
                        s.totalAmount = list.stream().mapToDouble(Order::getAmount).sum();
                        s.avgAmount = list.stream().mapToDouble(Order::getAmount).average().orElse(0);
                        s.maxAmount = list.stream().mapToDouble(Order::getAmount).max().orElse(0);
                        s.minAmount = list.stream().mapToDouble(Order::getAmount).min().orElse(0);
                        return s;
                    }
                )
            ));
        System.out.println("各品类详细统计:");
        stats.forEach((category, stat) -> 
            System.out.println(category + ": " + stat));
    }
}

使用数据库SQL进行聚合

1 实体类和Repository

@Entity
@Table(name = "orders")
public class OrderEntity {
    @Id
    private Long id;
    @Column(name = "category")
    private String category;
    @Column(name = "product")
    private String product;
    @Column(name = "amount")
    private Double amount;
    @Column(name = "order_date")
    private LocalDate orderDate;
    @Column(name = "status")
    private String status;
    // getter/setter省略
}
// JPA Repository
@Repository
public interface OrderRepository extends JpaRepository<OrderEntity, Long> {
    // 按类别统计销售额
    @Query("SELECT o.category, SUM(o.amount) FROM OrderEntity o " +
           "WHERE o.status = '已完成' GROUP BY o.category")
    List<Object[]> findCategorySales();
    // 按月统计销售额
    @Query("SELECT FUNCTION('MONTH', o.orderDate), SUM(o.amount) " +
           "FROM OrderEntity o WHERE o.status = '已完成' " +
           "GROUP BY FUNCTION('MONTH', o.orderDate)")
    List<Object[]> findMonthlySales();
    // 多维度统计
    @Query("SELECT FUNCTION('MONTH', o.orderDate), o.category, " +
           "COUNT(o), SUM(o.amount), AVG(o.amount) " +
           "FROM OrderEntity o WHERE o.status = '已完成' " +
           "GROUP BY FUNCTION('MONTH', o.orderDate), o.category")
    List<Object[]> findMonthlyCategoryStats();
}

2 聚合结果映射

// 聚合结果DTO
public class SalesStatDTO {
    private String category;
    private Double totalAmount;
    private Long orderCount;
    // 构造函数、getter/setter
    public SalesStatDTO(String category, Double totalAmount, Long orderCount) {
        this.category = category;
        this.totalAmount = totalAmount;
        this.orderCount = orderCount;
    }
}
// 服务层
@Service
public class OrderAggregationService {
    @Autowired
    private OrderRepository orderRepository;
    public List<SalesStatDTO> getCategorySales() {
        List<Object[]> results = orderRepository.findCategorySales();
        return results.stream()
            .map(row -> new SalesStatDTO(
                (String) row[0],
                (Double) row[1],
                null
            ))
            .collect(Collectors.toList());
    }
}

使用MapReduce思维进行聚合

public class MapReduceAggregationDemo {
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        // Map阶段:提取键值对
        Map<String, Double> categoryAmounts = orders.stream()
            .filter(o -> "已完成".equals(o.getStatus()))
            .collect(Collectors.toMap(
                Order::getCategory,
                Order::getAmount,
                Double::sum  // Reduce阶段:合并
            ));
        System.out.println("MapReduce方式统计结果:");
        categoryAmounts.forEach((category, total) -> 
            System.out.printf("%s: %.2f元\n", category, total));
    }
}

使用并发聚合提升性能

public class ParallelAggregationDemo {
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        // 使用并行流处理大数据集
        Map<String, Double> categorySales = orders.parallelStream()
            .filter(o -> "已完成".equals(o.getStatus()))
            .collect(Collectors.groupingByConcurrent(
                Order::getCategory,
                Collectors.summingDouble(Order::getAmount)
            ));
        System.out.println("并行聚合结果:");
        categorySales.forEach((category, total) -> 
            System.out.printf("%s: %.2f元\n", category, total));
    }
}

自定义聚合器

public class CustomAggregatorDemo {
    // 自定义聚合结果类
    static class ProductSalesStats {
        private String product;
        private int orderCount;
        private double totalAmount;
        private double maxAmount;
        private LocalDate lastOrderDate;
    }
    // 自定义Collector
    static class ProductStatsCollector 
            implements Collector<Order, Map<String, ProductSalesStats>, List<ProductSalesStats>> {
        @Override
        public Supplier<Map<String, ProductSalesStats>> supplier() {
            return HashMap::new;
        }
        @Override
        public BiConsumer<Map<String, ProductSalesStats>, Order> accumulator() {
            return (map, order) -> {
                map.computeIfAbsent(order.getProduct(), k -> new ProductSalesStats());
                ProductSalesStats stats = map.get(order.getProduct());
                stats.product = order.getProduct();
                stats.orderCount++;
                stats.totalAmount += order.getAmount();
                stats.maxAmount = Math.max(stats.maxAmount, order.getAmount());
                if (stats.lastOrderDate == null || 
                    order.getOrderDate().isAfter(stats.lastOrderDate)) {
                    stats.lastOrderDate = order.getOrderDate();
                }
            };
        }
        @Override
        public BinaryOperator<Map<String, ProductSalesStats>> combiner() {
            return (map1, map2) -> {
                map2.forEach((key, value) -> {
                    map1.merge(key, value, (v1, v2) -> {
                        v1.orderCount += v2.orderCount;
                        v1.totalAmount += v2.totalAmount;
                        v1.maxAmount = Math.max(v1.maxAmount, v2.maxAmount);
                        if (v2.lastOrderDate.isAfter(v1.lastOrderDate)) {
                            v1.lastOrderDate = v2.lastOrderDate;
                        }
                        return v1;
                    });
                });
                return map1;
            };
        }
        @Override
        public Function<Map<String, ProductSalesStats>, List<ProductSalesStats>> finisher() {
            return map -> new ArrayList<>(map.values());
        }
        @Override
        public Set<Characteristics> characteristics() {
            return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));
        }
    }
    public static void main(String[] args) {
        List<Order> orders = DataGenerator.generateOrders();
        List<ProductSalesStats> stats = orders.stream()
            .filter(o -> "已完成".equals(o.getStatus()))
            .collect(new ProductStatsCollector());
        System.out.println("产品统计结果:");
        stats.forEach(s -> System.out.printf(
            "商品=%s, 订单数=%d, 总额=%.2f, 最高价=%.2f, 最后下单=%s\n",
            s.product, s.orderCount, s.totalAmount, 
            s.maxAmount, s.lastOrderDate));
    }
}

实战建议

  1. 选择合适的聚合方式

    • 小数据集:使用Stream API
    • 大数据集:使用数据库SQL或并行流
    • 实时计算:使用MapReduce思想
  2. 性能优化

    • 使用parallelStream()处理大数据集
    • 避免在聚合过程中创建临时对象
    • 合理设置JVM内存参数
  3. 代码维护性

    • 封装聚合逻辑到独立方法
    • 使用DTO作为聚合结果
    • 编写单元测试验证聚合结果

这些示例涵盖了Java中常见的数据聚合实现方式,可以根据实际需求选择合适的方案。

抱歉,评论功能暂时关闭!