Поиск слишком медленный. Как мне переиндексировать базу данных postgres в приложении rails с помощью gem pg_search?

Я использую гем pg_search в своем приложении для функции поиска. Перед добавлением pg_search я уже добавил 130 000 строк данных в таблицу в моей базе данных Postgres. Теперь, когда я запускаю поиск, он занимает слишком много времени, то есть около 16000 мс.

Я слежу за полнотекстовым поиском Railscasts Episode343 в PostgreSQL

Вот код моей модели для pg_search:

include PgSearch
pg_search_scope :search, :against => [:applicant, :generic_name, :trade_name, :description],
using: {tsearch: {dictionary: "english"}},
ignoring: :accents

def self.text_search(query)
    if query.present?
        rank = <<-RANK
            ts_rank(to_tsvector(generic_name), plainto_tsquery(#{sanitize(query)})) +
            ts_rank(to_tsvector(trade_name), plainto_tsquery(#{sanitize(query)}))+
            ts_rank(to_tsvector(description), plainto_tsquery(#{sanitize(query)})) +
            ts_rank(to_tsvector(applicant), plainto_tsquery(#{sanitize(query)})) 
        RANK
        where("generic_name @@ :q or trade_name @@ :q or description @@ :q or applicant @@ :q", q: query)
    else
        all
    end
end

И мой вывод на сервер выглядит следующим образом:

  Parameters: {"utf8"=>"✓", "query"=>"intraocular lenses"}
  Parameters: {"utf8"=>"✓", "query"=>"intraocular lenses"}
  Rendered layouts/_search.html.erb (1.5ms)
  Rendered layouts/_search.html.erb (1.5ms)
  Rendered medicaldevices/index.html.erb within layouts/application (16535.9ms)
  Rendered medicaldevices/index.html.erb within layouts/application (16535.9ms)
  Rendered layouts/_header.html.erb (1.8ms)
  Rendered layouts/_header.html.erb (1.8ms)
  Rendered layouts/_footer.html.erb (0.1ms)
  Rendered layouts/_footer.html.erb (0.1ms)
Completed 200 OK in 16574ms (Views: 60.3ms | ActiveRecord: 16510.7ms)
Completed 200 OK in 16574ms (Views: 60.3ms | ActiveRecord: 16510.7ms)

Вот мой файл миграции для индексации

class AddSearchIndexToMedicaldevices < ActiveRecord::Migration

 def up
     execute "create index generic_name on medicaldevices using gin(to_tsvector('english',     generic_name))"
    execute "create index trade_name on medicaldevices using gin(to_tsvector('english', trade_name))"
    execute "create index description on medicaldevices using gin(to_tsvector('english', description))"
    execute "create index applicant on medicaldevices using gin(to_tsvector('english', applicant))"
  end

  def down
    execute "drop index generic_name"
    execute "drop index trade_name"
    execute "drop index description"
    execute "drop index applicant"
  end

end

person Subrat Rout    schedule 11.10.2013    source источник
comment
При чтении документов текстового поиска PostgreSQL можно сделать вывод, что вам следует использовать индекс GIN.   -  person Denis de Bernardy    schedule 11.10.2013


Ответы (2)


Думаю, вот ваш ответ (http://www.postgresql.org/docs/8.3/static/textsearch-tables.html).

12.2.2. Создание индексов

Мы можем создать индекс GIN (раздел 12.9) для ускорения текстового поиска:

CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector('english', body));

Обратите внимание, что используется версия to_tsvector с двумя аргументами. В индексах выражений можно использовать только функции текстового поиска, которые задают имя конфигурации (раздел 11.7). Это связано с тем, что default_text_search_config не должен влиять на содержимое индекса. Если бы они были затронуты, содержимое индекса могло бы быть несовместимым, потому что разные записи могли бы содержать tsvectors, которые были созданы с разными конфигурациями текстового поиска, и не было бы никакого способа угадать, какие из них какие. Правильно сделать дамп и восстановить такой индекс было бы невозможно.

Поскольку версия to_tsvector с двумя аргументами использовалась в указанном выше индексе, только ссылка на запрос, использующая версию to_tsvector с двумя аргументами с тем же именем конфигурации, будет использовать этот индекс. То есть WHERE to_tsvector ('english', body) @@ 'a & b' может использовать индекс, а WHERE to_tsvector (body) @@ 'a & b' - не может. Это гарантирует, что index будет использоваться только с той же конфигурацией, которая использовалась для создания записей индекса.

person Sergio Tulentsev    schedule 11.10.2013

Серджио, я следовал тому пути, о котором вы упомянули, и это сработало. Мне пришлось изменить свой старый код выше на следующий:

where("to_tsvector('english', generic_name) @@ plainto_tsquery(:q) or 
       to_tsvector('english', trade_name) @@ plainto_tsquery(:q) or 
       to_tsvector('english', description) @@ plainto_tsquery(:q) or 
       to_tsvector('english', applicant)@@ plainto_tsquery(:q)", q: query).order("#{rank} DESC")

Мне пришлось добавить planto_tsquery (q) для поиска по нескольким словам. Спасибо!

person Subrat Rout    schedule 11.10.2013