Запись данных JSON в Cassandra с использованием клиента python, проблема с выбором первичного ключа

#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, спасибо. Я сделал то, что вы предложили, сделав первичный ключ функцией как идентификатора датчика, так и метки времени, чтобы гарантировать, что никакие одинаковые показания метки времени не совпадают. Поддержал бы ваш ответ, но у меня достаточно репутации для этого. Приветствия!