所以我想将编码为 JSON 字符串的数据写入 Cassandra 表中。我做了以下步骤:
- 创建一个 Cassandra 表,其中包含具有我的 JSON 字符串的所有属性的列。这是 cql:
CREATE TABLE on_equipment (
ChnID varchar,
StgID varchar,
EquipID varchar,
SenID varchar,
value1 float,
value2 float,
value3 float,
electric_consumption float,
timestamp float,
measurement_location varchar,
PRIMARY KEY ((timestamp))
) WITH comment = 'A table for the on equipment readings';
- 编写一个 Python Cassandra 客户端,将数据从 JSON 负载写入 Cassandra。 这是进行 INSERt 查询的代码片段(msg.value 是 json 字符串):
session.execute('INSERT INTO ' + table_name + ' JSON ' + "'" + msg.value + "';")
执行此操作时我没有出现任何书写错误。
但是,我遇到了一个问题:
我拥有的 JSON 数据来自 IoT 源,我拥有的属性之一是 unix 时间戳。 JSON 记录的示例如下(注意时间戳属性):
{'timestamp': 1598279069.441547, 'value1': 0.36809349674042857, 'value2': 18.284579388599308, 'value3': 39.95615809003724, 'electric_consumption': 1.2468644044844224, 'SenID': '1', 'EquipID': 'MID-1', 'StgID': '1', 'ChnID': '1', 'measurement_location': 'OnEquipment'}
为了插入多条记录,我在Cassandra表中定义了时间戳值作为数据的主键。问题是并非所有记录都被写入 Cassandra,只有时间戳属于特定组的记录。我知道这一点是因为我已经生成了大约 100 条消息并且收到了零个写入错误,但表格的内容只有 4 行:
timestamp | chnid | electric_consumption | equipid | measurement_location | senid | stgid | value1 | value2 | value3
------------+-------+----------------------+---------+----------------------+-------+-------+----------+----------+----------
1.5983e+09 | 1 | 0.149826 | MID-1 | OnEquipment | 1 | 1 | 0.702309 | 19.92813 | 21.47207
1.5983e+09 | 1 | 1.10219 | MID-1 | OnEquipment | 1 | 1 | 0.141921 | 5.11319 | 78.17094
1.5983e+09 | 1 | 1.24686 | MID-1 | OnEquipment | 1 | 1 | 0.368093 | 18.28458 | 39.95616
1.5983e+09 | 1 | 1.22841 | MID-1 | OnEquipment | 1 | 1 | 0.318357 | 16.9013 | 71.5506
换句话说,Cassandra 正在更新这四行的值,而此时它应该写入所有 100 条消息。
我的猜测是我错误地使用了 Cassandra 主键。时间戳列是 float 类型。
我的问题: 这种行为有意义吗?你能解释一下吗? 我可以使用什么作为主键来解决这个问题? 有没有办法让主键成为 Cassandra 写入或到达时间?
预先感谢您的帮助!
最佳答案
您已将主键定义为时间戳 - 如果您将数据插入 Cassandra 表,并且您正在写入的数据与表中已有数据具有相同的主键,您将覆盖它。所有插入实际上都是插入/更新,因此当您第二次使用相同的主键值时,它会更新。
至于解决方案 - 这很诡异 - 主键必须符合它的名称 - 它是主要的,例如唯一 - 即使它是时间戳而不是 float ,您也应该在主键中至少有 1 个其他字段(例如 IoT 唯一标识符),以便在完全相同的时间从两个不同设备读取的 2 个读数不会发生冲突.
在 Cassandra 中,您可以根据您打算如何访问数据来对数据和键进行建模 - 不知道不可能知道主键(分区 + 集群键)应该是什么。理想情况下,您还需要了解有关数据基数和选择性的信息。
识别并定义您打算对数据运行的查询,这应该指导您的分区键和集群键选择 - 它们共同构成主键。
这里要添加到上面的具体问题是数据超出了 float 可以存储的精度 - 限制有效值并使它们全部相同。如果将 float 更改为 double,它会存储数据而不将值限制为相同的值 - 这会导致更新插入而不是插入新行。 (JSON 插入部分与问题无关,因为它发生了)
重现问题如下:
CREATE TABLE on_equipment (
ChnID varchar,
timestamp float,
PRIMARY KEY ((timestamp))
) ;
insert into on_equipment(timestamp, chnid) values (1598279061,'1');
insert into on_equipment(timestamp, chnid) values (1598279062,'2');
insert into on_equipment(timestamp, chnid) values (1598279063,'3');
insert into on_equipment(timestamp, chnid) values (1598279064,'4');
select count(*) from on_equipment;
1
select timestamp from on_equipment;
1.59827904E9
您可以看到该值已四舍五入并设置了上限,所有 4 个值的上限相同,如果您使用较小的数字作为时间戳,它会起作用,但这样做不是很有用。
将其更改为双数:
CREATE TABLE on_equipment (
ChnID varchar,
timestamp double,
PRIMARY KEY ((timestamp))
) ;
insert into on_equipment(timestamp, chnid) values (1598279061,'1');
insert into on_equipment(timestamp, chnid) values (1598279062,'2');
insert into on_equipment(timestamp, chnid) values (1598279063,'3');
insert into on_equipment(timestamp, chnid) values (1598279064,'4');
select count(*) from on_equipment;
4
关于json - 使用 python 客户端将 JSON 数据写入 Cassandra,主键选择问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63565125/