使用 python 客户端将 JSON 数据写入 Cassandra,主键选择问题
Writing JSON data into Cassandra using python client, issue with primary key choice
所以我想将编码为 JSON 字符串的数据写入 Cassandra table。我做了以下步骤:
- 创建一个 Cassandra table,其中包含具有我的 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中定义了时间戳值作为数据的主键table。问题是并非所有记录都被写入 Cassandra,只有时间戳属于特定组的记录。我知道这一点是因为我已经生成了大约 100 条消息并且收到了零个写入错误,但是 table 的内容只有 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 table,并且您正在写入的数据与 table 中已有的数据具有相同的主键,您将覆盖它。所有插入都有效 insert/update,因此当您第二次使用相同的主键值时,它将更新。
至于解决方案 - 这是一个骗局 - 主键必须符合它的名称 - 它是主要的,例如唯一 - 即使它是时间戳而不是浮点数,您也应该在主键中至少有 1 个其他字段(例如 IoT 唯一标识符),以便在完全相同的时间从两个不同设备读取的 2 个读数不会发生冲突.
在 Cassandra 中,您可以根据您打算如何访问数据来对数据和键进行建模 - 不知道不可能知道主键(分区 + 集群键)应该是什么。理想情况下,您还需要了解有关数据基数和选择性的知识。
识别并定义您打算 运行 对数据的查询,这应该指导您的分区键和集群键选择 - 它们共同构成主键。
这里要添加到上面的具体问题是数据超出了浮点数可以存储的精度 - 限制有效值并使它们全部相同。如果将 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 字符串的数据写入 Cassandra table。我做了以下步骤:
- 创建一个 Cassandra table,其中包含具有我的 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中定义了时间戳值作为数据的主键table。问题是并非所有记录都被写入 Cassandra,只有时间戳属于特定组的记录。我知道这一点是因为我已经生成了大约 100 条消息并且收到了零个写入错误,但是 table 的内容只有 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 table,并且您正在写入的数据与 table 中已有的数据具有相同的主键,您将覆盖它。所有插入都有效 insert/update,因此当您第二次使用相同的主键值时,它将更新。
至于解决方案 - 这是一个骗局 - 主键必须符合它的名称 - 它是主要的,例如唯一 - 即使它是时间戳而不是浮点数,您也应该在主键中至少有 1 个其他字段(例如 IoT 唯一标识符),以便在完全相同的时间从两个不同设备读取的 2 个读数不会发生冲突.
在 Cassandra 中,您可以根据您打算如何访问数据来对数据和键进行建模 - 不知道不可能知道主键(分区 + 集群键)应该是什么。理想情况下,您还需要了解有关数据基数和选择性的知识。
识别并定义您打算 运行 对数据的查询,这应该指导您的分区键和集群键选择 - 它们共同构成主键。
这里要添加到上面的具体问题是数据超出了浮点数可以存储的精度 - 限制有效值并使它们全部相同。如果将 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