使用弹性搜索按大小过滤狂欢产品

时间:2015-05-06 14:24:13

标签: ruby-on-rails ruby ruby-on-rails-4 elasticsearch spree

这是我的spree_elasticsearch_product_decorator.rb文件,其中包含所有搜索逻辑 模块狂欢   Product.class_eval做     包括Elasticsearch :: Model

index_name Spree::ElasticsearchSettings.index
document_type 'spree_product'

mapping _all: {"index_analyzer" => "nGram_analyzer", "search_analyzer" => "whitespace_analyzer"} do
  indexes :name, type: 'multi_field' do
    indexes :name, type: 'string', analyzer: 'nGram_analyzer', boost: 100
    indexes :untouched, type: 'string', include_in_all: false, index: 'not_analyzed'
  end
  indexes :description, analyzer: 'snowball'
  indexes :available_on, type: 'date', format: 'dateOptionalTime', include_in_all: false
  indexes :price, type: 'double'
  indexes :sku, type: 'string', index: 'not_analyzed'
  indexes :taxon_ids, type: 'string', index: 'not_analyzed'
  indexes :collection_ids, type: 'string', index: 'not_analyzed'
  indexes :properties, type: 'string', index: 'not_analyzed'
end

def as_indexed_json(options={})
  result = as_json({
    methods: [:price, :sku],
    only: [:available_on, :description, :name],
    include: {
      variants: {
        only: [:sku],
        include: {
          option_values: {
            only: [:name, :presentation]
          }
        }
      }
    }
  })
  result[:properties] = property_list unless property_list.empty?
  result[:taxon_ids] = taxons.map(&:self_and_ancestors).flatten.uniq.map(&:id) unless taxons.empty?
  result[:collection_ids] = collections.uniq.map(&:id) unless collections.empty?
  result
end

# Inner class used to query elasticsearch. The idea is that the query is dynamically build based on the parameters.
class Product::ElasticsearchQuery
  include ::Virtus.model

  attribute :from, Integer, default: 0
  attribute :price_min, Float
  attribute :price_max, Float
  attribute :properties, Hash
  attribute :query, String
  attribute :taxons, Array
  attribute :collections, Array
  attribute :browse_mode, Boolean
  attribute :sorting, String

  def to_hash
    q = { match_all: {} }
    unless query.blank? # nil or empty
      q = { query_string: { query: query, fields: ['name^5','description','sku'], default_operator: 'AND', use_dis_max: true } }
    end
    query = q

    and_filter = []
    unless @properties.nil? || @properties.empty?
      # transform properties from [{"key1" => ["value_a","value_b"]},{"key2" => ["value_a"]}
      # to { terms: { properties: ["key1||value_a","key1||value_b"] }
      #    { terms: { properties: ["key2||value_a"] }
      # This enforces "and" relation between different property values and "or" relation between same property values
      properties = @properties.map {|k,v| [k].product(v)}.map do |pair|
        and_filter << { terms: { properties: pair.map {|prop| prop.join("||")} } }
      end
    end

    sorting = case @sorting
    when "name_asc"
      [ {"name.untouched" => { order: "asc" }}, {"price" => { order: "asc" }}, "_score" ]
    when "name_desc"
      [ {"name.untouched" => { order: "desc" }}, {"price" => { order: "asc" }}, "_score" ]
    when "price_asc"
      [ {"price" => { order: "asc" }}, {"name.untouched" => { order: "asc" }}, "_score" ]
    when "price_desc"
      [ {"price" => { order: "desc" }}, {"name.untouched" => { order: "asc" }}, "_score" ]
    when "score"
      [ "_score", {"name.untouched" => { order: "asc" }}, {"price" => { order: "asc" }} ]
    else
      [ {"name.untouched" => { order: "asc" }}, {"price" => { order: "asc" }}, "_score" ]
    end

    # facets
    facets = {
      price: { statistical: { field: "price" } },
      properties: { terms: { field: "properties", order: "count", size: 100 } }, 
      taxon_ids: { terms: { field: "taxon_ids", size: 1000000 } },
      collection_ids: { terms: { field: "collection_ids", size: 1000000 } }
    }

    # basic skeleton
    result = {
      min_score: 0.1,
      query: { filtered: {} },
      sort: sorting,
      from: from,
      facets: facets
    }

    # add query and filters to filtered
    result[:query][:filtered][:query] = query
    # taxon and property filters have an effect on the facets
    and_filter << { terms: { taxon_ids: taxons } } unless taxons.empty?
    and_filter << { terms: { collection_ids: collections } } unless collections.empty?
    # only return products that are available
    and_filter << { range: { available_on: { lte: "now" } } }
    result[:query][:filtered][:filter] = { "and" => and_filter } unless and_filter.empty?

    # add price filter outside the query because it should have no effect on facets
    if price_min && price_max && (price_min < price_max)
      result[:filter] = { range: { price: { gte: price_min, lte: price_max } } }
    end

    result
  end
end

private

def property_list
  product_properties.map{|pp| "#{pp.property.name}||#{pp.value}"}
end

我需要以某种方式实现大小过滤器

对于每个大小,我有一个Spree :: Variant属于Spree :: Product,并在name列中存储size的值,例如 Spree :: Variant.name =“13 US”

如何使用elasticsearch按变体对产品进行排序?

感谢您的帮助!

0 个答案:

没有答案