<commit_before>class ContSpec < ActiveRecord::Base
  belongs_to :product

  # Get specs for a single item, returns a hash of this format: {"price" => 1.75, "width" => ... }
  def self.cache_all(p_id)
    CachingMemcached.cache_lookup("ContSpecs#{p_id}") do
      select("name, value").where(["product_id = ?", p_id]).each_with_object({}){|r, h| h[r.name] = r.value}
    end
  end
  def self.cachemany(p_ids, feat) # Returns numerical (floating point) values only
    CachingMemcached.cache_lookup("ContSpecs#{feat}#{p_ids.join(',').hash}") do
      select("value").where(["product_id IN (?) and name = ?", p_ids, feat]).map(&:value)
    end
  end
  
  def self.all
    CachingMemcached.cache_lookup("ContSpecsAll#{Product.initial}") do
      joins("INNER JOIN search_products ON cont_specs.product_id = search_products.product_id").select("search_products.product_id, group_concat(cont_specs.name) AS names, group_concat(cont_specs.value) AS vals").where(:search_products => {:search_id => Product.initial}).group(:product_id)
    end
  end
  
  # This probably isn't needed anymore, but is a good example of how to do class caching if we want to do it in future.
  def self.featurecache(p_id, feat) 
    @@cs = {} unless defined? @@cs
    p_id = p_id.to_s
    unless @@cs.has_key?(Session.product_type + p_id + feat)
      find_all_by_product_type(Session.product_type).each {|f| @@cs[(Session.product_type + f.product_id.to_s + f.name)] = f}
    end
    @@cs[(Session.product_type + p_id + feat)]
  end
  
  def self.allMinMax(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}MinMax-#{feat}") do
      #all = ContSpec.allspecs(feat)
      all = ContSpec.initial_specs(feat)
      [all.compact.min,all.compact.max]
    end
  end

  def self.allLow(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}Low-#{feat}") do
      ContSpec.initial_specs(feat).sort[Session.search.product_size*0.4]
    end
  end

  def self.allHigh(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}High-#{feat}") do
      ContSpec.initial_specs(feat).sort[Session.search.product_size*0.6]
    end
  end
  
  def == (other)
     return false if other.nil?
     return value == other.value && product_id == other.product_id #&& name == other.name Not included due to partial db instatiations ie .select("product_ids, values")
  end
  
  def self.by_feat(feat)
    SearchProduct.fq2 unless defined? @@by_feat
    @@by_feat[feat]
  end
  
  
  def self.by_feat=(specs)
    @@by_feat = specs
  end
  
  private
  
  def self.initial_specs(feat)
    joins("INNER JOIN search_products ON cont_specs.product_id = search_products.product_id").where(:cont_specs => {:name => feat}, :search_products => {:search_id => Product.initial}).select("value").map(&:value)
  end<commit_msg>Attempt to take out lazy loading of caching functions (weird marshalling bug with memcached)<commit_after>class ContSpec < ActiveRecord::Base
  belongs_to :product

  # Get specs for a single item, returns a hash of this format: {"price" => 1.75, "width" => ... }
  def self.cache_all(p_id)
    CachingMemcached.cache_lookup("ContSpecs#{p_id}") do
      select("name, value").where(["product_id = ?", p_id]).all.each_with_object({}){|r, h| h[r.name] = r.value}
    end
  end
  def self.cachemany(p_ids, feat) # Returns numerical (floating point) values only
    CachingMemcached.cache_lookup("ContSpecs#{feat}#{p_ids.join(',').hash}") do
      select("value").where(["product_id IN (?) and name = ?", p_ids, feat]).all.map(&:value)
    end
  end
  
  def self.all
    CachingMemcached.cache_lookup("ContSpecsAll#{Product.initial}") do
      joins("INNER JOIN search_products ON cont_specs.product_id = search_products.product_id").select("search_products.product_id, group_concat(cont_specs.name) AS names, group_concat(cont_specs.value) AS vals").where(:search_products => {:search_id => Product.initial}).all.group(:product_id)
    end
  end
  
  # This probably isn't needed anymore, but is a good example of how to do class caching if we want to do it in future.
  def self.featurecache(p_id, feat) 
    @@cs = {} unless defined? @@cs
    p_id = p_id.to_s
    unless @@cs.has_key?(Session.product_type + p_id + feat)
      find_all_by_product_type(Session.product_type).each {|f| @@cs[(Session.product_type + f.product_id.to_s + f.name)] = f}
    end
    @@cs[(Session.product_type + p_id + feat)]
  end
  
  def self.allMinMax(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}MinMax-#{feat}") do
      #all = ContSpec.allspecs(feat)
      all = ContSpec.initial_specs(feat)
      [all.compact.min,all.compact.max]
    end
  end

  def self.allLow(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}Low-#{feat}") do
      ContSpec.initial_specs(feat).sort[Session.search.product_size*0.4]
    end
  end

  def self.allHigh(feat)
    CachingMemcached.cache_lookup("#{Session.product_type}High-#{feat}") do
      ContSpec.initial_specs(feat).sort[Session.search.product_size*0.6]
    end
  end
  
  def == (other)
     return false if other.nil?
     return value == other.value && product_id == other.product_id #&& name == other.name Not included due to partial db instatiations ie .select("product_ids, values")
  end
  
  def self.by_feat(feat)
    SearchProduct.fq2 unless defined? @@by_feat
    @@by_feat[feat]
  end
  
  
  def self.by_feat=(specs)
    @@by_feat = specs
  end
  
  private
  
  def self.initial_specs(feat)
    joins("INNER JOIN search_products ON cont_specs.product_id = search_products.product_id").where(:cont_specs => {:name => feat}, :search_products => {:search_id => Product.initial}).select("value").all.map(&:value)
  end
{'fraction_non_alphanumeric': 0.13749338974087785, 'fraction_numerical': 0.0028203772254539045, 'mean_word_length': 4.075134168157424, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4002088', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1961, 'n_words': 404}