Mat*_*amp 6 schema nosql cassandra
我有一个玩具 Cassandra 集群在家里的一些 RaspberryPi 上运行。我目前正在将 CryptoCoin 数据记录到它,希望能更多地了解 Cassandra 以及沿途的其他一些事情。
我今天在这里的问题是找出我是否在这张表上正确构建了我的架构。
该表没有很多字段,主键是名称字段和时间戳字段。我想从所有硬币中查询最近 N 小时的数据(每分钟记录一次数据)。如果我使用简单的 WHERE 子句,我会收到“ALLOW FILTERING”警告。我理解为什么会发生这种情况,但我正在努力理解正确的前进道路以确保可扩展的解决方案。现在该表只有大约 320k 条记录,我可以毫无问题地使用 ALLOW FILTERING,但我意识到情况可能并非总是如此。
我设置了一个测试来查看运行两种不同的查询方法需要多长时间。ALLOW FILTERING 方法目前是最快的,但它可能会保持这种状态吗?这就是我知识匮乏的地方。
我有一个想法,添加另一个字段,即星期几,也可能是月份字段。我的想法是这可能允许在查询中进行更多过滤,因此我不必像下面所做的那样遍历所有代币,但我不知道这是否是个好主意。如果我这样做,我是否将它们设为主键?认为这是我对 Cassandra 最困惑的地方,但并非完全如此;也许只是不够自信。
CQL 表说明:
CREATE TABLE cryptocoindb.worldcoinindex (
name text,
timestamp int,
label text,
price_btc double,
price_cny double,
price_eur double,
price_gbp double,
price_rur double,
price_usd double,
volume_24h double,
PRIMARY KEY (name, timestamp)
) WITH CLUSTERING ORDER BY (timestamp ASC)
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';
Run Code Online (Sandbox Code Playgroud)
Python中的代码:
# First method using ALLOW FILTERING:
startTime = time.time()
oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)
query = "SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;".format(CASSANDRA_DB, CASSANDRA_TABLE, prior24hr)
rslt = session.execute(query, timeout=None)
worldcoinindex = rslt._current_rows
elapseTime = time.time()-startTime
print("Elapsed Time for this method: {}".format(elapseTime))
Run Code Online (Sandbox Code Playgroud)
此方法已用时间:0.6223547458648682
# Second method using multiple queries...
startTime = time.time()
# I get the unique coin names here.
qryGetCoinList = "SELECT DISTINCT name FROM {}.{};".format(CASSANDRA_DB, CASSANDRA_TABLE)
rslt = session.execute(qryGetCoinList, timeout=None)
rsltGetCoinList = rslt._current_rows
rsltGetCoinList = rsltGetCoinList.name.tolist()
oneDaySec = 60*60*24
prior24hr = int(time.time()-oneDaySec)
# This iterates over the unique coin names and queries
# the last 24 hrs worth of data per coin.
# NOTE: There are 518 unique coins.
rsltTodayPrices = pd.DataFrame()
for coin in rsltGetCoinList:
qryTodayPrices = """
SELECT * FROM {}.{}
WHERE name = '{}' AND timestamp > {};
""".format(CASSANDRA_DB,
CASSANDRA_TABLE,
coin,
prior24hr)
rslt = session.execute(qryTodayPrices, timeout=None)
TodayPrices = rslt._current_rows
rsltTodayPrices.append(TodayPrices)
elapseTime = time.time()-startTime
print("Elapsed Time for this method: {}".format(elapseTime))
Run Code Online (Sandbox Code Playgroud)
此方法已用时间:1.4576539993286133
谢谢!
Aar*_*ron 10
现在该表只有大约 320k 条记录,我可以毫无问题地使用 ALLOW FILTERING,但我意识到情况可能并非总是如此。
所以事情是这样的:Cassandra非常擅长通过特定的键查询数据。它还擅长检索分区内的一系列数据。
"SELECT * FROM {}.{} WHERE timestamp > {} ALLOW FILTERING;"
Run Code Online (Sandbox Code Playgroud)
但是由于其分布式特性,它并不擅长扫描整个表来编译结果集。这就是您要求它对上述查询执行的操作。
网络流量是昂贵的。因此,Cassandra 的主要目标是确保您的查询由单个节点提供服务。在ALLOW FILTERING
不指定分区键(名称)的情况下使用会导致您的查询需要协调器节点,并检查集群中的每个节点是否有可能与您的 WHERE 子句匹配的值。
从本质上讲,集群中的节点越多,对ALLOW FILTERING
性能的影响就越大(除非您至少指定分区键……只有这样才能保证您的查询可以由单个节点提供服务)。请注意,您的较慢查询实际上是正确的,并为您解决了该问题。
我有一个想法,添加另一个字段,即星期几,也可能是月份字段。
这是个好主意!
它解决了两个问题。
Cassandra 的每个分区限制为 20 亿个单元。由于您的分区键是“名称”并且您不断在其中添加唯一的时间戳,因此您将朝着该限制前进,直到达到该限制,或者您的分区变得太大而无法使用(可能是后者)。
这是我将如何解决这个问题:
CREATE TABLE cryptocoindb.worldcoinindex_byday (
daybucket text,
name text,
datetime timestamp,
label text,
price_btc double,
price_cny double,
price_eur double,
price_gbp double,
price_rur double,
price_usd double,
volume_24h double,
PRIMARY KEY (daybucket, datetime, name)
) WITH CLUSTERING ORDER BY (datetime DESC, name ASC);
Run Code Online (Sandbox Code Playgroud)
现在你可以这样查询:
SELECT * FROM cryptocoindb.worldcoinindex
WHERE daybucket='20170825' AND datetime > '2017-08-25 17:20';
Run Code Online (Sandbox Code Playgroud)
此外,通过按“日期时间”降序对行进行聚类,您可以确保最新的数据位于每个单元格的顶部(让 Cassandra 不必解析)。
我将“名称”移到最后一个聚类列,只是为了保持唯一性。如果您永远不会按“名称”进行查询,那么将其用作分区键就没有意义了。
希望这可以帮助。
注意:我将您更改timestamp int
为 ,datetime timestamp
因为它增加了示例的清晰度。您可以使用任何适合您的方法,但请注意以数据类型命名列所引起的混淆。
编辑 20170826
以下与您的代码相同还是不同?
PRIMARY KEY ((daybucket, datetime), name)
不,那不一样。那是使用一种叫做复合分区键的东西。它会在集群中为您提供更好的数据分布,但会使您的查询变得更加困难,并且基本上会让您重新进行表扫描。
对于 Cassandra 主键的一个好的、全面的描述,Carlo Bertuccini在 StackOverflow 上有很好的回答:
Is there a way to alter the way Cassandra reads timestamps or an easy way to make changes to that whole datafield to alter the timestamp so it will be correctly read?
Not really. Cassandra timestamps can be tricky to work with. They store with millisecond precision, but don't actually show that full precision when queried. Also, as of one of the 2.1 patches, it automatically displays time in GMT; so that can be confusing to people as well. If your way of managing timestamps on the application side is working for you, just stick with that.
归档时间: |
|
查看次数: |
5306 次 |
最近记录: |