2013-11-24 3 views
5

У меня есть требование, как показано нижеЛучший способ оптимизации запроса при поиске строки в больших предложениях

стихотворение принадлежит поэту

поэт имеет много стихов

Если пользователь ищет слово «рубин "

Следует предоставить,

Общее количество раз, когда слово 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 

И чтобы подсчитывать поэты в Поэма модели

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

Где стихи около 50к. его занимает почти более 1 минуты. Я знаю, что делаю неправильно, но я не смог его оптимизировать каким-либо другим способом.

Я думаю, что нижеприведенные строки занимают слишком много времени, когда они зацикливают каждое слово из всех стихотворений.

 words.each do |word| 
     count += 1 if word.upcase.include?(word.upcase) 
     end 

Может кто-нибудь из вас показать мне путь к оптимизации it.As отсутствия знаний в запросах я не мог сделать это в любой другой форме.

Заранее спасибо

+0

Знаешь, где уходит больше всего времени: получение поэтов? получение числа вхождений для искомого слова внутри poem_column? – juanpastas

+0

Оба взяли время, но искали слово внутри poem_column, беря больше. [Столбец poem содержит до 20 строк] – devudilip

+0

Рассмотрите возможность использования [SQLite3 Full Text Search] (http://www.sqlite.org/fts3.html). –

ответ

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 запросов, не включается, так что кажется, имеет смысл.

Я подумаю, как расширить этот способ поиска по всему содержанию.

+0

Единственное, что проблема с базой данных, так как мы должны хранить информацию о каждом слове, а также о ее действительно сокращенном времени. Спасибо и приветствуем Снова таблица ключевых слов будет иметь миллионы данных – devudilip

+0

SQLite full текстовый поиск дает больше смысла в комментарии @LS_dev. Я собирался предложить переключиться на более обычную производственную БД и использовать полнотекстовый поиск, например PostgreSQL, и использовать драгоценный камень 'pg_search'. – juanpastas

0

Im мой opnion, вы можете изменить следующий код цитируемого из вашего поста:

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} 
+0

он не делает никаких различий :-( – devudilip

Смежные вопросы