Cassandra查询生成-无法执行此查询,因为它可能涉及数据筛选,因此可能具有不可预测的性能



我得到了以下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,这有问题吗?

要理解这一点,您需要了解cassandra是如何存储数据的。主键中的第一个键称为分区键。它定义了行所属的分区。分区中的所有行都存储在一起,并一起复制。在分区内部,行是根据集群键存储的。这些是PK中不是分区键的列。所以,如果你的PK是(a,b,c,d),a定义了分区。在一个特定的分区(比如说,a=a1)中,行按b排序。对于每个b,行按c排序。依此类推。查询时,您需要指定一个(或几个分区),然后需要指定每个连续的聚类键,直到找到您要查找的键。除了查询中指定的最后一个集群列(可能是范围查询)之外,这些列必须精确相等。

在前面的例子中,您可以这样做

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));

集群键(manufactureryear)的顺序会因查询需求而异,但关键是model在这种情况下应该是您的分区键。

编辑

但应该这样,我应该根据我的查询设计我的表,从而有很多数据冗余。比方说,我有同样的汽车模型,有N个字段,其中N=10。如果我想按每个N字段进行筛选。我应该为每个不同的过滤器类型查询创建一个不同的模型吗。

在这个时代,磁盘比以前便宜得多。话虽如此,我明白在一个问题上扔更多的磁盘并不总是那么容易。我看到的更大的问题是调整应用程序的DAO层,使10个表保持同步。

在这种情况下,我建议集成像Elastic或Solr这样的搜索工具。事实上,Cassandra的企业版开箱即用地与Solr集成。如果你真的需要在10多列上运行查询,那么一个强大的搜索工具会很好地补充你的Cassandra集群。

最新更新