elasticsearch,spree,Ruby On Rails,Ruby,elasticsearch,Spree" /> elasticsearch,spree,Ruby On Rails,Ruby,elasticsearch,Spree" />

Ruby on rails Ruby elasticsearch模型-配置多个映射 模块狂欢 Product.class_eval do 包含Elasticsearch::Model 索引\名称狂欢::ElasticsearchSettings.index 文档类型“spree\u产品” 映射所有:{“索引分析器”=>“nGram分析器”,“搜索分析器”=>“空白分析器”} 索引:名称,类型:'multi_field'do 索引:名称,类型:'string',分析器:'nGram_analyzer',boost:100 索引:未触及,键入:“字符串”,在所有索引中包含\u:false,索引:“未分析” 结束 索引:名称\整个,键入:'multi\ u field'do 索引:名称,类型:'string',索引分析器:'simple' 结束 索引:name_completion,键入:“multi_field”do 索引:未触及,键入:“字符串”,在所有索引中包含\u:false,索引:“未分析” 结束 索引:分类单元ID,键入:“多字段”do 索引:分类单元ID,类型:'string',分析器:'simple' 索引:分类单元ID,类型:'string',分析器:'ngram' 结束 索引:description,analyzer:'snowball',include_in_all:false 索引:在上可用,键入:“日期”,格式:“dateOptionalTime”,包含在所有中:false 索引:价格,类型:'double',包含在所有中:false 索引:sku,类型:'string',索引:'not_analyzed',include_in_all:false 索引:属性,类型:'string',索引:'not_analysisd',include_in_all:false 结束 映射建议:{“索引分析器”=>“简单”,“搜索分析器”=>“空白分析器”} 索引:name_completion,键入:“multi_field”do 索引:名称,类型:'completion',索引分析器:'simple',搜索分析器:'simple',有效负载:true 结束 索引:分类单元ID,键入:“多字段”do 索引:分类单元ID,类型:'string',分析器:'simple' 索引:分类单元ID,类型:'string',分析器:'ngram' 结束 索引:description,analyzer:'snowball',include_in_all:false 索引:在上可用,键入:“日期”,格式:“dateOptionalTime”,包含在所有中:false 索引:价格,类型:'double',包含在所有中:false 索引:sku,类型:'string',索引:'not_analyzed',include_in_all:false 索引:属性,类型:'string',索引:'not_analysisd',include_in_all:false 结束 def as_index_json(选项={}) 结果=as_json({ 方法:[价格,:库存单位], 仅限:[:在上可用,:说明,:名称], 包括:{ 变体:{ 仅限:[:sku], 包括:{ 选项u值:{ 仅限:[:名称,:演示文稿] } } } } }) 结果[:properties]=属性列表,除非属性列表为空? 结果[:taxon_id]=taxon.map(&:self_和_祖先)。展平.uniq.map(&:id),除非taxon.empty? 结果 结束 #用于查询elasticsearch的内部类。其思想是根据参数动态构建查询。 类产品::ElasticsearchQuery include::Virtus.model 属性:从,整数,默认值:0 属性:价格\最小值,浮动 属性:最大价格,浮动 属性:属性,哈希 属性:查询,字符串 属性:分类单元,数组 属性:浏览模式,布尔值 属性:排序,字符串 #启用浏览模式时,分类单元过滤器位于顶层。这会导致结果受到限制,但facetting是在完整的数据集上完成的。 #禁用浏览模式时,分类单元筛选器将放置在已筛选查询中。这将导致面仅限于结果集。 #方法,该方法基于当前属性创建实际查询。 #我们的想法是始终使用以下模式并填充空格。 # { #查询:{ #过滤:{ #查询:{ #查询字符串:{query:,字段:[]} # } #过滤器:{ #以及:[ #{术语:{分类单元:[]}, #{terms:{properties:[]} # ] # } # } # } #筛选器:{范围:{价格:{lte:,gte:}}, #排序:[], #发件人:, #方面: # } def to_散列 q={match_all:{} 除非查询。空白?#零或空 q={query\u字符串:{query:query,字段:['name^5','description','sku'],默认\u运算符:'AND',使用\u dis\u max:true} 结束 查询=q and_filter=[] 除非@properties.nil?| |@是空的吗? #从[{“key1”=>[“value\u a”,“value\u b”]}、{“key2”=>[“value\u a”]}转换属性 #对{terms:{properties:[“key1 | | value_a”,“key1 | | value_b”]} #{术语:{属性:[“key2 | | value_a”]} #这将强制不同属性值之间的“和”关系和相同属性值之间的“或”关系 properties=@properties.map{| k,v |[k].product(v)}.map do | pair| 和{u过滤器{order:“asc”},{“price”=>{order:“asc”},{u分数”] 当“name_desc” [{“name.untouched”=>{order:“desc”}},{“price”=>{order:“asc”}},“\u score”] 当“价格”\u asc [{“价格”=>{order:“asc”},{“名称.未触及”=>{order:“asc”},{U分数”] 当“价格描述”时 [{“price”=>{order:“desc”},{“name.untouched”=>{order:“asc”},{u分数”] 什么时候“得分” [“_score”,{“name.untouched”=>{order:“asc”},{“price”=>{order:“asc”}] 其他的 [{“name.untouched”=>{order:“asc”}},{“price”=>{order:“asc”}},{U分数”] 结束 #面 面={ 价格:{统计:{字段:“价格”}, 属性:{terms:{字段:“属性”,顺序:“计数”,大小:1000000}, 分类单元ID:{术语:{字段:“分类单元ID”,大小:1000000} } #基本骨架 结果={ min_分数:0.1, 查询:{已筛选:{}, 排序:排序, from:from,, 面:面 } #将查询和筛选器添加到已筛选的 结果[:查询][:筛选][:查询]=查询 #分类单元和属性过滤器对方面有影响 并且_filter

