4

我在 Cassandra 中对来自 RDBMS 的数据库进行建模。我想知道如何创建嵌入在同一列名中的一对多关系并对我的表进行建模以适应以下查询需求。

例如:

Boxes:{
  23442:{
    belongs_to_user: user1,
    box_title: 'the box title',
    items:{
      1: {
         name: 'itemname1',
         size: 44
      },
      2: {
        name: 'itemname2',
        size: 24
      }
    }
  },

 { ... }
}

我读到最好使用复合列而不是超级列,所以我需要一个实现这一点的最佳方法的示例。我的查询是这样的:

  • 按 Id 获取框的项目
  • 获得前 20 个盒子及其项目(用于在页面上显示一系列盒子及其项目)
  • 按项目 id 更新项目大小(按数字增加大小)
  • 通过用户 ID 获取所有框(属于特定用户的所有框)

我期待大量的写入来改变盒子中每个项目的大小。我想知道在不需要使用超级列的情况下实现它的最佳方法。此外,我不介意得到一个考虑到 Cassandra 1.2 新特性的解决方案,因为我将在生产中使用它。

谢谢

4

3 回答 3

2

由于多种原因,这个特定的模型有些挑战性。

例如,使用框 ID 作为行键,查询框的范围将需要在 Cassandra 中进行范围查询(而不是列切片),这意味着使用有序分区器。有序分区器几乎总是一个坏主意

另一个挑战来自需要增加项目大小,因为这需要使用计数器列族。计数器列族存储计数器值。

暂时不考虑对一系列框 ID 的需求,您可以使用 CQL3 中的多个表对此进行建模,如下所示:

CREATE TABLE boxes (                                                                       
   id int PRIMARY KEY,                                                                 
   belongs_to_user text,                                                               
   box_title text,                                                                     
);
CREATE INDEX useridx on boxes (belongs_to_user);

CREATE TABLE box_items (                                                                   
   id int,                                                                             
   item int,                                                                           
   size counter,                                                                       
   PRIMARY KEY(id, item)                                                               
);

CREATE TABLE box_item_names (
    id int PRIMARY KEY,
    item int,
    name text
);

BEGIN BATCH
  INSERT INTO boxes (id, belongs_to_user, box_title) VALUES (23442, 'user1', 'the box title');
  INSERT INTO box_items (id, item, name) VALUES (23442, 1, 'itemname1');
  INSERT INTO box_items (id, item, name) VALUES (23442, 1, 'itemname2');
  UPDATE box_items SET size = size + 44 WHERE id = 23442 AND item = 1;                       
  UPDATE box_items SET size = size + 24 WHERE id = 23442 AND item = 2;
APPLY BATCH

-- Get items for box by ID                                                               
SELECT size FROM box_items WHERE id = 23442 AND item = 1;

-- Boxes by user ID
SELECT * FROM boxes WHERE belongs_to_user = 'user1';

需要注意的是,上面的 BATCH 突变既是原子的,又是孤立的。

从技术上讲,您还可以将所有这些非规范化到一个表中。例如:

CREATE TABLE boxes (
   id int,
   belongs_to_user text,
   box_title text,
   item int,
   name text,
   size counter,
   PRIMARY KEY(id, item, belongs_to_user, box_title, name)
);

UPDATE boxes set size = item_size + 44 WHERE id = 23442 AND belongs_to_user = 'user1'
    AND box_title = 'the box title' AND name = 'itemname1' AND item = 1;

SELECT item, name, size FROM boxes WHERE id = 23442;

但是,这不能保证正确性。例如,这个模型使得同一个盒子的项目可以有不同的用户或标题。而且,由于这构成boxes了一个计数器列族,它限制了您将来如何发展模式。

于 2012-10-29T12:34:51.900 回答
0

我认为首先在 PlayOrm 的对象中,然后在下面显示列模型....

Box {
   @NoSqlId
   String id;
   @NoSqlEmbedded
   List<Item> items;
}

User {
   @NoSqlId
   TimeUUID uuid;
   @OneToMany
   List<Box> boxes;
}

然后用户是这样的一行

rowkey = uuid=<someuuid> boxes.fkToBox35 = null, boxes.fktoBox37=null, boxes.fkToBox38=null

请注意,上面的形式是 columname=value,其中一些列名是复合的,而有些则不是。

盒子更有趣,说 Item 有字段 name 和 idnumber,那么 box row 将是

rowkey = id=myid, items.item23.name=playdo, items.item23.idnumber=5634, itesm.item56.name=pencil, items.item56.idnumber=7894

我不确定你在获得前 20 个盒子是什么意思?顶框是指其中的项目数量?

院长

于 2012-10-29T11:34:51.600 回答
0

您可以使用Query-Driven Methodology进行数据建模。您拥有三种广泛的访问路径:
1)每个查询的
分区 2)每个查询的分区+(一个或多个分区)
3)表或表+每个查询

最有效的选项是“<strong>partition per query”。在这种情况下,本文可以逐步为您提供帮助。它的样本正是一对多的关系

根据这个,你将有几个表有一些相似的列。您可以通过物化视图或批处理日志(作为替代方法)来管理它。

于 2016-03-01T05:50:07.497 回答