[英]What are the best practices for calculating statistics in REST API applications
我正在嘗試提供一項服務來計算每個月的統計數據。
我是這樣做的:
public Map<String, BigDecimal> getStatistic() {
List<Order> orders = orderService.findAll(Sort.by(Sort.Direction.ASC, "creationDate")).toList();
SortedMap<String, BigDecimal> statisticsMap = new TreeMap<>();
MathContext mc = new MathContext(3);
for (Order order : orders) {
List<FraudDishV1Response> dishesOfOrder = order.getDishIds()
.stream()
.map(dishId -> dishV1Client.getDishById(dishId))
.collect(Collectors.toList());
BigDecimal total = calculateTotal(dishesOfOrder);
String date = order.getCreatedDate().format(DateTimeFormatter.ofPattern("yyyy-MM"));
statisticsMap.merge(date, total, (a, b) -> a.add(b, mc));
}
return statisticsMap;
}
但是如果數據庫中有很多etries,則需要很長時間。 是否有在 REST API 應用程序中使用統計數據的最佳實踐?
而且我想知道將統計信息保存在單獨的存儲庫中是否是一種好方法? 它將節省計算統計數據的時間,但在數據庫中創建記錄期間,您還必須更新統計數據庫。
使用您的方法,您最終會在嘗試從數據庫加載大量數據時用完 memory。 您可以分批進行處理,但話又說回來,它只會讓您到目前為止。 理想情況下,任何類型的統計數據或按需報告都將由長期運行的計划作業提供服務,這些作業將定期在后台進行處理並為您生成所需的數據。 您可以將結果轉儲到一個表中,然后通過 API 從那里提供它。
另一種方法是進行實時處理。 如果您可以在您的應用程序中開發流式傳輸管道,那么我強烈建議您探索Apache Flink項目。
好吧,我沒有停下腳步,一步一步地提出了幾個解決方案……
第 1 步:使用streams
。 在此之前,計算 10,000 個 OrderEntities 記錄的統計信息需要 18 秒。 現在它已經加速到了 14 秒。
第 2 步:使用parallelStream
而不是streams
。 並行流將統計數據的計算加速到 6 秒。 我什至感到驚訝。
public SortedMap<String, BigDecimal> getStatisticsByParallelStreams() {
List<OrderEntity> orders = new ArrayList<>();
orderService.findAll(Sort.by(Sort.Direction.ASC, "createdDate")).forEach(orders::add);
MathContext mc = new MathContext(3);
return orders.stream().collect(Collectors.toMap(
order -> order.getCreatedDate().format(DateTimeFormatter.ofPattern("yyyy-MM")),
order -> calculateTotal(order.getDishIds()
.parallelStream()
.map(dishId -> dishV1Client.getDishById(dishId))
.collect(Collectors.toList())),
(a, b) -> a.add(b, mc),
TreeMap::new
));
}
第 3 步:優化對另一個微服務的請求。 我將JProfiler連接到應用程序,我發現我對另一個微服務做了額外的請求。 之后,我首先請求接收所有菜餚,然后在計算統計數據時,我使用收到的菜餚列表。 因此我將其加速到1.5 秒::
public SortedMap<String, BigDecimal> getStatisticsByParallelStreams() {
List<OrderEntity> orders = new ArrayList<>();
orderService.findAll(Sort.by(Sort.Direction.ASC, "createdDate")).forEach(orders::add);
List<FraudDishV1Response> dishes = dishV1Client.getDishes();
MathContext mc = new MathContext(3);
return orders.stream().collect(Collectors.toMap(
order -> order.getCreatedDate().format(DateTimeFormatter.ofPattern("yyyy-MM")),
order -> calculateTotal(order.getDishIds()
.parallelStream()
.map(dishId -> getDishResponseById(dishes, dishId))
.collect(Collectors.toList())),
(a, b) -> a.add(b, mc),
TreeMap::new
));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.