使用CQL3在Cassandra中进行数据版本控制

zaq34kh6  于 2023-06-29  发布在  Cassandra
关注(0)|答案(2)|浏览(135)

我正在努力为我试图满足的用例进行数据建模。我看了thisthis,甚至这个,但它们并不是我所需要的。
我有一个基本的表格:

CREATE TABLE documents (
    itemid_version text,       
    xml_payload text,
    insert_time timestamp,
    PRIMARY KEY (itemid_version)
);

itemid实际上是一个UUID(对所有文档都是唯一的),version是一个int(版本0是“第一个”版本)。xml_payload是完整的XML文档,可能会非常大。是的,我基本上是在创建一个版本化的文档存储。
正如你所看到的,我将这两个连接起来创建一个主键,我将在后面解释需求和/或用例时解释为什么这样做:

  • 用例1:用户需要获取单个(1)文档,用户知道项目ID和版本(不一定是最新版本)
  • 用例2:用户需要获取单个(1)文档,用户知道项目ID,但不知道最新版本
  • 用例3:用户需要单个(1)文档的版本历史
  • 用例4:用户需要获取文档列表(1个或多个),用户知道项目ID和版本(不一定是最新版本)

我将编写执行用例的客户端代码,请原谅语法,因为我试图成为语言无关的。
第一个很简单

$itemid_version = concat($itemid, $version)
$doc = csql("select * from documents where itemid_version = {0};" 
    -f $itemid_version)

现在,为了满足第二和第三个用例,我添加了下表:

CREATE TABLE document_versions (
    itemid uuid,
    version int,
    PRIMARY KEY (itemid, version)
) WITH clustering order by (version DESC);

将在创建新文档和现有文档的新版本时添加新记录。
现在我们有这个(用例#2):

$latest_itemid, $latest_version = csql("select itemid, 
    version from document_versions where item_id = {0} 
    order by version DESC limit 1;" -f $itemid)
$itemid_version = concat($latest_itemid, $latest_version)
$doc = csql("select * from documents where itemid_version = {0};" 
    -f $itemid_version)

这个(用例#3):

$versions = csql("select version from document_versions where item_id = {0}" 
    -f $itemid)

对于第三个要求,我添加了另一个表:

CREATE TABLE latest_documents (
    itemid uuid,
    version int,
    PRIMARY KEY (itemid, version)
)

为新文档插入记录,为现有文档更新记录。
现在我们有了这个

$latest_itemids, $latest_versions = csql("select itemid, version 
    from latest_documents where item_id in ({0})" -f $itemid_list.toCSV())

foreach ($one_itemid in $latest_itemids, $one_version in $latest_versions)
    $itemid_version = concat($latest_itemid, $latest_version)
    $latest_docs.append(
        cql("select * from documents where itemid_version = {0};" 
        -f $itemid_version))

现在,我希望清楚为什么我将itemidversion连接起来为documents创建索引,而不是创建复合键:在SELECTWHERE子句中不能有OR
您可以假设只有一个进程执行插入/更新,因此不需要担心一致性或隔离问题。
我的思路对吗?有很多事情让我不舒服......但主要是因为我还不了解Cassandra:

  • 我觉得documents的主键应该是(itemid,version)的组合,但是我不能满足用例#4(从查询返回一个列表)......由于性能问题(网络开销),我不可能对每个文档使用单独的SELECT语句......或者我可以(应该)吗?
  • 如果事先不知道文件的版本,则需要两次往返才能获得文件。这可能是我必须接受的妥协,除非有更好的办法。
f0brbegy

f0brbegy1#

让我们看看我们是否可以从您的查询开始以自顶向下的方式提出一个模型:

CREATE TABLE document_versions (
  itemid uuid,
  name text STATIC,
  version int,   
  xml_payload text,
  insert_time timestamp,
  PRIMARY KEY ((itemid), version)
) WITH CLUSTERING ORDER BY (version DESC);
  • 用例1:用户需要获取单个(1)文档,用户知道项目ID和版本(不一定是最新版本)
SELECT * FROM document_versions 
  WHERE itemid = ? and version = ?;
  • 用例2:用户需要获取单个(1)文档,用户知道项目ID,但不知道最新版本
SELECT * FROM document_versions
  WHERE itemid = ? limit 1;
  • 用例3:用户需要单个(1)文档的版本历史
SELECT * FROM document_versions 
  WHERE itemid = ?
  • 用例4:用户需要获取文档列表(1个或多个),用户知道项目ID和版本(不一定是最新版本)
SELECT * FROM documents 
  WHERE itemid = 'doc1' and version IN ('1', '2');

用一个表来处理所有这些查询是正确的方法。
我建议参加Datastax免费在线课程:[DS220 Data Modeling](https://academy.datastax.com/resources/ds220-data-modeling)
huus2vyu

huus2vyu2#

这实际上与您的解决方案非常相似,除了您可以存储所有版本并能够从一个表(document_versions)中获取“最新”版本。
在大多数情况下,我认为你可以在一个SELECT中得到你想要的,除了用例2,它需要获取文档的最新版本,其中SELECT首先需要在document_versions上。

CREATE TABLE documents (
        itemid_version text,
        xml_payload text,
        insert_time timestamp,
        PRIMARY KEY (itemid_version)
);

CREATE TABLE document_versions (
        itemid text,
        version int,
        PRIMARY KEY (itemid, version)
) WITH CLUSTERING ORDER BY (version DESC);

INSERT INTO documents (itemid_version, xml_payload, insert_time) VALUES ('doc1-1', '<?xml>1st</xml>', '2014-05-21 18:00:00');
INSERT INTO documents (itemid_version, xml_payload, insert_time) VALUES ('doc1-2', '<?xml>2nd</xml>', '2014-05-21 18:00:00');
INSERT INTO documents (itemid_version, xml_payload, insert_time) VALUES ('doc2-1', '<?xml>1st</xml>', '2014-05-21 18:00:00');
INSERT INTO documents (itemid_version, xml_payload, insert_time) VALUES ('doc2-2', '<?xml>2nd</xml>', '2014-05-21 18:00:00');

INSERT INTO document_versions (itemid, version) VALUES ('doc1', 1);
INSERT INTO document_versions (itemid, version) VALUES ('doc1', 2);
INSERT INTO document_versions (itemid, version) VALUES ('doc2', 1);
INSERT INTO document_versions (itemid, version) VALUES ('doc2', 2);
  • 用例1:用户需要获取单个(1)文档,用户知道项目ID和版本(不一定是最新版本)
SELECT * FROM documents WHERE itemid_version = 'doc1-2';
  • 用例2:用户需要获取单个(1)文档,用户知道项目ID,但不知道最新版本(您需要将第一个查询结果中的串联itemid + version馈送到第二个查询中)
SELECT * FROM document_versions WHERE itemid = 'doc2' LIMIT 1;

SELECT * FROM documents WHERE itemid_version = 'doc2-2';
  • 用例3:用户需要单个(1)文档的版本历史
SELECT * FROM document_versions WHERE itemid = 'doc2';
  • 用例3:用户需要获取文档列表(1个或多个),用户知道项目ID和版本(不一定是最新版本)
SELECT * FROM documents WHERE itemid_version IN ('doc1-2', 'doc2-1');

相关问题