Rails 4.2 and Elastic Search – Querying and Filtering Across Multiple Nested Models

At work recently I have been working on a new filtering and search page for ourselves. The requirements were searching and filtering said search results. Things get complicated and performance tends to suffer when dealing with complicated and far reaching relationships. You end joining every table in the database and even then you are only filtering and not actually searching. Sometimes denormalized data just makes sense. It’s still a WIP but here it as anyway, hope this snippet helps you get rolling with your project.

def self.search(query="", options={})

   params = {
      query: {
        filtered: {
          query: {
            multi_match: {
              query: query,
              fields: ['title^10', 'overview']
            },
            match_all: {}
          },
          filter: {
            bool: {
              must: [
                {
                  nested: {
                    path: 'regions',
                    filter: {
                      bool: {
                        must: [
                          {
                            terms: { 'regions.id' => options[:regions] }
                          }
                        ]
                      }
                    }
                  }
                },
                {
                  nested: {
                    path: 'genres',
                    filter: {
                      bool: {
                        must: [
                          {
                            terms: { 'genres.id' => options[:genres] }
                          }
                        ]
                      }
                    }
                  }
                }
              ]
            }
          }
        }
      },
      sort: [
        {
          options[:col].try(:downcase) => {
            order: options[:direction].try(:downcase) #, ignore_unmapped: true
          }
        }
      ]
    }

    params[:query][:filtered][:query].delete(:match_all) if query.present?
    params[:query][:filtered][:query].delete(:multi_match) if query.blank?
    params.delete(:sort) if options[:col].blank? || options[:direction].blank?

    __elasticsearch__.search(params).page(options[:page]).per(options[:limit])
  end

 

Published by

Anthony

Anthony loves open source software. Especially Linux and Ruby on Rails. He enjoys tinkering with his Raspberry Pi projects, writing code late at night, and drinking coffee. He aspires to be a Linux guru and software development magician. He is currently reading books on AI.

Leave a Reply

Your email address will not be published. Required fields are marked *