Ruby on rails 如何使用Ruby快速计算字符串中子字符串的出现次数

Ruby on rails 如何使用Ruby快速计算字符串中子字符串的出现次数,ruby-on-rails,ruby,performance,string,benchmarking,Ruby On Rails,Ruby,Performance,String,Benchmarking,我有一个300MB大小的文本文件,我想计算文件中每10000个子字符串的出现次数。我想知道如何快速完成 现在,我使用以下代码: content = IO.read("path/to/mytextfile") Word.each do |w| w.occurrence = content.scan(w.name).size w.save end Word是一个ActiveRecord类 我花了将近一天的时间才完成计数。有没有办法加快速度?谢谢 编辑1: 再次感谢你。我正在运行rails

我有一个300MB大小的文本文件,我想计算文件中每10000个子字符串的出现次数。我想知道如何快速完成

现在,我使用以下代码:


content = IO.read("path/to/mytextfile")
Word.each do |w|
  w.occurrence = content.scan(w.name).size
  w.save
end
Word是一个ActiveRecord类

我花了将近一天的时间才完成计数。有没有办法加快速度?谢谢

编辑1: 再次感谢你。我正在运行rails 2.3.9。单词表的
name
字段包含我正在搜索的内容,并且它只包含唯一的值。我使用批处理(每次1000行)加载,而不是使用
Word.each
。这应该会有帮助

我用博隆的想法重写了整个代码。现在只花了几个小时就完成了计数

我分析了新版本的代码,现在花费时间最多的方法是utf8编码支持的字符串截断代码

def truncate(n)
  self.slice(/\A.{0,#{n}}/m)
end
字符计数码

def utf8_length
  self.unpack('U*').size
end

还有其他更快的方法来替换它们吗?

使用
scan
创建一个数组,计算数组的大小,然后将其丢弃。如果在一个大文件中多次出现子字符串,则会临时创建一个大数组,这可能会消耗内存管理的CPU时间,但即使使用300MB,也应该运行得很快

因为Word是一个ActiveRecord类,所以它依赖于模式和数据库中的任何索引,以及数据库服务器可能存在的任何问题。如果数据库未优化或响应缓慢,或者用于检索数据的查询效率低下,那么迭代将很慢。您可能会发现抓取
Word
组的速度要快得多,这样它们就在RAM中,然后对它们进行迭代

而且,如果数据库和代码在同一台机器上运行,您可能会受到资源限制,例如只有一个驱动器,没有足够的RAM,等等

如果不了解更多关于您的环境和硬件的信息,很难说


编辑:


我可以先将子字符串抓取到数组/散列中,然后将计数结果添加到数组或散列中,并在所有计数完成后将结果写回数据库。你觉得会更快,对吗

不,我怀疑这会有很大帮助,而且,在不知道问题所在的情况下,您可能会使问题变得更糟,因为您必须从数据库中加载10000条记录作为对象,然后构建一个10000个元素的哈希或数组,该哈希或数组也将与DB记录一起存储在内存中,然后将它们写出来

Ruby目前只使用一个内核,但使用Ruby1.9+可以提高速度。我建议让它管理你的Ruby。请务必阅读该页上的说明,然后运行
rvm notes
并遵循这些说明

您的单词模型以及底层模式和索引是什么样子的?数据库是否在同一台计算机上


编辑:从您的表模式来看,除了
id
之外,您没有任何索引,这对正常的查找没有多大帮助。我建议在Stack Overflow的同级站点上展示您的模式,并解释您想要做什么。至少,我会在文本字段中添加一个键,以帮助避免对任何搜索进行全表扫描

更有用的是阅读:来自“活动记录查询接口”

另外,请查看当您的
Word.each运行时发出的SQL。是否类似于“从word中选择*”
?如果是这样的话,Rails将拉入10000条记录,逐个对它们进行迭代。如果它类似于
“select*from word where id=1”
,那么在更新计数时,对于每个记录,都会先读取数据库,然后再写入。这就是“批量检索多个对象”链接将帮助修复的场景

另外,我猜
内容
是您正在搜索的文本,但我不能确定。是否可能存在重复的文本值,导致您对同一文本进行多次扫描?如果是这样,请使用该字段上的
唯一
条件选择您的记录,然后一次性更新所有匹配记录的计数

你有没有分析过你的代码,看看Ruby本身是否能帮助你找出问题所在?稍微修改代码以处理100或1000条记录。使用
-r profile
标志启动应用程序。当应用程序退出时,探查器将输出一个表,显示花费的时间


您正在运行什么版本的Rails?

我认为您可以用不同的方式解决这个问题

您不需要扫描文件这么多次,您可以创建一个数据库,如在或中,对于找到的每个单词,您获取它的数据库,然后添加一些“计数器”字段

你可以问我“但是我必须经常扫描我的数据库,这可能需要更多”。当然,你不会问这个问题,但这不会花费更多的时间,因为数据库集中在IO中,而且你总是可以


编辑:根本没有办法划界??假设在有a Word.name字符串的地方,实际上包含一个(不简单的)正则表达式。正则表达式是否可以包含\n?好的,如果正则表达式可以包含任何值,那么您应该估计正则表达式可以获取的字符串的最大大小,将其加倍,并按该字符数扫描文件,但将光标移动该数字

假设您估计您的正则表达式可以获取的最大值为20个字符,而您的文件具有0到30000个字符。你把每个正则表达式从0到40个字符,然后再从20到60,从40到80,等等

您还应该保持较小正则表达式的位置,这样它就不会重复


最后,这个解决方案似乎不值得努力,您的问题可能有一个基于正则表达式的更好的解决方案,但它比调用扫描字快。计数乘以您的300Mb字符串。

您可以将整个“Word”表加载到一个表中,然后从您说的