我的要求如下
诗歌属于诗人 诗人有很多诗
如果用户搜索“ruby”一词
它应该给,
所有诗歌中使用单词ruby的总次数。
显示所有带有红宝石一词的诗歌。
每首诗中使用红宝石的次数。
使用单词ruby的诗人总数。
每位诗人使用红宝石这个词的总次数。
所以我在模型诗中的查询就在这里
poems= where("poem_column like ?", "%#{word}%" )
@results = {}
poems.each do |poem|
words = poem.poem_column.split
count = 0
words.each do |word|
count += 1 if word.upcase.include?(word.upcase)
end
@results[poem] = count # to get each poem using word ruby
end
让诗人数数 在诗歌模型中
@poets = poems.select("distinct(poet_id)")
@poets.each do |poet|
@poets_word_count << poems.where("poet_id = #{poem.poet_id}").count
end
诗歌大约50k。它花了不到1分钟。 我知道我的做法是错误的,但我无法以任何其他方式对其进行优化。
我认为以下几行花费了太多时间来循环所有诗歌中的每个单词。
words.each do |word|
count += 1 if word.upcase.include?(word.upcase)
end
你们中的任何人都可以告诉我优化它的方法。由于缺乏查询知识,我无法以任何其他方式进行。
提前致谢
答案 0 :(得分:1)
不是答案,只是一个测试。
首先,在保存每首诗时减少数据提取关键词:
rails g resource Keyword word occurrences poem_id:integer
rails db:migrate
然后在你的诗歌模型中:
# add more words
EXCLUDED_WORDS = %w( the a an so that this these those )
has_many :keywords
before_save :set_keywords
# { :some => 3, :word => 2, :another => 1}
def keywords_hash(how_many = 5)
words = Hash.new 0
poem_column.split.each do |word|
words[word] += 1 if not word.in? EXCLUDED_WORDS
end
Hash[words.sort { |w, w1| w1 <=> w }.take(how_many)]
end
def set_keywords
keywords_hash.each do | word, occurrences |
keywords.create :word => word, :occurrences => occurrences
end
end
在Keyword
模型中:
belongs_to :poem
def self.poem_ids
includes(:poem).map(&:poem_id)
end
def self.poems
Poem.where(id: poem_ids)
end
然后当你有词要搜索:
keywords = Keyword.where(word: word)
poems = keywords.poems
poets = poems.poets
要使用最后一部分,您需要Poem
模型:
def self.poet_ids
includes(:poet).map(&:poet_id)
end
def self.poets
Poet.where(id: poet_ids)
end
据我所知,这种方式只需要3个查询,没有连接,所以看起来很有意义。
我会考虑如何扩展这种方式来搜索整个内容。
答案 1 :(得分:0)
我的意见是,您可以更改帖子中引用的以下代码:
poems.each do |poem|
words = poem.poem_column.split
count = 0
words.each do |word|
count += 1 if word.upcase.include?(word.upcase)
end
@results[poem] = count # to get each poem using word ruby
end
为:
poems.each {|poem| @results[poem] = poem.poem_column.scan(/ruby/i).size}