搜索关联模型弹性搜索 - Rails

时间:2017-05-01 17:12:26

标签: ruby-on-rails ruby elasticsearch

我已经在网上找了很长时间才找到解决方案,但我似乎无法想出任何可行的方法。我正在构建一个包含三个ActiveRecord模型的网站的产品搜索。协会如下:

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

我已成功将ElasticSearch集成到我的rails应用程序中,但我似乎无法让搜索范围包含多个模型。目前,当我搜索时,搜索的唯一字段是Product类中的列。我想要搜索NormalBrand和NormalModels中的列。下面是我目前的Product类代码。我已经阅读了使用Tire的github上的示例,但我无法让它工作(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

第一次在我的控制器中调用Product.search函数

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)

我第二次尝试搜索。

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)

我的搜索控制器

class SearchController < ApplicationController
  def search
    if params[:q].nil?
      @products = []
    else
      @products = Product.search params[:q]
    end
  end
end

1 个答案:

答案 0 :(得分:0)

在这种情况下:

def as_indexed_json(options={})
    as_json(
      include: { 
           normal_model: { methods: [:name], only: [:name] }
         }
    )
 end

您应该为关联的模型添加嵌套索引:

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

并更改您的查询,如下所示:

def self.search(query)
  __elasticsearch__.search(
    {
      query: {
        multi_match: {
          query: query,
          fields: ['normal_model.name^10', 'name^10', 'text']
        }
      }
    }
  )
end