在大句子中搜索字符串时优化查询的最佳方法

dev*_*lip 5 ruby sql sqlite ruby-on-rails ruby-on-rails-3

我有如下要求

诗属于诗人

诗人有很多诗

如果用户搜索"ruby"这个词

它应该给,

所有诗歌中使用单词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
Run Code Online (Sandbox Code Playgroud)

并让诗人在诗歌模型中占有一席之地

   @poets = poems.select("distinct(poet_id)")
      @poets.each do |poet|
        @poets_word_count << poems.where("poet_id = #{poem.poet_id}").count
      end
Run Code Online (Sandbox Code Playgroud)

诗歌大约50k.它花了不到1分钟.我知道我的做法是错误的,但我不能以任何其他方式对其进行优化.

我认为以下几行花费了太多时间,因为它循环了所有诗歌的每个单词.

      words.each do |word|
        count += 1 if word.upcase.include?(word.upcase)
      end
Run Code Online (Sandbox Code Playgroud)

你们中的任何人都可以告诉我优化它的方法.由于缺乏查询知识,我无法以任何其他方式做到这一点.

提前致谢

jua*_*tas 1

不是答案,只是测试。

首先,在保存每首诗时减少提取关键字的数据:

rails g resource Keyword word occurrences poem_id:integer
rails db:migrate
Run Code Online (Sandbox Code Playgroud)

然后在你的 Poem 模型中:

# 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
Run Code Online (Sandbox Code Playgroud)

Keyword模型中:

belongs_to :poem

def self.poem_ids
  includes(:poem).map(&:poem_id)
end

def self.poems
  Poem.where(id: poem_ids)
end
Run Code Online (Sandbox Code Playgroud)

然后当您有要搜索的词时:

keywords = Keyword.where(word: word)
poems = keywords.poems
poets = poems.poets
Run Code Online (Sandbox Code Playgroud)

要使用最后一部分,您需要在Poem模型中:

def self.poet_ids
  includes(:poet).map(&:poet_id)
end

def self.poets
  Poet.where(id: poet_ids)
end
Run Code Online (Sandbox Code Playgroud)

据我所知,这种方式只需要 3 个查询,不需要连接,所以这似乎是有道理的。

我会思考如何扩展这种方式来搜索整个内容。