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

时间:2013-11-24 16:31:56

标签: sql ruby-on-rails ruby ruby-on-rails-3 sqlite

我的要求如下

  诗歌属于诗人

     诗人有很多诗

如果用户搜索“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

你们中的任何人都可以告诉我优化它的方法。由于缺乏查询知识,我无法以任何其他方式进行。

提前致谢

2 个答案:

答案 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}