因此,我正在为产品价格跟踪设计此数据模型。
许多用户可以关注产品,用户可以关注许多产品,因此它具有多对多的关系。 产品处于持续跟踪状态,但只有在与前一个产品不同的情况下才会插入新价格。
用户已为其关注产品设置了价格上限,因此每次价格变化时,都会检查首选项,并在价格低于其阈值时通知用户。
所以最初我想到了以下产品型号:
然而" 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
答案 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群集或主从实现。