MySQL数据模型对Cassandra的帮助?

时间:2011-08-18 16:45:56

标签: data-modeling cassandra

我正在尝试将RDBMS模型移交给Cassandra,并且很难创建模式。这是我的数据模型:

CREATE TABLE Domain (
    ID INT NOT NULL PRIMARY KEY,
    DomainName NVARCHAR(74) NOT NULL,
    HasBadWords BIT,
    ...
);
INSERT INTO Domain (DomainName, HasBadWords) VALUES ('domain1.com', 0);
INSERT INTO Domain (DomainName, HasBadWords) VALUES ('domain2.com', 0);

CREATE TABLE ZoneFile (
    ID INT NOT NULL PRIMARY KEY,
    DomainID INT NOT NULL,
    Available BIT NOT NULL,
    Nameservers NVARCHAR(MAX),
    Timestamp DATETIME NOT NULL
);
INSERT INTO ZoneFile (DomainID, Available, Nameservers, Timestamp) VALUES (1, 0, "ns1", '2010-01-01');
INSERT INTO ZoneFile (DomainID, Available, Nameservers, Timestamp) VALUES (2, 0, "ns1", '2010-01-01');
INSERT INTO ZoneFile (DomainID, Available, Nameservers, Timestamp) VALUES (1, 1, "ns2", '2011-01-01');
INSERT INTO ZoneFile (DomainID, Available, Nameservers, Timestamp) VALUES (2, 1, "ns2", '2011-01-01');

CREATE TABLE Backlinks (
    ID INT NOT NULL PRIMARY KEY,
    DomainID INT NOT NULL,
    Backlinks INT NOT NULL,
    Indexed INT NOT NULL,
    Timestamp DATETIME NOT NULL
);
INSERT INTO Backlinks (DomainID, Backlinks, Indexed, Timestamp) VALUES (1, 100, 200, '2010-01-01');
INSERT INTO Backlinks (DomainID, Backlinks, Indexed, Timestamp) VALUES (2, 300, 600, '2010-01-01');
INSERT INTO Backlinks (DomainID, Backlinks, Indexed, Timestamp) VALUES (1, 500, 1000, '2010-01-01');
INSERT INTO Backlinks (DomainID, Backlinks, Indexed, Timestamp) VALUES (2, 600, 1200, '2010-01-01');

由此,我推断出我可能有一个Keyspace:DomainData。在这个密钥空间中,我可以有一个名为“Domain”的列家族,就像我在sql中的Domain表一样:

"Domain" : { //ColumnFamily
    "domain1.com" : { "HasBadWords" : 0 }, //SuperColumn
    "domain2.com" : { "HasBadWords" : 0 }  //SuperColumn
}

接下来的表格让我感到困惑。 ZoneFile和Backlinks本质上应该存储查找每个域的这些值的结果历史记录。因此,一个域到多个ZoneFile记录。出于查询目的,我希望能够轻松获得“最新”的ZoneFile记录或给定的域。我需要对Backlinks做同样的事情。

我正在考虑这样的事情,并对域的密钥进行范围查找,然后获取应该是最新时间戳的“最后”记录...

"ZoneFiles" : { //ColumnFamily
    "domain1.com:2010-01-01 12:00:00.000" : { "Available" : 0, "Nameservers" : "ns1" }, //SuperColumn
    "domain1.com:2011-01-01 12:00:00.000" : { "Available" : 1, "Nameservers" : "ns2" }, //SuperColumn
    "domain2.com:2010-01-01 12:00:00.000" : { "Available" : 0, "Nameservers" : "ns1" }, //SuperColumn
    "domain2.com:2011-01-01 12:00:00.000" : { "Available" : 1, "Nameservers" : "ns2" }  //SuperColumn
}

我不相信这是正确的答案,键中字符串域和字符串日期时间的组合感觉不对。有人能指出我正确的方向吗?

修改

假设我使用:

"ZoneFiles" : {
  "domain1.com" : {
    timestamp1 : "{\"available\":1,\"nameservers\":\"ns1\"}",
    timestamp2 : "{\"available\":1,\"nameservers\":\"ns1\"}",
  }
}

如何查询最新时间戳早于给定日期的域行列表?

1 个答案:

答案 0 :(得分:4)

如果我正确理解您的问题,您想要对此模型进行的唯一查询是“请为我提供给定域名的最新区域文件或反向链接”?

如果是这种情况,我会在域“行”键下的“域”列系列中将这些值的最新值存储在单独的列中。我还会在更新此最新值时存储(时间戳)。每次在zonefile和反向链接中获取信息的新值时,我只会覆盖“域”列族中的值并更新时间戳。

我假设您也保留了这些历史数据,以便您可以查询它,并且我假设查询类型将“在两次之间向我显示给定域的所有更新”(这是正确的吗?)。如果是这样,我不会手动构造这样的复合行键,因为它将要求您使用Order Preserving Partitioner从get_range_slices获取正确的结果。正如您可能知道的那样,使用OPP进行负载平衡可能是一项艰巨的任务。

相反,我会将行键设为域ID,列键是更新的时间戳。然后,您可以将更新打包到单个值(例如,使用json),使用超级列或使用0.8中的新复合键。如果像这样完成,您可以使用get_slice来满足您的查询,并且它将与Random Partitioner一起正常运行,从而使负载平衡变得更加容易。

汤姆威尔基| Acunu | www.acunu.com | @tom_wilkie

回复评论:“我如何查询最近的zonefile时间戳列早于给定时间戳的域列表?”

您可以通过插入另一个列系列来实现:

row key: day (or hour, or some other reasonable 'bucketing') 
column key: timestamp of update 
value: domain

...每次更新zonefile时。然后,要从t获取最近更新的域,请执行:

result = []
for i in day(t) ... day(now):
    result.extend(get_slice(i, range(t, '')))

这将要求您从结果中删除重复条目,因此只有在t很近时才会起作用。您还必须考虑写入的负载平衡,这会将所有负载集中在单个服务器上(因为,在任何时候,您只插入一行)

如果这些权衡不合适,那么您可以查看hadoop集成并使用它来执行此查询。或者您可以进行其他权衡(使用OPP,或者在写入之前执行读取以删除重复项,这将是v。慢)