Ruby on rails Ruby elasticsearch模型-配置多个映射 模块狂欢 Product.class_eval do 包含Elasticsearch::Model 索引\名称狂欢::ElasticsearchSettings.index 文档类型“spree\u产品” 映射所有:{“索引分析器”=>“nGram分析器”,“搜索分析器”=>“空白分析器”} 索引:名称,类型:'multi_field'do 索引:名称,类型:'string',分析器:'nGram_analyzer',boost:100 索引:未触及,键入:“字符串”,在所有索引中包含\u:false,索引:“未分析” 结束 索引:名称\整个,键入:'multi\ u field'do 索引:名称,类型:'string',索引分析器:'simple' 结束 索引:name_completion,键入:“multi_field”do 索引:未触及,键入:“字符串”,在所有索引中包含\u:false,索引:“未分析” 结束 索引:分类单元ID,键入:“多字段”do 索引:分类单元ID,类型:'string',分析器:'simple' 索引:分类单元ID,类型:'string',分析器:'ngram' 结束 索引:description,analyzer:'snowball',include_in_all:false 索引:在上可用,键入:“日期”,格式:“dateOptionalTime”,包含在所有中:false 索引:价格,类型:'double',包含在所有中:false 索引:sku,类型:'string',索引:'not_analyzed',include_in_all:false 索引:属性,类型:'string',索引:'not_analysisd',include_in_all:false 结束 映射建议:{“索引分析器”=>“简单”,“搜索分析器”=>“空白分析器”} 索引:name_completion,键入:“multi_field”do 索引:名称,类型:'completion',索引分析器:'simple',搜索分析器:'simple',有效负载:true 结束 索引:分类单元ID,键入:“多字段”do 索引:分类单元ID,类型:'string',分析器:'simple' 索引:分类单元ID,类型:'string',分析器:'ngram' 结束 索引:description,analyzer:'snowball',include_in_all:false 索引:在上可用,键入:“日期”,格式:“dateOptionalTime”,包含在所有中:false 索引:价格,类型:'double',包含在所有中:false 索引:sku,类型:'string',索引:'not_analyzed',include_in_all:false 索引:属性,类型:'string',索引:'not_analysisd',include_in_all:false 结束 def as_index_json(选项={}) 结果=as_json({ 方法:[价格,:库存单位], 仅限:[:在上可用,:说明,:名称], 包括:{ 变体:{ 仅限:[:sku], 包括:{ 选项u值:{ 仅限:[:名称,:演示文稿] } } } } }) 结果[:properties]=属性列表,除非属性列表为空? 结果[:taxon_id]=taxon.map(&:self_和_祖先)。展平.uniq.map(&:id),除非taxon.empty? 结果 结束 #用于查询elasticsearch的内部类。其思想是根据参数动态构建查询。 类产品::ElasticsearchQuery include::Virtus.model 属性:从,整数,默认值:0 属性:价格\最小值,浮动 属性:最大价格,浮动 属性:属性,哈希 属性:查询,字符串 属性:分类单元,数组 属性:浏览模式,布尔值 属性:排序,字符串 #启用浏览模式时,分类单元过滤器位于顶层。这会导致结果受到限制,但facetting是在完整的数据集上完成的。 #禁用浏览模式时,分类单元筛选器将放置在已筛选查询中。这将导致面仅限于结果集。 #方法,该方法基于当前属性创建实际查询。 #我们的想法是始终使用以下模式并填充空格。 # { #查询:{ #过滤:{ #查询:{ #查询字符串:{query:,字段:[]} # } #过滤器:{ #以及:[ #{术语:{分类单元:[]}, #{terms:{properties:[]} # ] # } # } # } #筛选器:{范围:{价格:{lte:,gte:}}, #排序:[], #发件人:, #方面: # } def to_散列 q={match_all:{} 除非查询。空白?#零或空 q={query\u字符串:{query:query,字段:['name^5','description','sku'],默认\u运算符:'AND',使用\u dis\u max:true} 结束 查询=q and_filter=[] 除非@properties.nil?| |@是空的吗? #从[{“key1”=>[“value\u a”,“value\u b”]}、{“key2”=>[“value\u a”]}转换属性 #对{terms:{properties:[“key1 | | value_a”,“key1 | | value_b”]} #{术语:{属性:[“key2 | | value_a”]} #这将强制不同属性值之间的“和”关系和相同属性值之间的“或”关系 properties=@properties.map{| k,v |[k].product(v)}.map do | pair| 和{u过滤器{order:“asc”},{“price”=>{order:“asc”},{u分数”] 当“name_desc” [{“name.untouched”=>{order:“desc”}},{“price”=>{order:“asc”}},“\u score”] 当“价格”\u asc [{“价格”=>{order:“asc”},{“名称.未触及”=>{order:“asc”},{U分数”] 当“价格描述”时 [{“price”=>{order:“desc”},{“name.untouched”=>{order:“asc”},{u分数”] 什么时候“得分” [“_score”,{“name.untouched”=>{order:“asc”},{“price”=>{order:“asc”}] 其他的 [{“name.untouched”=>{order:“asc”}},{“price”=>{order:“asc”}},{U分数”] 结束 #面 面={ 价格:{统计:{字段:“价格”}, 属性:{terms:{字段:“属性”,顺序:“计数”,大小:1000000}, 分类单元ID:{术语:{字段:“分类单元ID”,大小:1000000} } #基本骨架 结果={ min_分数:0.1, 查询:{已筛选:{}, 排序:排序, from:from,, 面:面 } #将查询和筛选器添加到已筛选的 结果[:查询][:筛选][:查询]=查询 #分类单元和属性过滤器对方面有影响 并且_filter,ruby-on-rails,ruby,elasticsearch,spree,Ruby On Rails,Ruby,elasticsearch,Spree,发现了问题。嵌套字段以完成可能不是一个好主意 设置映射: 映射do 索引:nam module Spree Product.class_eval do include Elasticsearch::Model index_name Spree::ElasticsearchSettings.index document_type 'spree_product' mapping _all: {"index_analyzer" => "nGram_analyzer"

