我正在研究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
,它只会给我一个正数。我愿意接受有关该算法的反馈,但我现在对它非常满意。我现在面临的最大问题是:
答案 0 :(得分:2)
一个非常好的解决方案,但有点复杂的是使用一些外部软件来比较每次更新“之前和之后”的文本。 Git将是一个明显的选择,你甚至可以拥有像github页面和wiki工作的版本历史!然而,还有很多其他程序,其唯一目的是比较文本和发现差异。只需在谷歌上搜索“文本比较工具”。
编辑(git集成工具):
我发现这些宝石可用于从ruby调用git命令:
编辑2(文字比较工具):
以下是我发现的一些资源,可用于比较文本:
Ruby Gems
在线API
编辑3(我对上一个问题的回答): 使用Levensthtein算法的好解决方案!我会尽力回答你最后两个问题,但没有正确答案,所以这只是我的观点:
我应该将它存储在我的postgres数据库中,还是应该使用像redis这样的其他商店?
这不是真正的键/值情况,即使你改变了实现,我也看不出有任何理由使用Redis。也许如果你以后遇到性能方面的问题,但我现在认为redis将是一个过早且适当的不必要的优化。
如果用户每隔一小时写一次,那么每天不会使每日单词过期,甚至比每天更频繁地跟踪是不是一个非常糟糕的主意?这样我就可以给作家一个非常精细的写作历史,也可以帮助他们追踪他们最有效率的时间。
不,这不是一个坏主意。 Postgres和大多数SQL数据库通常都经过优化,可以查询很多行。查询具有大量行的表,然后使用几行(例如,连接)来查询几行的速度更快。
然而,这也取决于你将如何使用这些数据。您是否只是查询最后一天左右,还是需要经常使用用户更改的整个历史记录?用于制作统计数据的Fx?如果是这种情况,您是否应该通过在较长时间内使用包含汇总数据的表来正确考虑优化。我在一些简单的会计软件中做了我自己的工作,用于显示收入和结果的统计数据(通过显示每周的摘要而不是单独的每笔交易)。
答案 1 :(得分:2)
我们大规模地做类似的事情。如果您担心可伸缩性,那么将此代码保留在基本postgres数据库中的Rails应用程序中并不是您的最佳选择。
如果您要添加一堆这样的指标,如果您要按用户计算单词和差异,则应考虑启动流处理或批处理平台。这些解决方案并非无足轻重,但如果您需要扩展,则值得。
我们的解决方案使用Twitter风暴(http://storm-project.net)与Mongo中的数据计数器。实际上,他们的例子是一个字数统计应用程序。实际上,正如你所问的那样,Redis并不是一个糟糕的选择。我不同意@jokklan,因为redis可以毫不费力地实现计数器存储。
我们确实从SQL数据库中选择了数据,所以首先,postgres不是一个糟糕的选择,但是当你开始真正扩展这个东西时,这可能是你第一件事。
我们还有分叉风暴部署,以帮助更可靠地启动风暴服务器。 https://github.com/korrelate/storm-deploy
显然,有很多不同的平台可供选择。
运行一些后台作业来使用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/)。
如果没有关于你所谈论的规模的更多信息,我不能诚实地给你一个好的推荐。鉴于此,我可以帮助缩小您的选择范围。有多少用户?你是否认真考虑所有这些粒度(如果你这样做,那就好了,只是帮助确定规模)?除了计算和差异之外,还有其他你想要做的事吗?
答案 2 :(得分:0)
这与您提出的方法类似,但会基于保存。它也可以制作一个较小的桌子。您可以使用与文本关联的模型,例如DailyText,只需user_id,日期,到期日期和单词数。然后,您可以在存储基本上执行以下操作的文本的表上具有触发器:
保存更新或插入更新daily_text set number_of_words + = length(:new) - length(:old)其中day = date.day和user_id = user.id
这会给你一点灵活性,你可以设置长度(:new) - 长度(:old)不低于零,甚至可以在removed_words列中单独删除单词。
或者你可以在任何你正在使用的程序中使用一个方法来存储之前的长度和长度,并在保存后更新这个简单的表。它基本上与数据库触发器的工作方式相同。
然后,到期日将使您能够清除旧数据的数据库。
或者,如果你想要一个非常小的桌子,那么你可以在一年中的某一天... ... 365然后有一个在午夜运行的任务来清除下一天的数据。
希望有意义