Reputation: 3164
I've been looking online for quite some time for a solution, but I cannot seem to come up with anything that works. I am building a product search for a site with three ActiveRecord Models. The associations go as follows:
class NormalBrand < ApplicationRecord
has_many :normal_models
end
class NormalModel < ApplicationRecord
belongs_to :normal_brand
has_many :products
end
class Product < ApplicationRecord
belongs_to :normal_model
end
I've successfully integrated ElasticSearch into my rails app but I cannot seem to get the search to have a scope of multiple models. Currently when I search, the only fields that are searched are the columns in the Product class. I want the columns in the NormalBrand and NormalModels to be searched as well. Below is my current code for the Product class. I've read through the example on github that uses Tire but I cannot get that to work (https://github.com/elastic/elasticsearch-rails/blob/master/elasticsearch-model/examples/activerecord_associations.rb).
require 'elasticsearch/model'
class Product < ApplicationRecord
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
#associations
belongs_to :category_model
belongs_to :normal_model
has_many :order_items
has_many :quote_items
#validations
validates :name, presence: true
validates :part_number, presence: true
validates :description, presence: true
validates :sku, presence: true
validates :sku, uniqueness: true
validates :price, presence: true
validates :price, numericality: { greater_than_or_equal_to: 0.0 }
validates :weight, presence: true
validates :weight, numericality: { greater_than_or_equal_to: 0.0 }
validates :url_key, presence: true
validates :url_key, uniqueness: true
#this is an overridden method.
def self.search(query)
__elasticsearch__.search(
{
query: {
multi_match: {
query: query,
fields: ['name^10', 'text']
}
}
}
)
end
settings index: { number_of_shards: 1 } do
mappings dynamic: 'false' do
indexes :name, analyzer: 'english'
indexes :text, analyzer: 'english'
end
end
def as_indexed_json(options={})
as_json(
include: {
normal_model: { methods: [:name], only: [:name] }
}
)
end
#def to_param
# url_key
#end
end
Product.import force: true
The first time the Product.search function is called in my controller
Processing by SearchController#search as HTML
Parameters: {"q"=>"PS300"}
Product Load (0.8ms) SELECT "products".* FROM "products" ORDER BY
"products"."id" ASC LIMIT $1 [["LIMIT", 1000]]
NormalModel Load (0.4ms) SELECT "normal_models".* FROM "normal_models"
WHERE "normal_models"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "normal_models".* FROM "normal_models" WHERE
"normal_models"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Rendering search/search.html.erb within layouts/application
Rendered search/search.html.erb within layouts/application (11.6ms)
Rendered layouts/_header.html.erb (4.3ms)
Rendered layouts/_flash_messages.html.erb (0.7ms)
Rendered layouts/_footer.html.erb (0.3ms)
Completed 200 OK in 4797ms (Views: 4544.7ms | ActiveRecord: 8.7ms)
The second time I attempt to search.
Started GET "/catalogsearch/result/?q=Nordictrack" for 50.255.94.246 at 2017-05-02 13:46:47 +0000
Cannot render console from 50.255.94.246! Allowed networks: 127.0.0.1, ::1,
127.0.0.0/127.255.255.255
Processing by SearchController#search as HTML
Parameters: {"q"=>"Nordictrack"}
Rendering search/search.html.erb within layouts/application
Rendered search/search.html.erb within layouts/application (176.3ms)
Rendered layouts/_header.html.erb (1.3ms)
Rendered layouts/_flash_messages.html.erb (0.6ms)
Rendered layouts/_footer.html.erb (0.4ms)
Completed 200 OK in 239ms (Views: 237.2ms | ActiveRecord: 0.0ms)
My search controller
class SearchController < ApplicationController
def search
if params[:q].nil?
@products = []
else
@products = Product.search params[:q]
end
end
end
Upvotes: 2
Views: 788
Reputation: 1
in this case:
def as_indexed_json(options={})
as_json(
include: {
normal_model: { methods: [:name], only: [:name] }
}
)
end
you should add nested indexes for associated model:
settings index: { number_of_shards: 1 } do
mappings dynamic: 'false' do
indexes :name, analyzer: 'english'
indexes :text, analyzer: 'english'
indexes :normal_model, type: 'nested' do
indexes :name, analyzer: 'english'
end
end
end
and change your query, like this:
def self.search(query)
__elasticsearch__.search(
{
query: {
multi_match: {
query: query,
fields: ['normal_model.name^10', 'name^10', 'text']
}
}
}
)
end
Upvotes: 0