【问题标题】:How to track that a user visited the site each day for X days?如何跟踪用户每天访问该网站 X 天?
【发布时间】:2009-05-31 18:39:55
【问题描述】:

Stack Overflow 上有一个新徽章。 “woot”徽章授予在 30 天内每天访问该网站的用户。你如何实现这样的功能?如何以最简单的方式跟踪用户在 X 天内每天访问该网站的情况?

我想有两个字段 - 一个用于上次登录的时间戳,另一个用于计算用户连续访问该站点的天数。逻辑是首先将计数器设置为1,并存储登录时间。在下一次登录时,检查自上次登录以来是否不超过一天,并增加计数器,或将其设置回 1。然后将时间戳字段更新为当前日期。

你能做得更简单吗?

【问题讨论】:

  • 恕我直言,这是最佳解决方案。
  • 对了,为什么是“woot!”徽章。原来的名字(“爱好者”)更好。为什么是奇怪的字体?
  • @Zifre,因为那是赞助服务器故障启动的公司的标志
  • 确实是一个非常有趣的问题,特别是作为一个练习来证明你不能用少于两个日期变量(或日期和间隔变量)来做到这一点。我可能会选择我的第一个答案...我正在寻找那个...

标签: database-design methodology


【解决方案1】:

您确实需要一个 cookie,因为人们可能不会每天登录 -- 例如因为他们会自动登录 2 周,或者因为他们在您的网站上做的事情不是- 停止 50 小时不睡觉和吃午饭 :) 你可能真的想计算用户访问网站的时间。

现在,理论上可以记录每次访问并执行数据库查询,正如上面建议的那样,但您可能会(和我一样)认为它在实用性和隐私+简单性之间取得了错误的平衡。

您指定的算法明显存在缺陷:由于您只存储整数天数,因此您错过了每 12 小时登录和注销的用户(您的算法将天数保持为 1)

这是我发现最简洁的解决方案,每个用户有 两个 日期字段,在一种不言自明的非面向对象的 Python 中:

# user.beginStreak----user.lastStreak is the last interval when 
# user accessed the site continuously without breaks for more than 25h 

def onRegister (user):
    ...
    user.beginStreak = user.endStreak = time() # current time in seconds 
    ...

def onAccess (user): 
    ...
    if user.endStreak + 25*60*60 < time():
        user.beginStreak = time()
    user.endStreak = time()
    user.wootBadge = ( user.endStreak-user.beginStreak > 30*24*60*60 )
    ...

(请原谅我的 Pythonic 技能,我是一名学术和首次使用网站的用户)

您不能使用 one 变量来执行此任务。我相信有人可以写出一个干净的论据来证明这一事实。

【讨论】:

  • 不,不需要 cookie,特别是如果您建议将 'woot' 计算中使用的任何数字存储在那里。规则 #1:永远不要相信来自客户端的数据。
  • 好吧,cookie 之所以存在只是因为您的意思是“访问该站点”的时间问题。如果您的意思是“用户登录”,则不需要 cookie。如果您的意思是“用户在两周前登录但又回来了”,那么您需要一个 cookie。无论哪种方式,问题本身都在于 onAccess() 内部应该包含什么,而不是如何定义什么是访问。
【解决方案2】:

实际上,如果会员的访问是在一个 SQL 数据库中,你可以用一个 SQL 查询来完成整个事情。这也可能比将所有数据发送到客户端程序进行检查要快:

/*
    Find all members who visited at least once every day
  for 30 or more days.  --RBarryYoung, 2009-05-31
*/
;WITH
  cteVisitDays as (
    Select
      MemberID
    , DATEDIFF(dd,'2008-06-01',VisitTime) as VisitDay
     From tblMembersLog
     Where Not Exists( Select * From tblMemberTags T
    Where T.MemberID = tblMembersLog.MemberID
     And T.TagName = 'WOOT!' )
     Group By MemberID
        , DATEDIFF(dd,'2008-06-01',VisitTime)
    )
, cteVisitRunGroups as (
    Select 
      MemberID
    , VisitDay - Row_Number() Over(
            Partition By MemberID
            Order By VisitDay
        ) as RunGrouping
     From cteVisitDays
     )
SELECT Distinct
  MemberID
 From cteVistRunGroups
 Group By MemberId, RunGrouping
 Having COUNT(*) >= 30

【讨论】:

  • 哇,这看起来很难看。用逗号开始一行让我的眼睛流血。
  • 抱歉,我在“运营商第一”的代码格式化学校。 “尾随运算符”格式的代码对我来说看起来很怪诞。并且不要让我开始使用双向的代码......
  • 当然,不同的格式样式对专业人士来说并不重要。只要它是一致的。
【解决方案3】:

使用时间戳跟踪数据库中的每次访问(您可能已经这样做了)。然后创建一条sql语句,将结果按天分组,同时统计当天的访问次数。最近30天的时间段内,不允许有0-visit day...

【讨论】:

  • 你忘了需要 cookie。
  • 为什么?只需将每次访问都存储在数据库中..?
  • 绝不需要 cookie。用户必须登录并与站点交互。将这一天标记为“活跃”很容易。向我解释为什么您需要为您登录的网站设置 cookie?
【解决方案4】:

我第二次接受 ropstah 的方法。登录时间等用户统计信息通常在数据库中可用。我们需要从可用数据中得出某些事实。因此,与其为每次访问设置一个计数器并增加内容,我更喜欢在用户登录数据上运行并发布当天结果的批处理作业。

但是,一旦用户“吸引”了用户,您可能希望停止为该用户计算“吸引”。 否则,用户每天都有可能被“吸引”,直到遇到无登录日。 (但这是一个小问题)。

【讨论】:

    【解决方案5】:

    如果这是您想要记录的唯一内容,那么也许这是一个很好的解决方案。不过,我喜欢将逻辑和日志分开,这样既可以增加我可以使用的原始信息量,又可以在不破坏现有数据的情况下调整逻辑。

    在这种情况下,我会记录每次访问或每次操作(取决于需求/空间/等),然后在某处编写一个存储过程或方法来检查数据并返回 true(匹配徽章标准)或 false(不符合条件)。

    我会创建一个特定的架构来保存这样的信息的唯一情况是,如果所需的计算花费了太长时间,要么是因为数据量大,要么是因为数据的复杂性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-07
      • 1970-01-01
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多