1
votes

After following the Searchkick Readme and a few examples, I've tried to implement a fairly straightforward search involving a belongs_to association. Still, I'm not seeing the behavior I was hoping for, and I'm hoping I'm just missing something small...

I have an Book model that belongs_to Author. I'd like to enable a search on either book names or author names. So, for example, if I were to search for "Stone" I'd see both "Stone Phillips" (author) and "A Stone's Throw" (book). Furthermore if I were to amend my search to "Stone meadow" it would return Stone Phillips as an author along with his book titled "My meadow".

I found a way to solve for the first example, but I can't get the second example to work. Currently, I have a simple pg_search executing both of the above examples with ease, using an "associated_against" method. Though I thought Searchkick provided something as simple as that, I can't seem to make it work...

The major approaches I've tried:

In my controller

@search = Book.search params[:query],
      limit: 30,
      fields: [:book_name, :author_name], 
      misspellings: false

And in my model (first just the "search_data" method; later added the scope...)

scope :search_import, -> { includes(:author) } 
  
  def search_data
    {
      book_name: book_name,
      author_name: author(&:author_name)
    }
  end

This approach doesn't return any results on the author name for some reason. I'm only seeing related book names when I use one word searches--and I don't see any results with multiple word searches.

I've also tried switching this to run through the Author model, which seems to work better because I get results for both books and authors. However, I also get a lot of garbage results that aren't related. And, I still only see results for one word searches--no results on two word searches.

I've also tried adding multiple Model indices to my controller code:

@search = Book.search params[:query],
      limit: 30,
      index_name: [Book.searchkick_index.name, Author.searchkick_index.name],
      fields: [:book_name, :author_name], 
      misspellings: false

This actually provides the best set of results for one word. It returns all the expected book names and author names without all the garbage. But when I try to add a second word to narrow the search, I get no results...

I've tried a number of other small changes, using suggestions from other posts, tutos, etc. And, in case anyone is wondering, I'm always reindexing after I make changes to the search_data or searchkick methods.

I hope I've provided enough info, but please let me know if you have questions....I can't seem to figure out what's eluding me. Any help is much appreciated!

1

1 Answers

0
votes

Here's how we implemented something similar in our system (note this is a trimmed down extraction, so there may be a few minor syntax issues, but should get the general gist across):

class Product
  searchkick word_middle: [:title, :authors]

  def search_data
    {
      title: title,
      authors: authors.map(&:full_name).join('')
    }
  end

  def search_by_title_or_author(term, opts = {})
    search_opts = default_search_opts.merge(opts)
    search term, search_opts.merge(
      operator: 'or',
      fields: [
        [ { 'title^10': :word_middle }, { 'authors': :word_middle } ]
      ]
    )
  end

  protected

  def default_search_opts
    {
      per_page: 10,
      load: false  # we use caching, so don't load from DB by default,
      # we have other defaults as well that we include here
    }
end

In our experience, this has worked best for us, but your needs might require some tweaking. We also weigh title matches higher, so you can omit that boost if you'd like.