Search code examples
ruby-on-railspg-search

How to show excerpts from pg-search multisearch results


I've set up pg_search in my Rails app on 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'>]

I'd like to display these results with excerpts from content to show where the match occurs. I can call excerpt(content, @query) to get exactly what I want when @query is only one word, but excerpt() only handles exact matches, so if:

@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'>]

then excerpt(content, @query) is nil because nowhere in content does the exact phrase 'car fast' appear.

I considered excerpt(content, @query.split(' ').first) to at least show something for multi-word queries, but there are still cases such as this:

@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

So, how do folks show excerpts from search results when using pg_search?


Solution

  • FWIW— Following nertzy's example above, I was able to get this to work with the following:

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

    I was having trouble getting plainto_tsquery(?) to work, as it was throwing a syntax error. My solution above was simply the result of doing

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

    and then plugging in the to_tsquery arguments for the new plainto_tsquery call—something I'm sure is not entirely sound, but seems to work.