Как показать выдержки из результатов мультипоиска pg-search

Я настроил pg_search в своем приложении Rails на Heroku:

@query = 'fast'
PgSearch.multisearch(@query) #=>
[#<PgSearch::Document searchable: ferrari, :content: 'this car is really fast'>,
 #<PgSearch::Document searchable: viper, :content: 'a very fast car'>]

Я хотел бы отобразить эти результаты с выдержками из content, чтобы показать, где происходит совпадение. Я могу вызвать excerpt(content, @query), чтобы получить именно то, что мне нужно, когда @query — это всего лишь одно слово, а excerpt() обрабатывает только точные совпадения, поэтому, если:

@query = 'car fast'
PgSearch.multisearch(@query) #=>
[#<PgSearch::Document searchable: ferrari, :content: 'this car is really fast'>,
 #<PgSearch::Document searchable: viper, :content: 'a very fast car'>]

тогда excerpt(content, @query) равно нулю, потому что нигде в content не появляется точная фраза «автомобиль быстро».

Я считал, что excerpt(content, @query.split(' ').first) по крайней мере показывает что-то для запросов, состоящих из нескольких слов, но все еще бывают такие случаи:

@query = 'car?'
@results = PgSearch.multisearch(@query) #=>
[#<PgSearch::Document searchable: ferrari, :content: 'this car is really fast'>,
 #<PgSearch::Document searchable: viper, :content: 'a very fast car'>]
excerpt(@results.first.content, @query) #=> nil

Итак, как люди показывают выдержки из результатов поиска при использовании pg_search?


person Steve Grossi    schedule 21.06.2012    source источник


Ответы (4)


FWIW — следуя приведенному выше примеру nertzy, я смог заставить это работать со следующим:

PgSearch.multisearch(@query).select("ts_headline(pg_search_documents.content, plainto_tsquery('english', ''' ' || unaccent('#{@query}') || ' ''' || ':*')) AS excerpt")

У меня возникли проблемы с запуском plainto_tsquery(?), поскольку он выдавал синтаксическую ошибку. Мое решение выше было просто результатом выполнения

PgSearch.multisearch(@query).select(["ts_headline(pg_search_documents.content, plainto_tsquery(?)) AS excerpt", @query]).to_sql

а затем подключить аргументы to_tsquery для нового вызова plainto_tsquery — я уверен, что это не совсем правильно, но, похоже, работает.

person sirvine    schedule 15.01.2013
comment
Этот первый блок кода работал для меня. Спасибо Sirvine за ответ и спасибо Nertzy за то, что указал нам правильное направление и за отличный драгоценный камень pg_search! - person Steve Grossi; 26.01.2013
comment
Разве этот первый блок кода не подлежит SQL-инъекции? - person bfcoder; 20.08.2015

Я автор и сопровождающий pg_search.

На данный момент нет встроенного способа получения выдержек вместе с вашими результатами в pg_search, но он легко может быть, если у меня или у кого-то еще будет время, чтобы его встроить.

В PostgreSQL есть функция ts_headline, которую вы можете вызвать который возвращает фрагмент строки в виде столбца.

Можно было бы вызвать что-то вроде этого (я еще не проверял):

PgSearch.multisearch(@query).select(["ts_headline(pg_search_documents.content, plainto_tsquery(?)) AS excerpt", @query])

Тогда каждый из ваших результатов должен иметь метод excerpt, который возвращает что-то вроде того, что вы хотите.

Кстати, это то, что я в конечном итоге хочу сделать автоматическим в pg_search. У меня просто еще не было времени вникать в это слишком глубоко.

person Grant Hutchins    schedule 13.10.2012

Если вы интерполируете строку, вы будете подвергаться атакам SQL-инъекций.

Поскольку .select не примет параметризованный оператор, как это делает .where (Users.where("id = ?", params[:id])), вам потребуется явная очистка.

sanitized = ActionController::Base.helpers.sanitize(params[:q])
@results = PgSearch.multisearch(params[:q])
                  .select(["ts_headline(pg_search_documents.content, plainto_tsquery('english', ''' ' || '#{sanitized}' || ' ''' || ':*')) AS excerpt"])
person bfcoder    schedule 19.08.2015

Есть гораздо более простой способ, если вам не хочется копаться в SQL — вы можете использовать встроенную функциональность pg_search gem для отображения выдержек очень простым и понятным способом:

В вашем контроллере:

@articles = Article.search(params[:search]).with_pg_search_highlight

На ваш взгляд:

= raw(article.pg_search_highlight)

Это должно сработать.

person The Whiz of Oz    schedule 15.07.2016
comment
Это не работает для мультипоиска, как указано в вопросе. - person thewoolleyman; 10.07.2017