【问题标题】:Getting all rows for a large grouping in CQL when the group's ID can change当组的 ID 可以更改时,在 CQL 中获取大型分组的所有行
【发布时间】:2016-07-06 12:24:34
【问题描述】:

例如,假设我想存储书籍以及它们在哪些图书馆中。我可以制作这样的表格:

create table book (
  id uuid,
  created timestamp,
  title text,
  library_id uuid,

  primary key (id)  
);

如果我想获取给定图书馆中所有书籍的列表,我可以制作如下的物化视图:

create materialized view book_per_library as
  select *
  from book
  where library_id is not null
  and id is not null
  primary key (library_id, id);

我认为该架构存在一些问题,我不确定如何解决这些问题。

问题1.一个节点的书太多,查询慢

为了使这个示例与我实际使用的数据等效,我可能在一个图书馆中拥有数十亿本书。如果我的分区键是 library_id(在表或物化视图中),我会最大化可以存储在具有该分区键的节点上的内容。我发现的一种可能的解决方案是根据创建的时间戳对数据进行分区,如下所示:

create table book (
  id uuid,
  created timestamp,
  title text,
  library_id uuid,
  date text,

  primary key (id, library_id)  
);

create materialized view book_per_library as
  select *
  from book
  where library_id is not null
  and date is not null
  and id is not null
  primary key ((library_id, date), id);

这是基于诸如https://academy.datastax.com/demos/getting-started-time-series-data-modeling 之类的读数,其中日期列类似于“2013-04-03”。然后我必须每天运行一个单独的查询。对于我的实际数据,我什至可能需要将其拆分为每小时,以便仍然允许单个节点存储所有数据。我的数据可以在短时间内(例如一小时)以非常大的爆发(例如数百万)添加。或者我的数据可以每隔一段时间逐个添加(例如一次一个或几个)。因此,它不是一个恒定的数据流。

无论如何,这里的查询不会是一个缓慢的过程吗?我可能不得不运行数千个查询来涵盖多年的跨度,只是为了获得那个图书馆中的书籍列表。另外,我怎么知道哪些日期实际有数据?

我想我基本上是想找到一种方法来避免必须使用类似 spark 的东西来阅读整个书桌,因为我不想阅读所有图书馆的行,只是我关心的那个。我还试图找到一种方法来避免对没有任何数据的日期运行查询,因为这似乎是在浪费时间。一个想法是找到一种方法让 cassandra 跟踪每个库的哪些日期有数据,这样我就知道要查询哪些分区键。也许有一个计数器表,我在其中存储每个日期值的书籍计数,例如“2013-04-03”。读取给定库的所有这些计数将是一个两步过程,然后仅对计数 > 0 的日期运行主查询。这是一个可行的解决方案吗?有更好的选择吗?

问题 2. 我必须能够将书籍移动到不同的图书馆,即我必须能够更改 library_id

作为一项要求,我必须能够将书籍移动到不同的图书馆。据我了解,这意味着我不能将 library_id 作为分区键列或集群列。如果我这样做了,那么将这本书“移动”到另一个图书馆需要我从当前图书馆删除它,然后将新记录添加到新图书馆。那准确吗?是否有更好的方法可以将表中的行与组相关联,同时也提供更改该分组的能力?

总体问题

在这种情况下,我想获取与某个“组 ID”(如 library_id)相关联的表的所有行,并且每个组可能有数十亿个行,我需要能够改变这种关联?

我打算使用 cassandra 3.x。

【问题讨论】:

    标签: database cassandra cql cql3


    【解决方案1】:

    恐怕 Cassandra 不是此类工作负载的最佳工具。事实上,Cassandra 非常擅长从一个分区中获取几行数据,即使是在一个巨大的数据集中,但同时获取数十亿行数据确实是一种反模式。


    但什么都没有丢失

    您的初始数据模型对我来说似乎是错误的。您建模了一个“库集合”,然后使用物化视图实现了一个查找表。我不知道这背后的原因,但如果你自己直接实现“物化”表,你最终会得到同样的结果:

    create table books_by_library_id (
      library_id int,
      book_id uuid,
      book_created timestamp,
      book_title text,
      book_date text,
    
      primary key (library_id, book_title)
    );
    

    现在,您的问题 1真实的。每个分区上的记录不应超过 10k 或 20k,因为查询该分区只会对一个节点造成压力。当前,您的分区仅包含 library_id 字段。您需要找到将数据拆分为多个分区的其他方法,然后通过多个查询取回数据,将数据重新组装到您的应用程序中。这将使您的集群能够轻松地承受数十亿行的提取,因为您将发出多个查询,每个查询都由不同的节点处理。基本上,您“手动”编排集群以获取您想要的内容。

    如何将数据拆分为多个分区?一种典型的方法是“存储”您的数据。在您的示例中,您可以轻松地将每个库“划分”为(至少)26 个存储桶,从 A 到 Z 每个字母一个:

    create table books_by_library_id_and_initials (
      library_id int,
      book_title_initials text,
      book_id uuid,
      book_created timestamp,
      book_title text,
      book_date text,
    
      primary key ((library_id, book_title_initials), book_title)
    );
    

    要获取属于library_id=2 的所有书籍,您需要发出 26 个查询:

    SELECT * FROM books_by_library_id_and_initials WHERE library_id=2 AND book_title_initials='a';
    SELECT * FROM books_by_library_id_and_initials WHERE library_id=2 AND book_title_initials='b';
    ...
    SELECT * FROM books_by_library_id_and_initials WHERE library_id=2 AND book_title_initials='z';
    

    此外,这仍然允许您直接通过以下方式获取书籍:

    SELECT * FROM books_by_library_id_and_initials 
    WHERE library_id=2 
      AND book_title_initials='c' 
      AND book_title = 'Cassandra from Zero to Hero';
    

    如果您担心将 50 亿行划分为 26 个桶还不够,您可以在分区键中添加另一个字母,最多 676 个桶(然后发出 676 个查询),或者另外两个字母,最多17576 个桶(然后发出 17576 个查询,唉!)。

    有了这些高数字,使用专用表跟踪特定存储桶中的书籍数量是有意义的。如果此表告诉您存储桶中没有书籍,则您不会发出查询。否则查询分区。

    CREATE TABLE my_counters (
      library_id int,
      book_title_initials text,
      books_count counter,
      PRIMARY KEY (library_id, book_title_initials)
    );
    
    SELECT counter FROM my_counters 
     WHERE library_id = 2 
       AND book_title_initials='cas';
    

    不过,我认为你不能走得更远。

    关于您的问题 2,您需要从一个图书馆中删除该书,然后在另一个图书馆中重新创建它。因为您无法更新主键的值,所以无法逃脱。

    HTH。

    【讨论】:

      【解决方案2】:

      您所描述的完全看起来像是在您的库表之上的索引数据库。我认为您可以充分利用 ElasticSearch 之类的东西。特别是如果您希望能够“即时”更改行关联规则 - 您将更改索引结构,但不会更改库数据。

      另外,DataStax Enterprise 有 Apache Solr support。但是,在您的情况下,这可能有点矫枉过正,因为您不需要全文搜索之类的东西。

      【讨论】:

        猜你喜欢
        • 2015-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-15
        • 2011-10-01
        • 2021-05-22
        • 2021-01-14
        • 2018-09-27
        相关资源
        最近更新 更多