Pythonクライアントを使用してJSONデータをCassandraに書き込む、主キーの選択に問題がある
そこで、JSON文字列としてコード化されたデータをCassandraテーブルに書き込みたいと思います。私は次の手順を実行しました。
- JSON文字列のすべての属性を持つ列を含むCassandraテーブルを作成します。そのための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ソースからのものであり、私が持っている属性の1つはUNIXタイムスタンプです。JSONレコードの例は次のとおりです(timestamp属性に注意してください)。
{'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個のメッセージすべてを書き込む必要があるときに、これら4つの行の値を更新しています。
私の推測では、Cassandraの主キーを誤って使用しています。タイムスタンプ列はfloat型です。
私の質問:この振る舞いは意味がありますか?説明してもらえますか?これを解決するための主キーとして何を使用できますか?主キーをCassandraの書き込み時間または到着時間にする方法はありますか?
よろしくお願いします!
回答
主キーを単なるタイムスタンプとして定義しました。Cassandraテーブルにデータを挿入し、書き込んでいるデータがすでにテーブルにあるデータと同じ主キーを持っている場合は、それを上書きします。すべての挿入は事実上挿入/更新であるため、同じ主キー値を2回使用すると、更新されます。
解決策に関しては-これはトリッキーです-主キーはその名前に忠実である必要があります-それはプライマリ、たとえば一意です-フロートではなくタイムスタンプであったとしても、少なくとも1つの他のフィールド(完全に同時に行われた2つの異なるデバイスからの2つの読み取り値が衝突しないように、主キー内のIoT一意の識別子)。
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