我得到了以下Cassandra模型:-
class Automobile(Model):
manufacturer = columns.Text(primary_key=True)
year = columns.Integer(index=True)
model = columns.Text(index=True)
price = columns.Decimal(index=True)
我需要以下查询:-
q = Automobile.objects.filter(manufacturer='Tesla')
q = Automobile.objects.filter(year='something')
q = Automobile.objects.filter(model='something')
q = Automobile.objects.filter(price='something')
这些都很好用,直到我想要多栏过滤(当我尝试时)
q = Automobile.objects.filter(manufacturer='Tesla',year='2013')
它抛出一个错误,说Cannot execute this query as it might involve data filtering and thus may have unpredictable performance.
我用allowed_filtering
重写了查询,但这不是最佳解决方案。
然后在阅读更多后,我编辑了我的模型如下:-
class Automobile(Model):
manufacturer = columns.Text(primary_key=True)
year = columns.Integer(primary_key=True)
model = columns.Text(primary_key=True)
price = columns.Decimal()
有了这个,我也可以在没有任何警告的情况下过滤多个库仑。
当我执行DESCRIBE TABLE automobile
时,它显示这将创建复合密钥PRIMARY KEY ((manufacturer), year, model)
。
所以,我的问题是,如果我将每个属性都声明为主键会怎样这有什么问题吗,因为我也可以过滤多个列。
这只是一个小模型。如果我有一个模型,比如:-
class UserProfile(Model):
id = columns.UUID(primary_key=True, default=uuid.uuid4)
model = columns.Text()
msisdn = columns.Text(index=True)
gender = columns.Text(index=True)
imei1 = columns.Set(columns.Text)
circle = columns.Text(index=True)
epoch = columns.DateTime(index=True)
cellid = columns.Text(index=True)
lacid = columns.Text(index=True)
mcc = columns.Text(index=True)
mnc = columns.Text(index=True)
installed_apps = columns.Set(columns.Text)
otp = columns.Text(index=True)
regtype = columns.Text(index=True)
ctype = columns.Text(index=True)
operator = columns.Text(index=True)
dob = columns.DateTime(index=True)
jsonver = columns.Text(index=True)
如果我把每个属性都声明为PK,这有问题吗?
在前面的例子中,您可以这样做
where a = a1 and b > b1
where a = a1 and b=b1 and c>c1
where a = a1 and b=b1 and c=c1 and d > d1
但不能这样做:
where a=a1 and c=c1
要做到这一点,你需要"允许过滤"(实际上,你应该考虑改变你的模型,或者在这一点上取消规范化)。
现在,谈谈你关于让每一个专栏都成为PK的一部分的问题。你可以这样做,但请记住,《卡桑德拉》中的所有文章都是混乱的。行由其主键标识。如果将每列都作为PK的一部分,则无法编辑一行。不允许更新主键中任何列的值。
解决此问题的正确方法是采用基于查询的建模方法。您应该使用四个(可能是三个)表和ZERO辅助索引来解决此问题,而不是使用一个具有三个辅助索引的表。
你的Automobile
原始表可能还可以。尽管我很想看看你的主键定义。但是,为了解决您对Automobile.objects.filter(year='something')
的查询,我会创建一个额外的查询表,如下所示(注意:在CQL中定义):
CREATE TABLE automobileByYear (
manufacturer text,
year bigint,
model text,
price decimal,
PRIMARY KEY ((year),manufacturer,model));
假设您还在Python端为该模型(AutomobileByYear
)创建了一个相应的类,那么您就可以提供如下查询:
AutomobileByYear.objects.filter(year='2013')
此外,将manufacturer
作为您的第一个集群密钥也将允许此查询发挥作用:
AutomobileByYear.objects.filter(manufacturer='Tesla',year='2013')
同样,为了按模型解决您的查询,我将创建一个额外的查询表(automobileByModel
),其中表的PRIMARY KEY定义被重新排序如下:
PRIMARY KEY ((model),manufacturer,year));
集群键(manufacturer
和year
)的顺序会因查询需求而异,但关键是model
在这种情况下应该是您的分区键。
编辑
但应该这样,我应该根据我的查询设计我的表,从而有很多数据冗余。比方说,我有同样的汽车模型,有N个字段,其中N=10。如果我想按每个N字段进行筛选。我应该为每个不同的过滤器类型查询创建一个不同的模型吗。
在这个时代,磁盘比以前便宜得多。话虽如此,我明白在一个问题上扔更多的磁盘并不总是那么容易。我看到的更大的问题是调整应用程序的DAO层,使10个表保持同步。
在这种情况下,我建议集成像Elastic或Solr这样的搜索工具。事实上,Cassandra的企业版开箱即用地与Solr集成。如果你真的需要在10多列上运行查询,那么一个强大的搜索工具会很好地补充你的Cassandra集群。