gpt4 book ai didi

cassandra - Cassandra 中版本化层次结构的高效建模

转载 作者:行者123 更新时间:2023-12-03 06:39:59 25 4
gpt4 key购买 nike

免责声明:
这是一个很长的帖子。我首先解释我正在处理的数据,以及我想用它做什么。
然后我详细说明了我考虑过的三种可能的解决方案,因为我已经尝试做我的功课(我发誓:])。我最终得到了一个“最佳猜测”,这是第一个解决方案的变体。

我的终极问题是:使用 Cassandra 解决我的问题的最明智的方法是什么?这是我的尝试之一,还是别的什么?
我正在寻找经验丰富的 Cassandra 用户的建议/反馈...

我的资料:
我有许多 super 文档,它们以树状结构(标题、副标题、部分……)拥有文档。

每个 SuperDocument 结构都可以随着时间的推移而改变(主要是标题的重命名),从而为我提供了多个版本的结构,如下所示。

superdocument versions

我在找什么:
对于每个 SuperDocument,我需要按上述日期为这些结构加上时间戳,并且我希望在给定日期内找到最接近的 SuperDocument 结构的早期版本。 (即 version_date < given_date 的最新版本)

这些注意事项可能有助于更轻松地解决问题:

  • 版本是不可变的:更改很少见,每次更改时我都可以创建整个结构的新表示。
  • 我不需要访问结构的子树。
  • 我认为可以说我不需要找到给定叶子的所有祖先,也不需要访问树内的特定节点/叶子。一旦我拥有整个树,我就可以在我的客户端代码中解决所有这些问题。

  • 好的,我们开始吧
    请记住,我真的才刚刚开始使用 Cassandra。我已经阅读/观看了大量有关数据建模的资源,但在该领域没有太多(任何!)经验!
    这也意味着一切都将用 CQL3 编写......对不起,节俭爱好者!

    我第一次尝试解决这个问题是创建下表:
    CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    pre_pos int,
    post_pos int,
    title text,

    PRIMARY KEY ((doc_id, version_date), pre_pos, post_pos)

    ) WITH CLUSTERING ORDER BY (pre_pos ASC);

    这会给我以下结构:

    enter image description here

    我正在使用 Nested Sets model为我这里的树;我认为保持结构有序会很好,但我愿意接受其他建议。

    我喜欢这个解决方案:每个版本都有自己的行,其中每一列代表层次结构的一个级别。
    但问题是我(坦率地)打算按如下方式查询我的数据:
    SELECT * FROM superdoc_structures 
    WHERE doc_id="3399c35...14e1" AND version_date < '2014-03-11' LIMIT 1

    Cassandra 很快提醒我,我不允许这样做! (因为partitioner不保留集群节点上的行序,所以无法通过partition key进行扫描)

    然后怎样呢...?
    好吧,因为 Cassandra 不允许我在分区键上使用不等式,所以就这样吧!
    我会做 version_date一个聚类键,我所有的问题都会消失。是的,不是真的...

    第一次尝试:
    CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    pre_pos int,
    post_pos int,
    title text,

    PRIMARY KEY (doc_id, version_date, pre_pos, post_pos)

    ) WITH CLUSTERING ORDER BY (version_date DESC, pre_pos ASC);

    我觉得这个不太优雅:所有版本 结构级别被制成现在非常宽的行的列(与我之前的解决方案相比):

    second modeling attempt

    问题:同样的请求,使用 LIMIT 1只会返回第一个标题。并且不使用 LIMIT将返回所有版本结构级别,我必须对其进行过滤以仅保留最新版本。

    第二次尝试:

    没有第二次尝试...虽然我有一个想法,但我觉得它没有明智地使用 Cassandra。

    这个想法是通过 version_date 进行聚类只有,并以某种方式将整个层次结构存储在每列值中。听起来很糟糕是不是?

    我会做这样的事情:
    CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    nested_sets map<int, int>,
    titles list<text>,

    PRIMARY KEY (doc_id, version_date)

    ) WITH CLUSTERING ORDER BY (version_date DESC);

    生成的行结构将是:

    third modeling attempt

    事实上,对我来说看起来没什么问题,但我可能会有比级别标题更多的数据来非规范化到我的列中。如果它只有两个属性,我可以使用另一个映射(例如将标题与 id 相关联),但是更多的数据会导致更多的列表,我觉得它很快就会成为一种反模式。
    另外,当数据进来时,我必须在我的客户端应用程序中将所有列表合并在一起!

    替代和最佳猜测
    仔细考虑之后,有一个“混合”解决方案可能有效并且可能高效且优雅:

    我可以使用另一个表,它只列出 SuperDocument 的版本日期并将这些日期缓存到 Memcache 实例(或 Redis 或其他)中,以便真正快速访问。
    这将使我能够快速找到我需要获取的版本,然后使用我的第一个解决方案的组合键请求它。

    那是两个查询,加上要管理的内存缓存存储。但无论如何我最终可能会得到一个,所以也许这会是最好的妥协?
    也许我什至不需要缓存存储?

    总而言之,我真的觉得第一个解决方案是对我的数据建模的最优雅的解决方案。你呢?!

    最佳答案

    首先,您不需要使用 memcache 或 redis。 Cassandra 将使您能够非常快速地访问该信息。您当然可以拥有一张类似于以下内容的表:

    create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    /* stuff */
    primary key (doc_id, version_date)
    } with clustering order by (version_date desc);

    这将为您提供一种快速访问给定版本的方法(此查询可能看起来很熟悉 ;-):
    select * from superdoc_structures 
    where doc_id="3399c35...14e1" and
    version_date < '2014-03-11'
    order by version_date desc
    limit 1;

    由于从模式的角度来看,文档树结构似乎没有任何相关性,而且每次有新版本时,您都乐于创建完整的文档,我不明白您为什么要这样做麻烦把树分解成单独的行。为什么不将表格中的整个文档作为文本或 blob 字段?
    create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    contents text;
    primary key (doc_id, version_date)
    } with clustering order by (version_date desc);

    因此,要获取新年时存在的文档内容,您需要执行以下操作:
    select contents from superdoc_structures
    where doc_id="...." and
    version_date < '2014-01-1'
    order by version_date > 1

    现在,如果您确实想要维护文档组件的某种层次结构,我建议您执行类似 closure table 的操作。表来表示它。或者,既然您愿意在每次写入时复制整个文档,为什么不在每次写入时复制整个部分信息,为什么不这样做并具有如下架构:
    create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    section_path varchar;
    contents text;
    primary key (doc_id, version_date, section_path)
    ) with clustering order by (version_date desc, section_path asc);

    然后让部分路径具有类似“first_level next_level sub_level Leaf_name”的语法。作为附带的好处,当您拥有文档的 version_date 时(或者如果您在 section_path 上创建二级索引),因为空格在词法上比任何其他有效字符“低”,您实际上可以非常干净地抓取一个小节:
    select section_path, contents from superdoc_structures
    where doc_id = '....' and
    version_date = '2013-12-22' and
    section_path >= 'chapter4 subsection2' and
    section_path < 'chapter4 subsection2!';

    或者,您可以使用 Cassandra 对集合的支持来存储这些部分,但同样......我不知道为什么你甚至会费心把它们分开,因为一大块就很好用。

    关于cassandra - Cassandra 中版本化层次结构的高效建模,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25449640/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com