【问题标题】:Smartly Tracking Words Written in a Rails App智能地跟踪写在 Rails 应用程序中的单词
【发布时间】:2013-10-14 23:38:59
【问题描述】:

问题

我正在 Rails 4 中开发一个创意写作应用程序,用户要求提供一项功能,让他们负责每天/每周/每月编写 X 个单词。处理随时间添加的词的跟踪问题的最佳方法是什么?

我目前的解决方案

我为每个用户存储了有限的总字数历史记录,让我可以将他们今天所有章节的总字数与他们昨天、上周或上个月所有章节的总字数进行比较。

我没有处理的边缘情况(并且不确定如何处理)

如果用户删除了大部分章节并重写或删除了整个章节或故事怎么办?我不想因为他们扔掉他们之前写的东西而惩罚他们。

编辑:

我刚刚修改了the Levenshtein algorithm 以计算添加、删除或替换的所有单词,以使作者对所有这些活动的写作目标给予肯定。您可以在此处查看代码:

def words_changed_since(second)
  first = self.split
  second = second.split
  matrix = [(0..first.length).to_a]
  (1..second.length).each do |j|
    matrix << [j] + [0] * (first.length)
  end

  (1..second.length).each do |i|
    (1..first.length).each do |j|
      if first[j-1] == second[i-1]
        matrix[i][j] = matrix[i-1][j-1]
      else
        matrix[i][j] = [
          matrix[i-1][j],
          matrix[i][j-1],
          matrix[i-1][j-1],
        ].min + 1
      end
    end
  end
  return matrix.last.last
end

