现在已经试用了几个星期的架构(有一些SO Q / As),我仍然不满意任何最终的设计。也许有人可以提出不同的建议。
我有一些传入的日志记录数据,格式为[timestamp,name,{custom_data}],其中数据是一组用户定义的键:ad-hoc插入的值对。有很多方法可以存储这些内容......但是我查找的所有方法在查询时都会出现问题。
查询需求包括custom_data的属性。例如,可能需要使用自定义数据查询所有事件:{foo = bar}或{wibble = bar}。数据被大量移动到集群进行处理,这里的瓶颈通常是线路上的数据。要求是尽可能少地移动数据。通常,事件有10个左右不同长度的自定义值,查询只需要2或3个。拉动7个未使用值的影响是巨大的。
我在模式中的实验如下:
卡珊德拉地图
CREATE TABLE logs (
action varchar,
date_bucket ascii,
action_time timeuuid,
custom_data map<text, text>,
PRIMARY KEY ((action, date_bucket), action_time)
) WITH CLUSTERING ORDER BY (action_time DESC)
这是获取数据的最好方法,也是最干净的架构。插入物很好。
不起作用是因为:执行查询会拉回整个地图。没有办法有选择地查询地图,这会导致数据过多。
EAV架构
CREATE TABLE logs (
action varchar,
date_bucket ascii,
action_time timeuuid,
property varchar,
value varchar,
PRIMARY KEY ((action, date_bucket), action_time, property)
) WITH CLUSTERING ORDER BY (action_time DESC, property)
有点传统的EAV型号。
不起作用,因为:
1)我找不到以所需方式查询的方法。 action_time在属性之前声明,所以如果你选择where where property ='foo',你将得到“错误请求:PRIMARY KEY部分属性不能被限制(前面部分action_time不受限制或非EQ关系)”
2)可以重新安排模式以在action_time之前给出属性,以便上述查询起作用。但是,您无法查询属性的子集(属性IN ...),因为您将收到错误请求:PRIMARY KEY部件属性不能受IN关系限制。
3)即使你可以让它工作,结果集仍然是EAV,因此线上的数据不是最佳的。对于每个事件,结果将是[{timeid:property_1:value} ... {timeid:property_n:value}],其中最佳结果是{timeid:[property_1:value ... property_n:value]}。鉴于在许多情况下,timeid与属性数据的宽度相同,这是一个很大的区别。
架构突变
嗯......这不太好看。这是一个没有值的空模式。
CREATE TABLE logs (
action varchar,
date_bucket ascii,
action_time timeuuid
PRIMARY KEY ((action, date_bucket), action_time)
) WITH CLUSTERING ORDER BY (action_time DESC)
每当插入属性时,将使用(适当的编码版本)属性名称作为列名直接尝试插入。如果该列不存在,则发出ALTER TABLE语句并重新插入该值。
它符合查询要求,但我不相信这会扩展得特别好。我认为可能只有大约10k的属性名称,但是很多并发的模式更改让我感到害怕。
还有什么?
我正在寻找更好的想法。希望有一些在那里。这对我来说似乎不是一个特别小的模特。
我想我正在寻找宽行中的宽行(如果有意义的话)?
可能是Cassandra不适合这个。我愿意接受这个答案。