发现了问题。嵌套字段以完成可能不是一个好主意

设置映射: 映射do 索引:nam
module Spree
    Product.class_eval do
       include 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 :name_whole, type: 'multi_field' do
      indexes :name, type: 'string', index_analyzer:'simple'
    end

    indexes :name_completion, type: 'multi_field' do
      indexes :untouched, type: 'string', include_in_all: false, index: 'not_analyzed'
    end

    indexes :taxon_ids, type: 'multi_field' do
      indexes :taxon_ids, type:'string', analyzer: 'simple'
      indexes :taxon_ids_ngram, type:'string', analyzer:'nGram_analyzer'
    end
    indexes :description, analyzer: 'snowball', include_in_all:false
    indexes :available_on, type: 'date', format: 'dateOptionalTime', include_in_all: false
    indexes :price, type: 'double', include_in_all:false
    indexes :sku, type: 'string', index: 'not_analyzed', include_in_all:false
    indexes :properties, type: 'string', index: 'not_analyzed', include_in_all:false
 end

 mapping _suggest: {"index_analyzer" => "simple", "search_analyzer" => "whitespace_analyzer"} do
    indexes :name_completion, type: 'multi_field' do
      indexes :name, type: 'completion', index_analyzer:'simple', search_analyzer: 'simple', payloads: true
    end


    indexes :taxon_ids, type: 'multi_field' do
      indexes :taxon_ids, type:'string', analyzer: 'simple'
      indexes :taxon_ids_ngram, type:'string', analyzer:'nGram_analyzer'
    end
    indexes :description, analyzer: 'snowball', include_in_all:false
    indexes :available_on, type: 'date', format: 'dateOptionalTime', include_in_all: false
    indexes :price, type: 'double', include_in_all:false
    indexes :sku, type: 'string', index: 'not_analyzed', include_in_all:false
    indexes :properties, type: 'string', index: 'not_analyzed', include_in_all:false
 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
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 :browse_mode, Boolean
  attribute :sorting, String

  # When browse_mode is enabled, the taxon filter is placed at top level. This causes the results to be limited, but facetting is done on the complete dataset.
  # When browse_mode is disabled, the taxon filter is placed inside the filtered query. This causes the facets to be limited to the resulting set.

  # Method that creates the actual query based on the current attributes.
  # The idea is to always to use the following schema and fill in the blanks.
  # {
  #   query: {
  #     filtered: {
  #       query: {
  #         query_string: { query: , fields: [] }
  #       }
  #       filter: {
  #         and: [
  #           { terms: { taxons: [] } },
  #           { terms: { properties: [] } }
  #         ]
  #       }
  #     }
  #   }
  #   filter: { range: { price: { lte: , gte: } } },
  #   sort: [],
  #   from: ,
  #   facets:
  # }
  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: 1000000 } },
      taxon_ids: { terms: { field: "taxon_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?
    # 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
end
end