Java 项目反应堆:用单核反应堆的结果来丰富通量的结果
我正在努力向我的公司介绍反应式编程。我正在构建一个简单的活动推荐系统演示,以证明其性能优势 我遇到的一个挑战是用一个流的结果丰富另一个流的结果。我有一个工作示例,如下所示,但我不确定这种方法是否存在任何问题。有人能看一下并提供任何潜在的改进吗Java 项目反应堆:用单核反应堆的结果来丰富通量的结果,java,reactive-programming,project-reactor,reactive-streams,Java,Reactive Programming,Project Reactor,Reactive Streams,我正在努力向我的公司介绍反应式编程。我正在构建一个简单的活动推荐系统演示,以证明其性能优势 我遇到的一个挑战是用一个流的结果丰富另一个流的结果。我有一个工作示例,如下所示,但我不确定这种方法是否存在任何问题。有人能看一下并提供任何潜在的改进吗 public Flux<Integer> getRecommendedActivities(Long userId, String location, Integer limit) { Flux<ActivityD
public Flux<Integer> getRecommendedActivities(Long userId, String location, Integer limit) {
Flux<ActivityData> activities = activityDatabaseService.getByLocation(location);
Mono<Map<String,BigInteger>> userCategoryScores = userScoresDatabaseService.get(userId);
return activities
.zipWith(userCategoryScores.cache().repeat(), this::scoreActivitiesBasedOnUserCategoryScores)
.sort(compareActivityScoreStrength)
.map(ScoredActivityData::getActivityId)
.take(limit);
}
private ScoredActivityData scoreActivitiesBasedOnUserCategoryScores(ActivityData deal,Map<String, BigInteger> categoryScores){
//This method combines the deal score and user category scores to come up with a final score
}
公共流量getRecommendedActivities(长用户ID、字符串位置、整数限制){
Flux activities=activityDatabaseService.getByLocation(位置);
Mono userCategoryScores=userScoresDatabaseService.get(userId);
返回活动
.zipWith(userCategoryScores.cache().repeat(),this::scoreActivitiesBasedOnUserCategoryScores)
.排序(比较活动核心强度)
.map(ScoredActivityData::getActivityId)
.采取(限制);
}
私有ScoredActivityData ScoreActivities基于用户分类核心(ActivityData交易、地图分类核心){
//此方法结合交易分数和用户类别分数得出最终分数
}
谢谢,
卡尔这里的代码没有本质上的错误。一些可能有用也可能无用的文体要点:
- 反应式编程的“标准”是使用流畅的风格并贯穿始终,而不是在方法顶部声明单独的局部变量,并使用反应链中的变量
模式可以很好地工作,但是如果可以避免的话,我发现它有点难看(x.zipWith(y.cache().repeat())
意味着我头脑中有两个真正的zipWith()
数据流,而不是一个被任意缓存和重复的
,因此这种行为不一定是“突出的”相反,我更喜欢单声道
——它更清楚地表明,您正在获取一个值,并通过实y.flatMapMany(x)
通量对多个值应用转换。因此,在您的情况下,这可能看起来像:
userScoresDatabaseService.get(userId) .flatMapMany(c -> activityDatabaseService.getByLocation(location) .map(a -> scoreActivitiesBasedOnUserCategoryScores(a, c)) ) .sort() //etc.
scoresDb.get(userId) .flatMapMany(c -> activityDb.getByLocation(location, limit, comparator) .map(a -> score(a, c).getActivityId()) )
确实应该是“最后的手段”操作,特别是因为您将性能优势作为探索反应式操作的理由。(从数据库服务中读取整个数据,然后对其进行排序,然后只获取第一个Flux.sort()
值会导致效率低下-最好在数据层中对值进行排序和限制。)请记住n
必须等待整个源代码Flux.sort()
完成,然后才能对值进行排序和返回,并将每个值存储在内存中,因此这样做首先会失去通量
的许多好处。它还使您的反应链更短、更简单,因为它不需要担心排序和限制通量
- Nit:有些方法名和变量名看起来很长。如果可能的话,我会缩短它们——我发现这使得在反应链的上下文中阅读起来更容易
getRecommendedActivities()
可以阅读如下内容:
userScoresDatabaseService.get(userId)
.flatMapMany(c -> activityDatabaseService.getByLocation(location)
.map(a -> scoreActivitiesBasedOnUserCategoryScores(a, c))
)
.sort() //etc.
scoresDb.get(userId)
.flatMapMany(c -> activityDb.getByLocation(location, limit, comparator)
.map(a -> score(a, c).getActivityId())
)
…至少对我来说,它读起来更短更简单。感谢您提供的详细信息真的很有用!决定遵循这种模式,但要更进一步,在数据层做更多的工作,以简化应用程序逻辑!