Cassandra数据建模

时间:2015-02-09 14:46:43

标签: cassandra cql cassandra-2.0 cql3 datastax

因此,我正在为产品价格跟踪设计此数据模型。

许多用户可以关注产品,用户可以关注许多产品,因此它具有多对多的关系。 产品处于持续跟踪状态,但只有在与前一个产品不同的情况下才会插入新价格。

用户已为其关注产品设置了价格上限,因此每次价格变化时,都会检查首选项,并在价格低于其阈值时通知用户。

所以最初我想到了以下产品型号:

然而" subscriberEmails"是一个列表集合,最多可处理65536个元素。但作为一个大数据解决方案,它是我们不想拥有的边界。所以我们最终为此写了一个单独的表:

所以现在" usersByProduct"可以有多达20亿列,足够公平。并且用户偏好存储在" Map"这又是有限的,但我们认为这是用户遵循的最佳产品数量。

现在我们遇到的问题如下:

每当我们想要更新产品的价格时,我们都必须进行如下查询:

INSERT INTO products("Id", date, price) VALUES (7dacedd2-c09b-46c5-8686-00c2a03c71dd, dateof(now()), 24.87);    // Example only

但INSERT操作不承认其他条件条款(IF NOT EXISTS)并且不是我们想要的。我们需要更新价格,只要它与前一个不同,所以这迫使我们进行两个查询(一个用于读取当前值,另一个用于在必要时更新它)。

PD。 UPDATE操作确实有IF条件,但不是我们的情况,因为我们需要INSERT。

UPDATE products SET date = dateof(now()) WHERE "Id" = 7dacedd2-c09b-46c5-8686-00c2a03c71dd IF price != 20.3;    // example only 

2 个答案:

答案 0 :(得分:2)

不要尝试在cassandra数据库上应用普通模型。它可能会起作用,但最终会导致糟糕的性能和可扩展性。

Cassandra数据建模的推荐方法是首先找出针对数据库的读取查询并构建数据,以便这些读取便宜。你可能需要稍微复制写入但是没关系,因为在Cassandra中写入非常便宜。

对于您的特定用例,关键查询似乎能够让所有用户对产品的价格变化感兴趣,因此您可以为此创建一个表格,例如:

create table productSubscriptions ( productId uuid, priceLimit float, createdAt timestamp, email text, primary key (productId,priceLimit,createdAt) );

但由于您还需要了解用户的所有产品订阅,因此您需要一个具有相同数据的用户键表:

create table userProductSubscriptions ( email text, productId uuid, priceLimit float, primary key (email, productId) )

使用这两个表,我想您可以看到所有主要查询都可以通过单行选择完成,插入/删除很简单,但需要您同步修改两个表。

显然,你需要充分利用架构以满足你的需求,但这应该会给你一个关于如何思考你的cassandra架构的例子。

条件更新问题

对于条件插入问题,最简单的答案是:如果你确实需要它,请使用UPDATE(更新和插入在CQL中几乎完全相同),但这是一个非常昂贵的操作,所以如果可以,请避免使用它。

对于您的用例,我会将您的产品表拆分为三个:

create table products ( category uuid, productId uuid, url text, price float, primary key (category, productId) ) create table productPricingAudit ( productId uuid, date timestamp, price float, primary key (productId, date) ) create table priceScheduler ( day text, checktime timestamp, productId uuid, url text, primary key (day, checktime) )

产品表可以保留完整目录,可选择按类别拆分(以便列出单个类别中的所有产品是单行选择)

productPricingAudit 会检索最新价格的插页,因为这样可以调试您可能遇到的任何定价问题

priceScheduler 包含按指定时间排序的特定日期的所有支票。您的调度程序只需在运行时就在单行上进行列范围查询。

使用这样的架构,您不关心条件更新,只要更新产品价格,您只需发出3个插入,即使它没有更改。

答案 1 :(得分:1)

好的,我会尝试回答我自己的问题:条件插入除了" IF NOT EXISTS" Cassandra在日期,期间不支持。

最接近的是条件更新,但这在我们的方案中不起作用。所以还有一个简单的选择:应用程序端逻辑。这意味着您必须阅读上一个条目并对您的应用程序执行决策。明显的缺点是执行了2个查询(一个SELECT和一个INSERT),这显然增加了延迟。

然而,这适合我们的应用程序,因为每次我们执行查询以排队所有应该检查的项目时,我们也可以选择项目网址及其当前价格。因此,检查最新价格的工人可以决定是否插入,因为他们有当前的价格进行比较。

所以......每隔X分钟就会执行一次类似的查询:

SELECT id, url, price FROM products WHERE "nextCheckTime" < now();    

// example only, wouldn't even work if nextCheckTime is not part of the PK or index

这是在Cassandra集群上执行的非常昂贵的操作,因为它必须经过默认情况下随机存储在不同节点中的所有行。另一个缺点是我们需要一些关于产品和用户的高级和特定统计数据。

所以我们已经决定在这种特殊情况下,关系数据库会比Cassandra更好地为我们服务。

我们遗憾地留下了Cassandra的所有优点(快速插入,易于扩展,内置分片......)并期待MySQL群集或主从实现。

相关问题