Cassandra中的行排序

2 投票
2 回答
868 浏览
提问于 2025-04-18 00:17

我在使用Cassandra 2.0.5时,有一个列族(columnfamily),并且使用了一个叫做Murmur3Partitioner的工具。在这个列族里,我存储了在某个时间段内唯一哈希值出现的次数(这些哈希值是从一段时间内发生的事件中提取的,具体细节不太重要)。

我的需求是选择在特定时间段内所有的哈希值及其计数(这里的hour字段就是指这个时间段)。

因为数据量可能非常大,我尝试使用分页的方法,比如使用LIMIT来限制每次返回的数据量,并从上次返回的哈希值继续获取,下面的例子就是这样做的。看起来这样做是有效的,因为哈希值似乎是按升序排列返回的。

有人能解释一下这到底是否真的有效,以及为什么吗?特别是我发现了这个链接,上面说行数据是……没有顺序的,所以现在想想,哈希值应该是随机返回的。

我通过分页的方法和在cqlsh中使用COUNT来验证这个过程,统计了行数,但由于数据量太大,我无法确认是否所有正确的哈希值都被返回了。

cqlsh:db> DESCRIBE COLUMNFAMILY hashes ;
CREATE TABLE hashes (
  hour text,
  hash text,
  count counter,
  PRIMARY KEY (hour, hash)
) WITH COMPACT STORAGE AND
  bloom_filter_fp_chance=0.010000 AND
  caching='KEYS_ONLY' AND
  comment='' AND 
  dclocal_read_repair_chance=0.000000 AND
  gc_grace_seconds=864000 AND
  index_interval=128 AND
  read_repair_chance=0.100000 AND
  replicate_on_write='true' AND
  populate_io_cache_on_flush='false' AND
  default_time_to_live=0 AND
  speculative_retry='99.0PERCENTILE' AND
  memtable_flush_period_in_ms=0 AND 
  compaction={'class': 'SizeTieredCompactionStrategy'} AND
  compression={'sstable_compression': 'LZ4Compressor'};


cqlsh:db> SELECT * FROM hashes WHERE hour = '2014032710' LIMIT 10;

 hour       | hash                                                             | count
------------+------------------------------------------------------------------+----------
 2014032710 | 000034d4b821c9af90bbf39cd803d45b25d7c14777697b8d9fc71c3a102c360f |        1
 2014032710 | 000063b39f526788dc026a07abe1bc1365652772e9c66be9a7408b16c61962fa |        2
 2014032710 | 00009c38834cedfb37bfd95355bba1a225aea6ee74f5ddc4ace820bfc33eb7a6 |        1
 2014032710 | 0000a68de59092e0326b3ceff8d9a1167c7f5ea0aac804389c259f336956e520 |        1
 2014032710 | 0000b0fed9e2f8f70e5e46f084be1872f0d1944c0e89a8850e6b7c3be17b8935 |        9
 2014032710 | 0001204a0fb29d3a8ac7164e451662069d19307ea56e014215a64cc606cf4df9 |        1
 2014032710 | 00015c165622a3c8b88d33e471d740088d9b6203dd81235d50ec129c40282229 |        1
 2014032710 | 00019ed1b3287ed808c24146d1f2e145238478b49ad3740fb58cb46bc509965a |       10
 2014032710 | 00019fa833cee60e7a1b8ed5d5c6fbef8c401a144e1537e15c9a5f65672d44fb |        1
 2014032710 | 0001df8d8319524a93ed523382a6cce8de9234211d5f3dc46bb4c530d9385150 |        1

(10 rows)

cqlsh:db> SELECT * FROM hashes WHERE hour = '2014032710' AND hash > '0001df8d8319524a93ed523382a6cce8de9234211d5f3dc46bb4c530d9385150' LIMIT 10;

 hour       | hash                                                             | count
------------+------------------------------------------------------------------+----------
 2014032710 | 000200428d93eb478c6a9ae0d9daa21fac88ca8dd4e536f60ae992dbea6155d4 |        2
 2014032710 | 00024447d8983fc0f022df4301eb69eca4ccc7cf0fc2e9361046dbaedbe830bc |        1
 2014032710 | 00025c6b3ef861fa3ef047d618f078927c9f8cf875e9b935c8e556189969bc17 |        1
 2014032710 | 00026f67e525bd11b67062e3122eb625799c6878f7812da8f23f0c8e9bd9f9d5 |        2
 2014032710 | 00028ded6dfe5d8616cc0eef559cfdf15fd51d5a36c17f2b9852785e8ca55c27 |        4
 2014032710 | 00028f8fab859c702fe0cc51db390ce7ae85ca97807a751ddf12fed57639239f |        1
 2014032710 | 0002f4046ef35e169fa79e2abf0b92212c1438487819dd8318301991ff99acac |       32
 2014032710 | 000381054a59d46c87164fcfb69952afa1e77acd71f88b25e09eab3eacc1b21a |        1
 2014032710 | 0003aca7fd2cab16a03d79fa7ac1505f144f9ba04fea87a050bef919aa628e74 |        1
 2014032710 | 0003e6a549b01cf1634c1b2844618d4e96ac00d74be30b9401b3fbbbc5bdb7e2 |        1

(10 rows)

2 个回答

1

试着使用token函数和limit一起,这样可以在多行数据中滚动查看。因为你已经定义了一个复合键,这样可以确保数据是有序的。你也可以在创建列族时看看CLUSTERING KEY ORDER。

希望这对你有帮助。

-Vivek
2

请了解一下“排序宽行”和“聚类顺序键”。以下是CQL规范页面中关于“分区键和聚类列”的一些摘录。

在CQL中,定义主键时列的顺序是很重要的。主键的第一个列叫做分区键。它的特点是,所有使用相同分区键的行(实际上甚至跨表)都会存储在同一个物理节点上。此外,对同一个表中使用相同分区键的行进行插入、更新或删除操作时,这些操作会被视为一个整体,并且是相互独立的。需要注意的是,可以使用复合分区键,也就是说,分区键可以由多个列组成,这时需要用额外的一对括号来定义哪些列组成分区键。

主键定义中剩下的列(如果有的话)被称为聚类列。在一个特定的物理节点上,针对某个分区键的行会按照聚类列的顺序存储,这样在按照这个顺序检索行时会特别高效(见SELECT)。

撰写回答