这是在初始化器中的 String 类上的猴子补丁,因此我可以调用 new_chapter_content.words_changed_since old_chapter_content 并且它只会给我一个正数。我愿意接受有关该算法的反馈,但我现在对此非常满意。我现在最大的问题是:

  1. 我应该将它存储在我的 postgres 数据库中,还是应该使用其他存储,例如 redis?
  2. 使每日单词过期,甚至比每日更频繁地跟踪,比如用户每小时写一次,这会是一个非常糟糕的主意吗?这将使我能够为作家提供非常详细的写作历史,并帮助他们跟踪他们何时最富有成效。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 word-count


    【解决方案1】:

    一个很好但也有点复杂的解决方案是使用一些外部软件来比较每次更新“之前和之后”的文本。 Git 将是一个明显的选择,然后您甚至可以拥有 github 页面和 wikis 等版本历史!但是,还有很多其他程序,其唯一目的是比较文本和发现差异。只需在 Google 上搜索“文本比较工具”即可。

    编辑(git 集成工具):

    我发现了这些可以用来从 ruby​​ 调用 git 命令的 gem:

    编辑 2(文本比较工具):

    这里是我找到的一些资源,可以用来比较文本:

    红宝石

    在线 API

    编辑 3(我对最后一个问题的回答): Levensthtein 算法的好解决方案!我会尽量回答你最后两个问题,但没有正确答案,所以这只是我的看法:

    1. 我应该将它存储在我的 postgres 数据库中,还是应该使用其他存储,例如 redis?

      这并不是真正的键/值情况,即使您更改了实现,我也看不到任何使用 Redis 的理由。也许如果您以后遇到性能问题,但我认为现在 redis 将是一种过早且不必要的优化。

    2. 不让每天的单词过期,甚至比每天更频繁地跟踪,比如用户每小时写一次,这会是一个非常糟糕的主意吗?这将使我能够为作家提供非常详细的写作历史,并帮助他们跟踪他们何时最有生产力。

      不,这不是一个坏主意。 Postgres 和大多数 SQL 数据库通常都经过优化以查询大量行。查询一个包含很多行的表比查询几个包含几行的表(例如连接)要快。

      但这也取决于您将如何使用这些数据。您会只查询最后一天左右,还是需要经常使用用户更改的整个历史? Fx 是用来做统计的吗?如果是这种情况,您是否应该适当地考虑通过使用包含较长时期汇总数据的表格来进行优化。我自己在自己制作的一些简单会计软件中执行此操作,用于显示收入和结果的统计数据(通过显示每周的摘要而不是单独显示每笔交易)。

    【讨论】:

    • 我已经想到了这一点,因为我使用 git 进行自己的版本控制,但我担心规模。首先,我认为我必须至少将存储在数据库中的所有文本(可能很快达到数十亿字)增加一倍,同时将其存储在本地或远程 git 存储库中。我现在在 heroku 上,所以这可能意味着一个远程存储库,这意味着会有很多文本占用带宽。
    • 我添加了一些指向其他资源的链接(fx 两个 gem),您可以使用 :) 我相信您可以通过在 google 上搜索找到更多。
    • 谢谢,但我现在有一个运行良好的算法,据我所知,这些 gem 都没有进行我需要的特定文本比较。他们会告诉我插入和删除的行和字符(有时被替换),但不是单词。我现在有代码来进行文本比较。我现在只需要在帖子末尾回答几个实际问题。
    • 我已经为你的问题添加了一些答案:)
    • 谢谢!非常感谢您帮助我解决这个问题,并在我独立取得进展的同时继续改进您的答案。
    【解决方案2】:

    我们的解决方案

    我们大规模地做类似的事情。如果您担心可伸缩性,那么将此代码保留在 Rails 应用程序中,脱离基本的 postgres 数据库并不是您的最佳选择。

    如果您要添加大量这样的指标,并且要按用户计算单词和单词中的差异,则应考虑启动流处理或批处理平台。这些解决方案并非微不足道,但如果您需要规模化,这些解决方案是值得的。

    我们的解决方案使用 twitter Storm (http://storm-project.net) 和 Mongo 中的数据计数器。事实上,他们的例子是一个字数统计应用程序。 Redis,正如你所问的那样,实际上并不是一个糟糕的选择。我不同意@jokklan,因为 redis 可以毫不费力地实现计数器存储。

    我们确实从 SQL 数据库中选择数据,所以首先,postgres 不是一个糟糕的选择,但是当你开始真正扩展这个东西时,这可能是你首先要删除的东西。

    我们还分叉了 Storm 部署,以帮助更可靠地启动 Storm 服务器。 https://github.com/korrelate/storm-deploy

    其他选项

    但显然,有很多不同的平台可供选择。

    1. 您可以使用 Hadoop MapReduce (http://hadoop.apache.org/docs/stable/mapred_tutorial.html)

    2. 我们通过 Mortar Data 用于其他东西的猪 (http://www.mortardata.com)

    3. Amazon EMR 可让您执行基本的 MapReduce 或 Pig 作业,但这更多是一种平台选择,而不是框架和实施选择

    4. 使用 Sidekiq (https://github.com/mperham/sidekiq) 或 Resque(鉴于 sidekiq 的进步并不真正推荐)或作为服务运行的 Iron Worker (http://www.iron.io/worker) 运行一些后台作业来编译此信息

      这是一篇关于我提到的一些选择的好文章,可能还有其他一些选择 (http://highlyscalable.wordpress.com/2013/08/20/in-stream-big-data-processing/)。

    推荐

    如果没有关于您所谈论的规模的更多信息,我无法诚实地给您一个好的建议。鉴于此,我或许可以帮助您更好地缩小选择范围。有多少用户?您是否认真考虑提供所有这些粒度(如果您愿意,那很好,只是帮助确定规模)?除了计数和比较之外,您还有其他想做的事情吗?

    【讨论】:

    • 这个答案非常有帮助,我希望我能在你和 jokklan 之间分红,因为你们都给了我一些新的信息和观点。我已经投票赞成这个答案,我希望其他人也这样做。
    • 其中有几个我没有听说过的项目(twitter 风暴,或 Hadoop MapReduce 等),但确实有很多选择。在我看来,@WattsInABox 比我更了解这个话题!但归根结底,一切都是为了找到适合您需求的东西。检查这些项目,看看你的项目最需要什么:)!我会推荐像 Sidekiq 这样简单的东西开始(你肯定需要某种后台工作者!),然后等待复杂的解决方案来满足你的需要,但是我之前没有尝试过这些,这真的完全取决于你:)!
    • 我同意@jokklan。该决定完全取决于规模(当前和未来)以及您计划添加多少功能。如果您想要计划在其上广泛构建的东西,那么早点跳到更复杂的技术可能是值得的。
    【解决方案3】:

    这与您建议的方法类似,但将基于保存。它还可以做成一张更小的桌子。你可以有一个与文本相关联的模型,比如 DailyText 只是 user_id、日期、到期日期和字数。然后,您可以在存储您的文本的表上设置触发器,这些触发器基本上执行以下操作:

    保存更新或插入更新daily_text set number_of_words += length(:new) - length(:old) where day = date.day and user_id = user.id

    这会给你一点灵活性,你可以设置 length(:new) - length(:old) 不低于零,甚至在 removed_words 列中单独计算删除单词。

    或者你可以在你使用的任何程序中使用一个方法来存储之前的长度和长度,然后在保存后更新这个简单的表。它本质上与数据库触发器的工作方式相同。

    到期日期将使您能够清除旧数据的数据库。

    或者,如果您想要一个非常小的表格,您可以将一年中的某一天设为 1 .. 365,然后有一个任务在午夜运行以清除接下来几天的数据。

    希望这是有道理的

    【讨论】:

    • 我已经编辑了我的问题,因为我得出了关于每次保存增加字数的类似结论,我现在有一个很好的算法来做到这一点。我正在考虑不要让这些记录过期,但不想在此过程中破坏我的数据库性能。您可以在我的编辑末尾看到加粗的问题以获取更多信息 - 我很喜欢您的想法。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    相关资源
    最近更新 更多