代码之家  ›  专栏  ›  技术社区  ›  Duc Nguyen

在Cassandra中的类型文本字段上组合相等和较小条件

  •  1
  • Duc Nguyen  · 技术社区  · 6 年前

    我使用Cassandra存储数据,我想对其使用EQUAL和NOT EQUALS查询。EQUAL(=)操作符工作正常。对于不等于运算符,我将<和>字段上的运算符(我使用SASI索引在每个字段上创建了自定义二级索引)。我使用SASI索引来支持
    但是,当我将运算符=和<组合在一起时;在查询中,Cassandra拒绝它(结果没有行)。您可以看到下面的示例查询,这更容易理解。 这是一个示例表:

    CREATE TABLE test (
        id uuid,
        a int,
        b int,
        c varchar,
        d varchar,
        timestamp bigint,
        PRIMARY KEY (id)
    );
    

    以下查询不返回任何内容:

    SELECT * FROM test WHERE a = 1 AND c < '2' ALLOW FILTERING;
    

    以下查询返回正确的结果:

    SELECT * FROM test WHERE a > 1 AND c = '2' ALLOW FILTERING;
    SELECT * FROM test WHERE c > '2' AND d < '2' ALLOW FILTERING;
    

    另外,我想按时间戳订购。 有人能解释为什么卡桑德拉会这样做吗?如何设计数据库以支持任何组合? 谢谢你的帮助。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Aaron    6 年前

    我以前说过,现在我再说一遍:

    ALLOW FILTERING is bad, bad, bad!

    二级索引也是如此。

    任何时候,如果您不筛选 WHERE 子句,则运行所谓的“多键查询”这是一种已知的反模式,因为它不能将自身限制为一个分区,因此查询需要引用多个节点才能完成。这是一种 不会缩放 ,因此使用 分布式 数据库

    在Cassandra中,您需要采用基于查询的建模方法。据我所知,你 id 定义为单独的主键,但不是通过它进行查询。主键定义应该真正反映希望表提供服务的查询类型。

    如果这是您要运行的查询,那么您的表定义将需要反映:

    CREATE TABLE test_by_a_and_c (
        id uuid,
        a int,
        b int,
        c varchar,
        d varchar,
        timestamp bigint,
        PRIMARY KEY (a,c,timestamp,id));
    

    这将按以下方式对数据进行分区 a ,并按 c , timestamp 身份证件 . 使用 c 因为您的第一个集群键将允许您的查询工作。使用 时间戳 因为第二个聚类键将允许您的结果按时间戳排序。 身份证件 在末端添加,以确保唯一性,这可能是必要的,也可能不是必要的。此定义将允许此查询工作:

    SELECT * FROM test_by_a_and_c WHERE a = 1 AND c < '2';
    

    对于第二个查询,您需要创建 包含相同数据的表,并相应调整主键定义:

        CREATE TABLE test_by_c_and_a (
        id uuid,
        a int,
        b int,
        c varchar,
        d varchar,
        timestamp bigint,
        PRIMARY KEY (c,a,timestamp,id));
    

    此定义将按以下方式对数据进行分区 c ,然后使用 作为满足所需查询的第一个群集键:

    SELECT * FROM test_by_c_and_a WHERE c = '2' AND a > 1;
    

    Cassandra保证分区存储在单个节点上。因此,通过使用一个好的分区键来限制您的模型,您基本上可以确保您的查询只需转到一个要解决的节点,从而大大减少了所需的网络时间。

    另外,我想按时间戳订购。有人能解释为什么卡桑德拉 这样的行为?

    Cassandra只能在分区键内强制执行排序顺序。群集顺序本质上是数据写入磁盘的方式。如果未在中指定分区键 哪里 子句,或者当查询可能包含多个键时,数据在读取时返回。首先,它将按照分区键的哈希标记值进行排序。然后,它将通过集群键,相对于当前分区键。

    例如,让我以您的第一个查询表为例 INSERT 一些随机数据。如果我在没有 哪里 子句中,您可以看到分区键的哈希标记值是如何发挥作用的:

    cassdba@cqlsh:stackoverflow>通过\u a\u和\u c从test\u中选择令牌(a)、a、b、c、d、timestamp;

     system.token(a)      | a | b | c | d | timestamp
    ----------------------+---+---+---+---+---------------------
     -4069959284402364209 | 1 | 2 | 7 | 2 | 2017-12-14 16:33:55
     -4069959284402364209 | 1 | 1 | 8 | 1 | 2017-12-14 16:33:55
     -3248873570005575792 | 2 | 2 | 3 | 2 | 2017-12-14 16:33:55
     -3248873570005575792 | 2 | 1 | 9 | 1 | 2017-12-14 16:33:55
     -2729420104000364805 | 4 | 1 | 6 | 1 | 2017-12-14 16:33:56
     -2729420104000364805 | 4 | 2 | 7 | 2 | 2017-12-14 16:33:57
      9010454139840013625 | 3 | 2 | 4 | 2 | 2017-12-14 16:33:56
      9010454139840013625 | 3 | 1 | 5 | 1 | 2017-12-14 16:33:56
    
    (8 rows)
    

    请注意,分区键的值 因其标记,按1、2、4、3顺序返回。此外 时间戳 仅与每个 .

    如何设计数据库以支持任何组合?

    你不能。对于Cassandra,您的查询 必须 提前知道。 那么您的表必须设计为服务于这些查询。如果需要更动态的查询模型,则需要使用更适合该模型的数据存储。