1

问题

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

我目前的解决方案

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

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

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

编辑:

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

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. 不让每天的单词过期,甚至比每天更频繁地跟踪,比如用户每小时写一次,这会是一个非常糟糕的主意吗?这将使我能够为作家提供非常详细的写作历史,并帮助他们跟踪他们何时最富有成效。
4

3 回答 3

2

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

编辑(git集成工具):

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

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

这是我找到的一些资源,它们可能对比较文本很有用:

红宝石

在线 API

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

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

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

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

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

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

于 2013-10-08T07:55:05.470 回答
2

我们的解决方案

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

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

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

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

我们还分叉了风暴部署,以帮助更可靠地启动风暴服务器。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/工人

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

推荐

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

于 2013-10-14T15:38:59.137 回答
0

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

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

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

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

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

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

希望这是有道理的

于 2013-10-08T16:57:32.920 回答