我的目标是在给定的时间范围(fromdate<stats\u date\u id<todate)内,对每个不同的提供者的发送的消息和发送的电子邮件进行求和,但不指定提供者的id。换句话说,我需要知道指定时间范围内的任何和所有提供者,并对其发送的消息和发送的电子邮件进行求和。
我有一个cassandra表,它使用一个express cassandra模式(在node.js中),如下所示:
module.exports = {
fields: {
stats_provider_id: {
type: 'uuid',
default: {
'$db_function': 'uuid()'
}
},
stats_date_id: {
type: 'timeuuid',
default: {
'$db_function': 'now()'
}
},
provider_id: 'uuid',
provider_name: 'text',
messages_sent: 'int',
emails_sent: 'int'
},
key: [
[
'stats_date_id'
],
'created_at'
],
table_name: 'stats_provider',
options: {
timestamps: {
createdAt: 'created_at', // defaults to createdAt
updatedAt: 'updated_at' // defaults to updatedAt
}
}
}
为了让它工作起来,我希望它能像下面这样简单:
let query = {
stats_date_id: {
'$gt': db.models.minTimeuuid(fromDate),
'$lt': db.models.maxTimeuuid(toDate)
}
};
let selectQueries = [
'provider_name',
'provider_id',
'count(direct_sent) as direct_sent',
'count(messages_sent) as messages_sent',
'count(emails_sent) as emails_sent',
];
// Query stats_provider table
let providerData = await db.models.instance.StatsProvider.findAsync(query, {select: selectQueries});
但是,这会抱怨需要过滤结果: Error during find query on DB -> ResponseError: Cannot execute this query as it might involve data filtering and thus may have unpredictable performance
.
我猜你不能有一个主键并且在上面做日期范围搜索?如果是这样,这种查询的正确方法是什么?
1条答案
按热度按时间vuv7lop31#
因此,虽然没有使用express cassandra,但我可以告诉您,在分区键上运行范围查询是一个很难回答的“否”。原因是cassandra无法为该查询确定单个节点,因此它必须轮询每个节点。由于这实际上是跨多个节点对表进行的完整扫描,因此会抛出该错误以防止运行错误的查询。
但是,您可以对集群键运行范围查询,前提是您要对它之前的所有键进行筛选。在你的情况下,如果我读对了,你的主键看起来像:
PRIMARY KEY (stats_date_id, created_at)
主键定义有两个问题:stats_date_id
是timeuuid。这对于数据分发非常有用。但查询灵活性太差了。实际上,您需要提供确切的timeuuid值来返回特定分区的数据。由于timeuuid具有毫秒精度,您需要知道精确到毫秒的查询时间。也许你有能力做到这一点,但通常这并不意味着一个好的分区键。分区下面有行吗(
created_at
)将不得不分享准确的时间,这通常会导致许多1:1基数比为partition:clustering keys.我的建议是在基数稍低的日期列上进行分区。想想在一个特定的时间范围内通常保存了多少提供者消息。还要选择一些不会同时存储太多提供者消息的内容,因为您不希望未绑定的分区增长(cassandra的硬限制是每个分区20亿个单元)。
可能是这样的:
PRIMARY KEY (week,created_at)
因此,您的cql查询可以如下所示:热释光;博士;
一个时间段上的分区不如ms上的分区精确,但是它足够大,可以满足您通常的查询。
在分区内的第一个集群键上应用范围过滤器。