#json #cassandra #cassandra-3.0
#json #cassandra #cassandra-3.0
Вопрос:
Итак, я хочу записать данные, которые закодированы в виде строки 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 для записи данных в Cassandra из полезной нагрузки JSON.
Вот фрагмент кода для выполнения запроса INSERt (msg.value — это строка json):
session.execute('INSERT INTO ' table_name ' JSON ' "'" msg.value "';")
При этом я не получаю ошибок записи.
Однако я столкнулся с проблемой:
Имеющиеся у меня данные JSON взяты из источников IoT, и одним из атрибутов, которые у меня есть, является временная метка 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 сообщений.
Я предполагаю, что я неправильно использую первичный ключ Cassandra. Столбец timestamp имеет тип float.
Мои вопросы: Имеет ли смысл такое поведение? Можете ли вы это объяснить? Что я могу использовать в качестве первичного ключа для решения этой проблемы? Есть ли способ сделать первичный ключ временем записи или прибытия Cassandra?
Заранее благодарю вас за вашу помощь!
Ответ №1:
Вы определили первичный ключ как просто временную метку — если вы вставляете данные в таблицу Cassandra, и данные, которые вы записываете, имеют тот же первичный ключ, что и данные, уже имеющиеся в таблице, вы их перезапишете. Все вставки фактически являются вставкой / обновлением, поэтому, когда вы используете одно и то же значение первичного ключа во второй раз, оно обновится.
Что касается решения — это хитрость — первичный ключ должен соответствовать своему имени — он первичен, например, уникален — даже если это была временная метка вместо числа с плавающей точкой, у вас также должно быть по крайней мере 1 другое поле (например, уникальный идентификатор IoT) в первичном ключе, чтобы 2 чтения с двух разных устройств, сделанные в одно и то же время, не конфликтовали.
В Cassandra вы моделируете данные и ключи на основе того, как вы собираетесь получить доступ к данным — не зная, что было бы невозможно узнать, каким должен быть первичный ключ (раздел ключ кластеризации). В идеале вам также необходимо кое-что знать о мощности и избирательности данных.
Определите запросы, которые вы собираетесь запускать к данным, которые должны определять ваш выбор ключа раздела и ключа кластеризации, которые вместе составляют первичный ключ.
Конкретная проблема, которую следует добавить к вышесказанному, заключается в том, что данные превышают точность, с которой может храниться значение с плавающей точкой, что ограничивает действующее значение и делает их все идентичными. Если вы измените значение с плавающей точкой на 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 значения ограничены одинаково, если вы используете меньшие числа для временных меток, это работает, но не очень полезно для этого.
Изменение его на double:
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
Комментарии:
1. Я согласен с тем, что вы говорите, однако на данный момент я отправляю одно сообщение каждую секунду, и временная метка не округляется до ближайшей секунды, т.е. ‘timestamp’: 1598279069.441547. Не должна ли каждая запись быть уникальной?
2. Если это разные значения — в тексте выше из-за форматирования мы не можем увидеть эту разницу. Каждая временная метка равна ‘1.5983e 09’ — можете ли вы исправить это, чтобы мы могли видеть реальные значения?
3. @FVCC — воспроизведено и обновлено, вы достигаете пределов значащих десятичных цифр в строке с плавающей запятой.
4. Работает отлично @Andrew, спасибо. Я сделал то, что вы предложили, сделав первичный ключ функцией как идентификатора датчика, так и метки времени, чтобы гарантировать, что никакие одинаковые показания метки времени не совпадают. Поддержал бы ваш ответ, но у меня достаточно репутации для этого. Приветствия!