如何有效地搜索字符串化数据?

时间:2017-04-24 18:18:50

标签: ruby-on-rails ruby database activerecord database-design

我有一个父ProductCategory和一个孩子Product。例如:

ProductCategory --- Product
          Drill --- DeWalt DWD 112
                --- Black & Decker 5 C
        Bicycle --- Motobecane Turino ELITE Disc Brake
                --- Shimano Aluminum

对于给定的ProductCategory,有一组属性,所有Products都应该相互比较(即,有数据)。但是,这组属性可能会在ProductCategories

之间变化

例如,对于Drill的ProductCategory,属性可能是Voltage, Amps, Corded vs Cordless。每个Product钻取都需要有这样的信息。但是,对于自行车的ProductCategory,属性应为Size, Road vs Mountain,并且每个Product自行车都需要具有此信息。 (对不起,我不知道任何关于演习或自行车的事情......为什么我选择这个是愚蠢的)

我试图设计数据库,以便对于给定的Product,属性是我可以轻松搜索的内容。例如,理想情况下我可以运行此命令:

drills = Product.where(product_category_id:1)
drills.where("voltage >= ?", 5)
-> returns the individual drills, which may include DeWalt but not Black & Decker

这似乎是一个有趣的权衡...因为我必须让Product为每个ProductCategory的每个属性都有列,即使是那些不是# Product columns :voltage, :integer #for Drill :amps, :integer #for Drill :corded, :boolean #for Drill :size, :integer #for Bicycle :mountain, :boolean #for Bicycle ... 的列。与之相关。例如:

ProductCategories

这看起来并不可持续......你可以很快看到,只有少数Product很快会有无数Product列!

另一方面,我考虑在父ProductCategory中定义每个Product所需的属性,然后请求这些属性/将它们存储在# ProductCategory has a column... :required_attributes, :text ProductCategory.where(name:"Drill").first.required_attributes -> "voltage,amps,corded" ProductCategory.where(name:"Bicycle").first.required_attributes -> "size,mountain" # Product has a column... :attribute_data, :text Product.where(name:"DeWalt").first.attribute_data -> "{'voltage':5,'amps':5,'corded':5}" 上作为字符串化数据:

Product

通过上面的设计,我可以创建一个强制执行该操作的前端,在创建required_attributes后,必须在每个drills = ProductCategory.where(name:"Drill") drills.where("attribute_data ...") 基于逗号分割后为其提供信息。但是当然,这会使搜索效率降低,至少我认为它确实...所以这是我的问题。 如何有效地搜索字符串化数据?如果我要搜索至少5伏的所有演练,请完成下面的操作。

#**include "stdafx.h"
#include <iostream>
#include <process.h>
#include <ctime>
#include <cstdlib>
#include <random>
using namespace std;
double printMatrix();
int main()
{
    int n = 0, m = 1;
    srand(time(0));
    rand() % 2;
    double printMatrix();
    cout << "Enter the number of rows: ";
    cin >> n;
    cout << "Enter the number of columns: ";
    cin >> m;
    system("pause");
    return 0;
}
double printMatrix()
{
    return (double)rand() / ((double)RAND_MAX + 1);
}

2 个答案:

答案 0 :(得分:0)

最简单的解决方案是在products上使用JSON or HSTORE数据类型列来存储规范。

但是如果你想为每个规范提供更多的控制和验证,你可以使用带有连接表的设计:

class Product
  has_many :specs
  has_many :definitions, through: :specs
end

# This is the "normalized" table that defines an specification
# for example "Size". This just holds the name for example and the acceptable values.
class Definition
  has_many :specs
  has_many :products, through: :specs
end

# this contains the actual specs of a product (the value)
# specs.payload is a JSON column
class Spec
  belongs_to :definition
  belongs_to :product
  delegate :name, to: :definition

  def value
    payload[:value]
  end

  def value=(val)
    payload[:value] = val
  end
end

使用这样的设计的一个典型问题是specs表必须将值存储为text(或varchar)列并处理类型转换的问题。但大多数现代数据库都支持动态列类型,如HSTORE或JSON,可用于存储实际值。

缺点是在查询时必须使用特殊的SQL语法:

Spec.where("payload->>'value' = ?", "foo")

这是所谓的Entity–attribute–value model的一种归一化变体,它可以是反模式,但通常是关系数据库中动态属性的唯一良好解决方案。

请参阅:

答案 1 :(得分:0)

解决避免EAV表问题的另一种解决方法是使用多表继承。此示例使用ActiveRecord :: ActsAs。

class Product < ActiveRecord::Base
  actable
  belongs_to :brand
  validates_numericality_of :universal_product_code, length: 12
  validates_presence_of :model_name, :price
end

class Bicycle < ActiveRecord::Base
  acts_as :product
  validates_numericality_of :gears
  validates_presence_of :size
end 

class PowerTool < ActiveRecord::Base
  acts_as :product
  validates_numericality_of :voltage, :amps
  validates_presence_of :voltage, :amps
end 

这会将基本信息存储在products表中:

change_table :products do |t|
  t.decimal :price
  t.sting :model_name
  t.integer :universal_product_code, length: 12
  t.integer :actable_id
  t.string  :actable_type
end

它使用多态关联将产品的子类型存储在更具体的表中:

create_table :bicycles do |t|
  t.integer :gears
  t.integer :size
end

create_table :power_tools do |t|
  t.boolean :corded
  t.integer :amps
  t.integer :size
end

这里的优点是你有一个定义的模式而不是一堆松散的属性。 缺点是,如果您正在设计一个通用的网上商店,那么固定的架构不会削减它。