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

Dex*_*spi 5 cassandra cassandra-2.0

我在Cassandra中相当n00b(我主要来自RDBMS背景,这里和那里都有一些NoSQL,例如Google的BigTable和MongoDB),并且我正在为自己想要满足的用例进行数据建模。我看了这个这个,甚至这个,但是它们并不是我所需要的。

我有这个基本表:

CREATE TABLE documents (
    itemid_version text,       
    xml_payload text,
    insert_time timestamp,
    PRIMARY KEY (itemid_version)
); 
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

CREATE TABLE document_versions (
    itemid uuid,
    version int,
    PRIMARY KEY (itemid, version)
) WITH clustering order by (version DESC);
Run Code Online (Sandbox Code Playgroud)

新记录将添加为新文档,并创建现有文档的新版本

现在我们有了这个(用例#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)
Run Code Online (Sandbox Code Playgroud)

这(用例#3):

$versions = csql("select version from document_versions where item_id = {0}" 
    -f $itemid)
Run Code Online (Sandbox Code Playgroud)

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

CREATE TABLE latest_documents (
    itemid uuid,
    version int,
    PRIMARY KEY (itemid, version)
)
Run Code Online (Sandbox Code Playgroud)

为新文档插入记录,为现有文档更新记录

现在我们有了这个:

$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))        
Run Code Online (Sandbox Code Playgroud)

现在,我希望这是很清楚,为什么我连接起来itemid,并version为创建一个索引documents,而不是创造一个复合键:我不能有ORWHERE条款SELECT

您可以假设只有一个进程会执行插入/更新操作,因此您不必担心一致性或隔离性问题。

我在正确的轨道上吗?有很多事情对我来说并不好...但是主要是因为我还不了解Cassandra:

  • 我觉得它的主键documents应该是(itemid,version)的组合,但我不能满足用例#4(从查询返回列表)...我可能无法为每个使用单独的SELECT语句由于性能下降(网络开销)而产生的文档...或者(应该)可以吗?
  • 如果版本未知,则需要2次以获取文档。可能是我必须忍受的妥协,或者也许有更好的方法。

reg*_*win 5

这将如何工作德克斯特?

它实际上与您的解决方案非常相似,除了您可以存储所有版本并能够仅从一张表(document_versions)中获取“最新”版本。

在大多数情况下,我认为您可以在单个 SELECT 中获得您想要的内容,除了用例 #2,其中获取文档的最新版本,其中首先需要在 document_versions 上进行预 SELECT。

第二次尝试

(我从第一次尝试中删除了代码,向在评论中关注的任何人道歉)。

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);
Run Code Online (Sandbox Code Playgroud)
  1. 用户需要获得他想要的单个 (1) 文档,他知道项目 ID 和版本(不一定是最新的)

    SELECT * FROM 文档 WHERE itemid_version = 'doc1-2';

  2. 用户需要获得他想要的单个 (1) 文档,他知道项目 ID 但不知道最新版本(您会将第一个查询的结果中的串联 itemid + 版本提供给第二个查询)

    SELECT * FROM document_versions WHERE itemid = 'doc2' LIMIT 1;

    SELECT * FROM 文档 WHERE itemid_version = 'doc2-2';

  3. 用户需要单个 (1) 文档的版本历史记录。

    SELECT * FROM document_versions WHERE itemid = 'doc2';

  4. 用户需要获取他想要的文档列表(1 个或多个),他知道项目 ID 和版本(不一定是最新的)

    SELECT * FROM 文档 WHERE itemid_version IN ('doc1-2', 'doc2-1');

干杯,


Igo*_*aya 5

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

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);
Run Code Online (Sandbox Code Playgroud)
  • 用例 1:用户需要获取单个 (1) 文档,用户知道项目 ID 和版本(不一定是最新的)

    SELECT * FROM document_versions 
      WHERE itemid = ? and version = ?;
    
    Run Code Online (Sandbox Code Playgroud)
  • 用例 2:用户需要获取单个 (1) 文档,用户知道项目 id 但不知道最新版本

    SELECT * FROM document_versions
      WHERE itemid = ? limit 1;
    
    Run Code Online (Sandbox Code Playgroud)
  • 用例 3:用户需要单个 (1) 文档的版本历史记录

    SELECT * FROM document_versions 
      WHERE itemid = ?
    
    Run Code Online (Sandbox Code Playgroud)
  • 用例 4:用户需要获取文档列表(1 个或多个),用户知道项目 ID 和版本(不一定是最新的)

    SELECT * FROM documents 
      WHERE itemid = 'doc1' and version IN ('1', '2');
     ```
    
    
    Run Code Online (Sandbox Code Playgroud)

所有这些查询的一张表是正确的方法。

我建议参加 Datastax 免费在线课程:DS220 数据建模