本文目录导读:

我将为您介绍Java中实现聚合查询的几种常见案例,包括使用Stream API、数据库查询和框架工具。
使用Java Stream API进行聚合查询
基础数据模型
// 数据模型
public class Order {
private Long id;
private String customerName;
private String product;
private Integer quantity;
private BigDecimal price;
private String category;
private LocalDate orderDate;
// getters/setters/constructors
public Order(Long id, String customerName, String product,
Integer quantity, BigDecimal price,
String category, LocalDate orderDate) {
this.id = id;
this.customerName = customerName;
this.product = product;
this.quantity = quantity;
this.price = price;
this.category = category;
this.orderDate = orderDate;
}
}
示例数据
public class AggregationExample {
private static List<Order> getSampleOrders() {
List<Order> orders = new ArrayList<>();
orders.add(new Order(1L, "张三", "笔记本电脑", 2, new BigDecimal("5999.99"), "电子产品", LocalDate.of(2024, 1, 15)));
orders.add(new Order(2L, "李四", "手机", 5, new BigDecimal("3999.99"), "电子产品", LocalDate.of(2024, 1, 20)));
orders.add(new Order(3L, "张三", "书籍", 10, new BigDecimal("29.99"), "图书", LocalDate.of(2024, 2, 5)));
orders.add(new Order(4L, "王五", "T恤", 20, new BigDecimal("89.99"), "服装", LocalDate.of(2024, 2, 10)));
orders.add(new Order(5L, "李四", "耳机", 3, new BigDecimal("299.99"), "电子产品", LocalDate.of(2024, 3, 1)));
orders.add(new Order(6L, "张三", "平板电脑", 1, new BigDecimal("3999.99"), "电子产品", LocalDate.of(2024, 3, 15)));
return orders;
}
}
各种聚合查询案例
public class StreamAggregationQueries {
public static void main(String[] args) {
List<Order> orders = getSampleOrders();
// 案例1: 按客户分组统计总消费金额
Map<String, BigDecimal> customerTotalSpending = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomerName,
Collectors.mapping(
order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
)
));
System.out.println("客户总消费金额: " + customerTotalSpending);
// 案例2: 按类别统计总销量
Map<String, Integer> categoryTotalQuantity = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.summingInt(Order::getQuantity)
));
System.out.println("类别总销量: " + categoryTotalQuantity);
// 案例3: 多级分组 - 按客户和类别统计
Map<String, Map<String, List<Order>>> customerCategoryOrders = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomerName,
Collectors.groupingBy(Order::getCategory)
));
System.out.println("客户-类别分组: " + customerCategoryOrders);
// 案例4: 统计每个客户购买的产品数量总和
Map<String, Integer> customerProductCount = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomerName,
Collectors.summingInt(Order::getQuantity)
));
System.out.println("客户购买产品总数: " + customerProductCount);
// 案例5: 计算平均每个订单的金额
Double averageOrderValue = orders.stream()
.mapToDouble(order -> order.getPrice().doubleValue() * order.getQuantity())
.average()
.orElse(0.0);
System.out.println("平均订单金额: " + averageOrderValue);
// 案例6: 找出最贵的订单
Optional<Map.Entry<String, BigDecimal>> maxOrder = orders.stream()
.collect(Collectors.toMap(
Order::getCustomerName,
order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())),
BigDecimal::add
))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
maxOrder.ifPresent(entry ->
System.out.println("消费最高的客户: " + entry.getKey() + ", 金额: " + entry.getValue()));
// 案例7: 统计每个类别的订单数
Map<String, Long> categoryOrderCount = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.counting()
));
System.out.println("类别订单数: " + categoryOrderCount);
// 案例8: 按月份统计销售额
Map<Integer, BigDecimal> monthlySales = orders.stream()
.collect(Collectors.groupingBy(
order -> order.getOrderDate().getMonthValue(),
Collectors.mapping(
order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
)
));
System.out.println("月销售额: " + monthlySales);
}
}
使用Spring Data JPA进行数据库聚合查询
Entity类
@Entity
@Table(name = "orders")
public class OrderEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "customer_name")
private String customerName;
private String product;
private Integer quantity;
private BigDecimal price;
private String category;
@Column(name = "order_date")
private LocalDate orderDate;
// getters/setters
}
Repository
@Repository
public interface OrderRepository extends JpaRepository<OrderEntity, Long> {
// 1. 按客户分组统计总消费
@Query("SELECT new com.example.dto.CustomerSummary(o.customerName, " +
"SUM(o.price * o.quantity)) " +
"FROM OrderEntity o " +
"GROUP BY o.customerName")
List<CustomerSummary> getCustomerTotalSpending();
// 2. 按类别统计总销量
@Query("SELECT o.category, SUM(o.quantity) as totalQuantity " +
"FROM OrderEntity o " +
"GROUP BY o.category")
List<Object[]> getCategoryTotalQuantity();
// 3. 统计每个类别的订单数和平均价格
@Query("SELECT o.category, COUNT(o), AVG(o.price), SUM(o.quantity) " +
"FROM OrderEntity o " +
"GROUP BY o.category")
List<Object[]> getCategoryStatistics();
// 4. 按月份统计销售额
@Query("SELECT MONTH(o.orderDate), YEAR(o.orderDate), SUM(o.price * o.quantity) " +
"FROM OrderEntity o " +
"GROUP BY YEAR(o.orderDate), MONTH(o.orderDate) " +
"ORDER BY YEAR(o.orderDate), MONTH(o.orderDate)")
List<Object[]> getMonthlySales();
// 5. 使用Criteria API进行动态聚合
List<OrderEntity> findByCustomerNameAndCategory(String customerName, String category);
}
DTO类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomerSummary {
private String customerName;
private BigDecimal totalAmount;
}
使用MyBatis进行聚合查询
Mapper接口
@Mapper
public interface OrderMapper {
// 1. 按客户分组统计
@Select("SELECT customer_name, SUM(price * quantity) as total_amount " +
"FROM orders " +
"GROUP BY customer_name")
@Results({
@Result(property = "customerName", column = "customer_name"),
@Result(property = "totalAmount", column = "total_amount")
})
List<CustomerSummary> getCustomerTotalSpending();
// 2. 复杂聚合查询
@Select("SELECT category, " +
"COUNT(*) as order_count, " +
"SUM(quantity) as total_quantity, " +
"AVG(price) as avg_price, " +
"MAX(price * quantity) as max_order_amount " +
"FROM orders " +
"WHERE order_date BETWEEN #{startDate} AND #{endDate} " +
"GROUP BY category " +
"HAVING COUNT(*) > #{minOrderCount}")
List<CategoryStats> getCategoryStats(@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate,
@Param("minOrderCount") Long minOrderCount);
// 3. XML映射查询
List<MonthlySales> getMonthlySalesByCustomer(@Param("customerName") String customerName);
}
XML映射文件
<!-- OrderMapper.xml -->
<mapper namespace="com.example.mapper.OrderMapper">
<resultMap id="MonthlySalesMap" type="com.example.dto.MonthlySales">
<result property="year" column="year"/>
<result property="month" column="month"/>
<result property="totalAmount" column="total_amount"/>
<result property="orderCount" column="order_count"/>
</resultMap>
<select id="getMonthlySalesByCustomer" resultMap="MonthlySalesMap">
SELECT
YEAR(order_date) as year,
MONTH(order_date) as month,
SUM(price * quantity) as total_amount,
COUNT(*) as order_count
FROM orders
WHERE customer_name = #{customerName}
GROUP BY YEAR(order_date), MONTH(order_date)
ORDER BY year, month
</select>
</mapper>
使用Elasticsearch进行聚合查询
@Service
public class ElasticsearchAggregationService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
public void performAggregationQueries() {
// 创建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 1. 按类别统计总销售额
TermsAggregationBuilder categoryAgg = AggregationBuilders
.terms("category_stats")
.field("category.keyword")
.subAggregation(
AggregationBuilders.sum("total_sales")
.field("price")
);
queryBuilder.addAggregation(categoryAgg);
// 2. 日期直方图聚合
DateHistogramAggregationBuilder dateAgg = AggregationBuilders
.dateHistogram("sales_over_time")
.field("orderDate")
.calendarInterval(DateHistogramInterval.MONTH)
.subAggregation(
AggregationBuilders.sum("monthly_revenue")
.field("price")
);
queryBuilder.addAggregation(dateAgg);
// 3. 复杂嵌套聚合
TermsAggregationBuilder nestedAgg = AggregationBuilders
.terms("by_customer")
.field("customerName.keyword")
.size(10)
.subAggregation(
AggregationBuilders.terms("by_category")
.field("category.keyword")
.subAggregation(
AggregationBuilders.stats("sales_stats")
.field("price")
)
);
queryBuilder.addAggregation(nestedAgg);
// 执行查询
SearchHits<OrderDocument> searchHits = elasticsearchTemplate.search(
queryBuilder.build(), OrderDocument.class);
// 处理聚合结果
Aggregations aggregations = searchHits.getAggregations();
}
}
高级聚合查询示例
public class AdvancedAggregationQueries {
// 1. 分区计算
public static Map<String, BigDecimal> calculateTopNCustomerSales(List<Order> orders, int n) {
return orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomerName,
Collectors.mapping(
order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
)
))
.entrySet()
.stream()
.sorted(Map.Entry.<String, BigDecimal>comparingByValue().reversed())
.limit(n)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
// 2. 滑动窗口聚合
public static Map<Integer, BigDecimal> calculateMovingAverage(List<Order> orders, int windowSize) {
return IntStream.range(0, orders.size())
.boxed()
.collect(Collectors.toMap(
i -> i,
i -> orders.subList(
Math.max(0, i - windowSize + 1),
i + 1
).stream()
.map(order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.divide(BigDecimal.valueOf(Math.min(windowSize, i + 1)), RoundingMode.HALF_UP)
));
}
// 3. Top-N统计
public static <T> Map<String, List<T>> getTopNPerGroup(
List<Order> orders,
Function<Order, String> classifier,
Comparator<Order> comparator,
int n) {
return orders.stream()
.collect(Collectors.groupingBy(
classifier,
Collectors.collectingAndThen(
Collectors.toList(),
list -> list.stream()
.sorted(comparator.reversed())
.limit(n)
.collect(Collectors.toList())
)
));
}
// 4. 使用并行流进行高性能聚合
public static Map<String, BigDecimal> parallelAggregation(List<Order> orders) {
return orders.parallelStream()
.collect(Collectors.groupingByConcurrent(
Order::getCategory,
Collectors.mapping(
order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())),
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
)
));
}
}
性能优化建议
public class AggregationOptimization {
// 1. 使用原始类型避免装箱拆箱
public static Map<String, Double> optimizedAggregation(List<Order> orders) {
return orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.summarizingDouble(order ->
order.getPrice().doubleValue() * order.getQuantity())
))
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().getSum()
));
}
// 2. 预聚合减少数据量
public static Map<String, BigDecimal> preAggregateAndCalculate(List<Order> orders) {
// 先按客户分组预聚合
Map<String, List<Order>> customerGroups = orders.stream()
.collect(Collectors.groupingBy(Order::getCustomerName));
// 再计算每个客户的统计信息
Map<String, BigDecimal> result = new HashMap<>();
customerGroups.forEach((customer, customerOrders) -> {
BigDecimal total = customerOrders.stream()
.map(order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
result.put(customer, total);
});
return result;
}
// 3. 使用Stream的专有操作
public static SummaryStatistics aggregateWithStatistics(List<Order> orders) {
DoubleSummaryStatistics stats = orders.stream()
.mapToDouble(order -> order.getPrice().multiply(BigDecimal.valueOf(order.getQuantity())).doubleValue())
.summaryStatistics();
return new SummaryStatistics(
stats.getCount(),
BigDecimal.valueOf(stats.getSum()),
BigDecimal.valueOf(stats.getAverage()),
BigDecimal.valueOf(stats.getMin()),
BigDecimal.valueOf(stats.getMax())
);
}
}
@Data
@AllArgsConstructor
class SummaryStatistics {
private long count;
private BigDecimal sum;
private BigDecimal average;
private BigDecimal min;
private BigDecimal max;
}
这些案例涵盖了Java中聚合查询的多种实现方式:
- Stream API - 适合内存中的小型数据集合
- JPA/MyBatis - 关系型数据库查询
- Elasticsearch - 全文搜索和聚合分析
- 并行处理 - 大数据量的性能优化
根据您的具体需求选择合适的实现方式,记得考虑数据量大小、实时性要求和系统复杂度等因素。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播