我在Ruby 1.9.2p320上使用Rails 3.2.11。
我创建了一个summarized()
方法,以显示某些关键字出现在一系列1,000到15,000个单词文档中的位置,这些文档存储为文本字符串。每个文档可以包含0到100次的每个关键字。
我有:
ActiveRecord::Schema.define(:version => 20130404000559) do
create_table "references", :force => true do |t|
t.text "source_text"
end
end
当我致电@reference.source_text.summarize(keywords)
时,即使keyword
中只有一个keywords
,以下方法也非常慢,:
class String
def summarized(keywords)
safe_text = Array.new
result = String.new
keywords.each do |keyword|
safe_text << self.strip_tags.gsub(/\n|\r/, " ").gsub(" ", " ").scan(/\w*.{0,250}#{keyword}.{0,250}\w*/im)
end
return safe_text.flatten.uniq
end
end
如何加快速度?
更新:我现在正在考虑strip_tags
may be at least one of the culprits的可能性。
答案 0 :(得分:6)
让我们先来看看为什么它很慢。你的正则表达式是这样开始的:
/\w*.{0,250}
现在让我们从更糟糕的情况开始(在你的情况下非常频繁)。你有1000个字符没有你的关键字。您的正则表达式将首先出现第一个单词,如果您的关键字在此处,则稍后检查250个字符。不。它会回到249。还是不高兴。 250次尝试之后,将开始对\w*
部分进行相同操作。你很幸运,单词很短。 它会对下一个(至少)749个字符做同样的事情。所以,在更糟糕的情况下,你会像250次一样通过你的字符串。 Laziness会解决问题,但是,我认为这不是你想要的行为(这个.{0,250}
是处理字符串的开头,不是吗?)。
现在,一个很酷的正则表达式工具是外观。您可以继续或返回字符串以进行一些额外的检查。虽然它不是捕获字符串的一部分,但您可以在其中使用捕获组 缺点?你不能有任意大小的落后(该死,只是你需要的)。所以它不会很有效,因为你不能确保在开头有一个完整的单词,但你也无法匹配字符串的250个第一个字符中的关键字。
所以,这是一个奇怪的解决方案:
- 在字符串的开头添加250个字符(空格?...),以确保我们可以在开头捕获单词。
- 使用此正则表达式(您可以考虑m_x所说的内容,并且只对所有关键字使用一次):
/#{keyword}(?<=(.{250}))(.{0,250}\w*)/im
然后操作相当多的结果(通过添加捕获的组重新组合字符串,删除作为250个添加的部分的最终字符,可能删除第一个单词以确保它的整体...)它应该要快得多。
编辑(关于正则表达式的评论):
您可能想知道为什么(?<=(.{250}))
放在关键字之后。好吧,只是在匹配关键字后进行捕获。这也意味着关键字也将成为捕获组的一部分,并且捕获组将仅在关键字之前捕获250-keyword.length字符(这不是一个问题,您可以根据长度动态创建正则表达式你的关键字,无论如何,我认为这不是一个问题)。你也可以在关键字的第一个字符之后放置lookbehind但是这很痛苦......好吧,我会在这里停止我的独白。
答案 1 :(得分:2)