J'insère dans une table Cassandra avec des colonnes d'horodatage. Les données que j'ai ont une précision de l'ordre de la microseconde. La chaîne de données de temps ressemble à ceci:
2015-02-16T18: 00: 03.234 + 00: 00
Cependant, dans cqlsh, lorsque je lance une requête select, les données en microsecondes ne sont pas affichées, je ne peux que voir le temps passer en seconde précision. Les données 234 microsecondes ne sont pas affichées.
Je suppose que j'ai deux questions:
1) Cassandra enregistre-t-il des microsecondes avec le type de données timestamp? Je suppose que oui?
2) Comment puis-je voir cela avec cqlsh pour vérifier?
Définition du tableau:
create table data (
datetime timestamp,
id text,
type text,
data text,
primary key (id, type, datetime)
)
with compaction = {'class' : 'DateTieredCompactionStrategy'};
Insérer une requête exécutée avec Java PreparedStatment:
insert into data (datetime, id, type, data) values(?, ?, ?, ?);
La requête sélectionnée était simplement:
select * from data;
Afin de répondre à vos questions, j'ai un peu creusé le sujet.
Microsecondes non, millisecondes oui. Si je crée votre table, insère une ligne et essaie de l'interroger avant l'heure tronquée, cela ne fonctionne pas:
aploetz@cqlsh:stackoverflow> INSERT INTO data (datetime, id, type, data)
VALUES ('2015-02-16T18:00:03.234+00:00','B26354','Blade Runner','Deckard- Filed and monitored.');
aploetz@cqlsh:stackoverflow> SELECT * FROM data
WHERE id='B26354' AND type='Blade Runner' AND datetime='2015-02-16 12:00:03-0600';
id | type | datetime | data
----+------+----------+------
(0 rows)
Mais lorsque je demande les mêmes valeurs id
et type
en spécifiant des millisecondes:
aploetz@cqlsh:stackoverflow> SELECT * FROM data
WHERE id='B26354' AND type='Blade Runner' AND datetime='2015-02-16 12:00:03.234-0600';
id | type | datetime | data
--------+--------------+--------------------------+-------------------------------
B26354 | Blade Runner | 2015-02-16 12:00:03-0600 | Deckard- Filed and monitored.
(1 rows)
Les millisecondes sont donc bien là. Un ticket JIRA a été créé pour ce problème ( CASSANDRA-5870 ), mais le problème a été résolu avec le message "Ne résout pas le problème".
Une façon possible de vérifier que les millisecondes sont bien présentes consiste à imbriquer la fonction timestampAsBlob()
à l'intérieur de blobAsBigint()
, comme ceci:
aploetz@cqlsh:stackoverflow> SELECT id, type, blobAsBigint(timestampAsBlob(datetime)),
data FROM data;
id | type | blobAsBigint(timestampAsBlob(datetime)) | data
--------+--------------+-----------------------------------------+-------------------------------
B26354 | Blade Runner | 1424109603234 | Deckard- Filed and monitored.
(1 rows)
Bien que cela ne soit pas optimal, vous pouvez clairement voir la valeur de la milliseconde de "234" à la fin. Cela devient encore plus évident si j'ajoute une ligne pour le même horodatage, mais sans millisecondes:
aploetz@cqlsh:stackoverflow> INSERT INTO data (id, type, datetime, data)
VALUES ('B25881','Blade Runner','2015-02-16T18:00:03+00:00','Holden- Fine as long as nobody unplugs him.');
aploetz@cqlsh:stackoverflow> SELECT id, type, blobAsBigint(timestampAsBlob(datetime)),
... data FROM data;
id | type | blobAsBigint(timestampAsBlob(datetime)) | data
--------+--------------+-----------------------------------------+---------------------------------------------
B25881 | Blade Runner | 1424109603000 | Holden- Fine as long as nobody unplugs him.
B26354 | Blade Runner | 1424109603234 | Deckard- Filed and monitored.
(2 rows)
Vous pouvez configurer le format de sortie des objets datetime dans le fichier .cassandra/cqlshrc
, en utilisant la syntaxe python 'strftime'.
Malheureusement, la directive %f
pour les microsecondes (il ne semble pas y avoir de directive pour les millisecondes) ne fonctionne pas pour les anciennes versions de Python, ce qui signifie que vous devez revenir à la solution blobAsBigint(timestampAsBlob(date))
.
Je pense que par "microsecondes" (par exemple 03.234567), vous voulez dire "millisecondes" (par exemple (03.234).
Le problème ici était un bogue cqlsh
qui ne supportait pas les fractions de seconde lors du traitement des horodatages.
Ainsi, alors que votre valeur en millisecondes a été préservée dans la couche de persistance réelle (cassandra), le shell (cqlsh) n'a pas réussi à les afficher.
Cela était vrai même si vous deviez modifier time_format
dans .cqlshrc
pour afficher des fractions de seconde avec une directive %f
(par exemple, %Y-%m-%d %H:%M:%S.%f%z
). Dans cette configuration, cqlsh rendrait 3.000000
pour notre valeur 3.234, car le problème était de savoir comment cqlsh chargeait les objets datetime sans charger les secondes partielles.
Cela étant dit, ce problème a été résolu dans CASSANDRA-10428 , et publié dans Cassandra 3.4 .
Il est impossible d'afficher des microsecondes (1 millionième de seconde) à l'aide du type de données Cassandra 'timestamp' car la plus grande précision disponible pour ce type de données est la milliseconde (1 millième de seconde).
http://docs.datastax.com/fr/cql/3.1/cql/cql_reference/timestamp_type_r.html
Les valeurs du type d'horodatage sont codées sous forme d'entiers signés de 64 bits représentant un nombre de millisecondes depuis le temps de base standard connu sous le nom de l'époque
Quelques codes liés:
cqlsh> CREATE KEYSPACE udf
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};
cqlsh> USE udf;
cqlsh:udf> CREATE OR REPLACE FUNCTION udf.timeuuid_as_us ( t timeuuid )
RETURNS NULL ON NULL INPUT
RETURNS bigint LANGUAGE Java AS '
long msb = t.getMostSignificantBits();
return
( ((msb >> 32) & 0x00000000FFFFFFFFL)
| ((msb & 0x00000000FFFF0000L) << 16)
| ((msb & 0x0000000000000FFFL) << 48)
) / 10
- 12219292800000000L;
';
cqlsh:udf> SELECT
toUnixTimestamp(now()) AS now_ms
, udf.timeuuid_as_us(now()) AS now_us
FROM system.local;
now_ms | now_us
---------------+------------------
1525995892841 | 1525995892841000