我正在进行酒店预订项目。一项新功能要求客户可以对酒店发表评论。每个评论都有一个评分(0 - > 5)。在搜索酒店页面上,每家酒店都会显示其平均评分。如何处理CQRS中的汇总/报告?
注释添加是很容易的,和CommentAddedEvent可以发布:
class CommentAddedEvent {
private String hotelId;
private double rating;
//other attributes omitted
}
在查询方面,注释行坚持对本次活动:
create table t_comment {
hotel_id number,
rating number(2,1)
}
但是我们放慢如何显示酒店的平均评级。以下是我们潜在的解决方案:
一)数据库集成
在搜索酒店查询端,使用SQL函数来获得平均:
select h.id, h.name,....,select avg(c.rating) from t_commentc , t_hotel
where.... group by c.hotel_id.....
这看起来很容易,但我们认为它会在测试中引入更多的努力,并可能导致一些性能问题。
B)事件处理计算平均
添加事件处理订阅CommentAddedEvent并计算平均值:
public void on(CommentAddedEvent event) {
Hotel hotel = ....
double total = hotel.rating * hotel.comments;
double average = (total + event.rating)/(hotel.comments + 1)
//update hotel
}
测试是容易的,但这种解决方案似乎并没有被幂等。当事件失败时,事件处理程序可以处理重复事件。
C)计划任务
添加计划任务,总结每家酒店的评论。但是这是低效率的,因为一些酒店自上次任务以来没有评论。
d)计划任务与事件处理混合
使用的事件处理程序,以纪念自去年任务评论酒店
public void on(CommentAddedEvent event) {
int count = uncalculatedCommentsOnHotel(...);
count++;
//update count
}
和进度基于具有计数大于零酒店摘要任务。
解决方案D是幂等的,似乎更有效。我们是否存在一些缺陷或其他解决方案?
如何保持对*阅读模式*,每家酒店的评论*号它获得*和*总分(总和)*(星星等)。也就是说,在每个* CommentAddedEvent *中,处理程序只是增加评论计数器,并为分数总和添加一些内容。然后,在查询阅读模型时,您只需阅读特定酒店的这些值即可。当然,在阅读模型表格/视图上,您可以添加一个“计算”列,平均值= *您的公式* :)您怎么看? –
@andrei但在处理程序中保留一个计数器会使处理程序成为有状态的bean? – Hippoom
我想到了类似于从读取模型中检索当前计数器并增加它们的东西。然后,我认为读取模型可以在必要时从事件重建。 –