观察和跟踪标签和类别的实现

我刚刚修订了标签和分类的“跟踪”和“关注”功能的实现:

关注分类和标签一直是一个功能较为有限的特性。当你开始关注某个分类时,你只会从那时起关注该分类下的新主题。(存在一个边缘情况,允许你也关注被重新分类的旧主题)

这一限制……嗯……确实有些局限。例如,开始关注 Contribute > Bug 标签后,你将无法收到大量当前关于 Contribute > Bug 的历史主题讨论的通知。

新的实现以一种非常简洁的方式解决了历史数据问题。

主题跟踪状态

对于你访问的每个主题,Discourse 都会存储一条包含用户信息和该主题相关数据的记录。

  • 你第一次访问它是什么时候?
  • 你目前阅读到了哪条回复?
  • 你是否处于跟踪/关注/静音状态?
  • 等等

当账号首次创建时,该表中没有任何记录。这些记录是按需在你访问主题时创建的。

这意味着,在一个拥有 20 万个主题的旧论坛中,我们无需为每个新用户创建 20 万条跟踪状态记录。

这正是“关注”功能最初被设计为“从今往后生效”的原始原因。我不希望在你关注某个分类时,需要回填数十万条记录,那将是一场性能灾难。

新的实现通过定义“隐式关注”的概念来解决这个问题。当新回复发布时,系统会检查分类和标签偏好(除了主题级别的偏好),以决定通知哪些用户。这使得我们能够在不依赖主题跟踪状态记录(直到最后一刻)的情况下,清晰地通知用户关于旧主题的新动态。

当进入一个新主题并创建跟踪状态记录时,我们还会检查用户的标签和分类偏好,以确定是否应在初始化对象中将其设为“关注”状态。

新的跟踪和关注实现

新的关注实现方式如下:

当用户关注某个分类/标签时

  • 该分类下所有处于“跟踪”或“常规”状态的旧主题跟踪记录将变为“已关注”(原因标记为“你正在关注此分类”)
  • 我们会存储一条记录,表明用户正在关注该分类
  • 缺少状态记录的主题将被隐式关注,只有在通知用户时才会创建跟踪记录

当用户停止关注某个分类/标签时

  • 该分类下所有因关注分类而被标记为“已关注”的主题将变回“跟踪”状态
  • 我们会移除表明用户正在关注该分类的记录

注意:我已将关于如何处理历史数据的“决策权”从用户手中移除。因为如果需要,只需点击“忽略”即可轻松“停止跟踪”。绝大多数情况下,停止关注的决定是正确的,无需在此处让用户参与决策。

跟踪功能的实现更为简单:

  • 所有处于“常规”状态的旧主题跟踪记录将变为“已跟踪”。
  • 其余内容将被隐式跟踪,无需创建记录

如果你停止跟踪某个分类,我们不会自动为你“停止跟踪”相关内容。预期是用户不会随意更改这些设置,因为撤销操作并不简单。如果你已经阅读了该主题、在该主题中回复过、手动跟踪过该主题,或者达到了阅读时长要求呢?更简单的实现方式是让用户在遇到不想跟踪的主题时,自行点击“忽略”按钮。

将分类用作“邮件列表”

此实现解锁了将“分类”或“标签”关注功能作为邮件列表替代方案的能力。这一功能一直备受用户期待。

过渡期

旧系统到新系统之间没有“迁移”过程。如果你拥有大量旧主题的“跟踪状态”记录,并且正在关注某个分类,你应该:

  • 停止关注该分类
  • 重新关注该分类

这将修复所有跟踪状态。我可能会在系统完全稳定后的一周左右考虑添加迁移功能。

希望你们更喜欢这个简化的实现。欢迎反馈或提问?

21 个赞

This is awesome! :100:

I’m sure some edge cases will pop up, but this is way better than the old system.

How does muting a category work now?

2 个赞

Zero changes were made to muting. Works exactly as it used to work, hides from front page.

5 个赞

Thank you @sam this seems to be exactly what I had expected all along.

I’m not entirely sure about existing Watchings.. is the

Just for performance, removing many many rows of watching states? Or is it required to get the “hey I’m watching a category” state?

If the migration you mentioned will set the category watching state once the dust settles, that’ll be awesome.

Again, thank you for this such quick, decisive action on the matter of Watching Categories.

I feel like I’m missing something. Why put this state on a record associated with the topic at all now? Why not just always check the preference?

Because you could be not watching a category but see a topic of interest and want to watch that topic specifically (which wouldn’t be covered under preference).

1 个赞

Yeah, of course. I’m not suggesting eliminating topic-based tracking states all together. Only in the cases of tracking categories or tags.

因为用户可以覆盖特定主题

关注 Contribute > Bug,但静音某个具体的 bug

7 个赞

I see. I guess there’s have to be a nil or default topic tracking state to know when to fall back on the category or tag preference.

It’s a bit hard to tell without the migration you mention, but so far this seems to be just right.

I look forward to a migration that will set the new style tracking state, so I can finish testing this out.

2 个赞

This sounds terrific, @sam! It sounds like this change is what the mailing list crowd was asking for.

What Discourse version is this change on?

I’m not sure how to transition, though. Would we need a script that removes and re-adds all users’ watched categories?

Edit: do these changes impact the watching/tracking states of Group PMs?

A migration is quite risky here, I am worried about adding it and its just for an edge case.

The edge case we are not handling now is:

  • User visits topic X in category Y
  • User watches category Y
  • Topic X is not watched
  • Admin upgrades Discourse
  • topic X is still not watched

However this works just fine

  • User never visited topic X in category Y
  • User watches category Y
  • Admin upgrades Discourse
  • topic X is watched

@alehandrof this is in latest beta, I would not worry about transition edge cases you can deal with them on a case by case basis imo. This has no impact on group PMs

1 个赞

What if:

  • User watches category Y (because I have that as the site default for users)
  • User visits topic X in category Y
  • Topic X is not watched (in other words, they took no action while viewing it)
  • Admin upgrades Discourse

Would topic X still be watched [by way of the category watch]?

Unfortunately the edge case you mention is exactly my situation.

I have specific groups watching specific categories (automated via a plugin). I need to know that everyone in that group is receiving notifications from every topic in that category.

2 个赞

@sam In my primary forum, about 1/2 the users are in the edge case you describe, the other are in the one I describe.

Like Alex, the goal is to know that users are Watching specific categories. Perhaps removing them & reading them to a Group could reset the Watching state, via this Group-watch feature request?

2 个赞

encountered this bug recently:

  1. Start by clicking the Category dropdown menu, and choose any category.
  2. While in the selected category space, click on the watch/track button next to + New Topic
  3. Choose to watch the category
  4. Refresh page, then try to unwatch the category by setting it to other option (like Normal or Watching First Post)
  5. Refresh page, the category is still being watched (Watching is still selected).
  6. Only way to unwatch the category is through the account preference page.

Shouldn’t user be able to unwatch any category the same way they use to watch one?

1 个赞

@sam Has this actually been implemented yet? If so, could you reference the commit?

Not following, this has been implemented for ages.

2 个赞

@sam That’s what I thought, which is why I’m a bit confused.
The way I understand it, if I am watching a category, a new topic in this category would result in a record being created for this topic where the initial state would be watching.

Is that correct?
Because the way I am experiencing it now is that you will for example get a notification about the new topic, but if you vist /latest?state=watching, the new topic will not show up. It is not until you go visit the topic that the watching state will be set.

@sam did you receive my question?