2014-01-16 31 views
2

我正在进行酒店预订项目。一项新功能要求客户可以对酒店发表评论。每个评论都有一个评分(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是幂等的,似乎更有效。我们是否存在一些缺陷或其他解决方案?

+0

如何保持对*阅读模式*,每家酒店的评论*号它获得*和*总分(总和)*(星星等)。也就是说,在每个* CommentAddedEvent *中,处理程序只是增加评论计数器,并为分数总和添加一些内容。然后,在查询阅读模型时,您只需阅读特定酒店的这些值即可。当然,在阅读模型表格/视图上,您​​可以添加一个“计算”列,平均值= *您的公式* :)您怎么看? –

+0

@andrei但在处理程序中保留一个计数器会使处理程序成为有状态的bean? – Hippoom

+0

我想到了类似于从读取模型中检索当前计数器并增加它们的东西。然后,我认为读取模型可以在必要时从事件重建。 –

回答

3

我会选择实现一个计算平均值的事件处理程序(选项b)。你有几个克服幂等问题的策略。

  1. 使消息处理器通过使用相关标识符的处理程序中添加条件检查幂等。在这种情况下,您可以跟踪每家酒店已处理的评论的ID,以防止并仅处理新评论。

    public void on(CommentAddedEvent event) 
    {  
        Hotel hotel = .... 
    
        if (hotel.CommentIds.Contains(event.CommentId)) 
         return; // comment has already been processed 
    
        double total = hotel.rating * hotel.comments; 
        double average = (total + event.rating)/(hotel.comments + 1) 
    
        hotel.CommentIds.Add(event.CommentId); 
        //update hotel 
    } 
    
  2. 基础设施级的重复数据删除的消息。收到事件时,可以针对事件存储进行检查。如果消息已经出现在事件存储中,则可以安全地丢弃它。这将确保每个事件处理程序最多接收一次该事件。

通过将重复数据删除责任移动到基础结构上,这意味着您不需要使每个事件处理程序都具有幂等性。这将允许您的原始选项b处理程序按原样工作。

进一步阅读

+0

不错的建议和文章。我所能想到的唯一风险是争议较大,尽管在我的酒店评论中不可能。但是如何总结经常总结,如页访问计数或类似的东西? – Hippoom