MessagePack est un format de sérialisation de données proposé et implémenté par M. Furuhashi de Treasure Data, et est bien connu comme format pour fluentd pour communiquer entre eux. Et je pense que vous l'êtes. Personnellement, je l'utilise souvent pour stocker des données lors de l'analyse de données, et cet article présentera la méthode.
Bien que j'essaie d'écrire l'article aussi précisément que possible, je suis relativement amateur de l'analyse des données, donc j'accueille vos suggestions et commentaires.
Tout ce que vous voulez faire est d'enregistrer les ** données que vous avez obtenues pour analyse au format MessagePack dans un fichier et de lire ces données au moment de l'analyse **.
Normalement, lors de l'analyse de données, etc., il semble que ce soit la voie royale pour les stocker une fois dans une base de données, etc., puis effectuer l'analyse, mais dans les cas suivants, je pense qu'il y a un mérite à enregistrer et à lire au format MessagePack. ..
Par exemple, si la sortie de données d'un certain système est JSON au format dictionnaire, les clés incluses dans chaque enregistrement sont différentes, le format de ce qui est entré en tant que valeur est différent et on ne sait pas si le format du dictionnaire ou le format du tableau est fourni. Ou quelque chose comme ça. De plus, même si la clé ou la valeur change, il est bon qu'un tel schéma ou spécification soit correctement défini, mais il y a des cas où il n'y a pas d'autre choix que d'estimer à partir des données réelles sans même la spécification.
Dans un tel cas, MessagePack peut convertir la structure hiérarchique telle que les dictionnaires et les tableaux presque telle quelle et l'utiliser, il est donc facile de l'insérer dans le fichier sans penser à quoi que ce soit pour le moment. Lors de la récupération de données pour l'analyse des données, les E / S de données deviennent souvent un goulot d'étranglement, de sorte que leur enregistrement localement dans un format de fichier facilite les essais et erreurs par la suite.
Il y a beaucoup de choses que l'on peut appeler analyse de données, mais il est souvent nécessaire de réaliser une «analyse exploratoire des données» pour saisir le tableau d'ensemble et formuler une hypothèse en pétrissant les données au stade où une hypothèse suffisante ne peut être établie. Dans un tel cas, vous pouvez convertir les données dans un format facile à traiter, extraire uniquement les données nécessaires et les enregistrer, etc. Dans ce cas, je pense qu'il peut y avoir des essais et des erreurs concernant le format des données, comme "Je veux ajouter cet attribut pour un moment" ou "Il semble préférable de l'enregistrer sous forme de dictionnaire plutôt que de liste".
Lors du traitement tout en modifiant de manière flexible le format des données de cette manière, lorsque le côté code est modifié en définissant à nouveau le schéma dans un endroit autre que le code qui traite les données (par exemple, créer une table avec SQL), etc. Des incohérences peuvent survenir dans chaque cas, ce qui peut être très gênant. D'autre part, si vous souhaitez enregistrer des données au format MessagePack, bien sûr, vous devez faire correspondre le format de données à la fois pour l'écriture et la lecture, mais le travail est minime.
(Cependant, si vous ne laissez pas de commentaires dans une certaine mesure, vous risquez de ne pas comprendre du tout le sens même si vous relisez le code vous-même quelques mois plus tard ...)
DB en tant que middleware stocke non seulement simplement les données, mais fournit également diverses fonctions telles que la définition des clés et la garantie de la fiabilité, ce qui prend plus de temps que la simple écriture sur disque. .. Cela peut être résolu par des techniques telles que la distribution de charge, mais si vous voulez simplement "sauvegarder un peu de données", vous pouvez le convertir au format MessagePack et l'écrire directement sous forme de fichier. Cependant, les performances d'écriture et de lecture des fichiers sont appliquées presque telles quelles.
Cependant, la fiabilité est la même que l'écriture dans un fichier et on suppose que toutes les données sont lues lors de la lecture.
D'un autre côté, bien sûr, il y a des cas où il ne convient pas d'enregistrer au format MessagePack et d'analyser les données.
Les technologies suivantes peuvent être considérées comme des alternatives. Veuillez sélectionner en fonction de la situation.
Il est préférable d'utiliser CSV (ou TSV) si les données sont dans un format de colonne de longueur presque fixe et non structurées de manière hiérarchique. Cependant, il est plus facile d'utiliser MessagePack lorsque des éléments de longueur variable et des structures hiérarchiques sont inclus.
Vous pouvez insérer sans définir de schéma dans une base de données orientée document, de sorte que vous pouvez faire de même à partir du point de sauvegarde des données pour le moment. Cependant, les performances de l'insertion semblent être 3 500 insert / s de trop, et lors de l'écriture avec MessagePack, il n'écrit que directement sur le disque, donc L'enregistrement avec MessagePack, qui conserve les performances des E / S de disque, est extrêmement rapide. Cependant, si vous souhaitez créer des clés plus tard, MongoDB sera plus adapté.
Il est désavantageux par rapport à MessagePack en termes de vitesse de traitement et de taille des données (référence). De plus, JSON est un module qui lit par étapes comme ijson lorsque vous souhaitez placer plusieurs objets dans un segment de données (par exemple, un fichier). Si vous ne l'utilisez pas, vous devez tout analyser en même temps, donc si le nombre de données est important, le traitement sera difficile sur une machine médiocre. D'un autre côté, si vous l'écrivez comme ijson, le code sera compliqué, donc je pense personnellement qu'il est plus facile de stocker des données en continu dans un segment de données et de les récupérer docilement.
Protocol Buffers est réputé comme l'une des technologies de sérialisation, mais il faut du temps pour traiter des données dont le schéma n'est pas clair car il est nécessaire de définir le schéma côté code de traitement. Lorsqu'elle est considérée comme une sérialisation de données comme une interface entre les logiciels, elle est pratique car elle régule le schéma, mais elle devient difficile à gérer dans les cas où vous ne savez pas quel type de données de schéma viendra.
Il y a beaucoup d'explications sur la page officielle, donc je n'ai pas besoin de beaucoup parler, mais je présenterai l'exemple de code en se concentrant uniquement sur l'écriture et la lecture du fichier. Le code peut également être trouvé sur github.
Dans tous les cas, les données suivantes doivent être écrites / lues dans le fichier «data.msg».
{
"name": "Alice",
"age": 27,
"hist": [5, 3, 1]
}
{
"name": "Bob",
"age": 33,
"hist": [4, 5]
}
Le package msgpack-python
est requis.
Installation
$ pip install msgpack-python
Écrire un exemple de code
# coding: UTF-8
import msgpack
obj1 = {
"name": "Alice",
"age": 27,
"hist": [5, 3, 1]
}
obj2 = {
"name": "Bob",
"age": 33,
"hist": [4, 5]
}
with open('data.msg', 'w') as fd:
fd.write(msgpack.packb(obj1))
fd.write(msgpack.packb(obj2))
Lire un exemple de code
# coding: UTF-8
import msgpack
for msg in msgpack.Unpacker(open('data.msg', 'rb')):
print msg
Le package msgpack
est requis.
$ gem install msgpack
Écrire un exemple de code
# -*- coding: utf-8 -*-
require "msgpack"
obj1 = {
"name": "Alice",
"age": 27,
"hist": [5, 3, 1]
}
obj2 = {
"name": "Bob",
"age": 33,
"hist": [4, 5]
}
File.open("data.msg", "w") do |file|
file.write(obj1.to_msgpack)
file.write(obj2.to_msgpack)
end
Lire un exemple de code
# -*- coding: utf-8 -*-
require "msgpack"
File.open("data.msg") do |file|
MessagePack::Unpacker.new(file).each do |obj|
puts obj
end
end
Il existe quelques bibliothèques MessagePack majeures, mais cette fois j'utiliserai msgpack-lite
pour le code.
$ npm install msgpack-lite
Écrire un exemple de code
const fs = require('fs');
const msgpack = require('msgpack-lite');
const obj1 = {
name: "Alice",
age: 27,
hist: [5, 3, 1]
};
const obj2 = {
name: "Bob",
age: 33,
hist: [4, 5]
};
fs.open('data.msg', 'w', (err, fd) => {
fs.writeSync(fd, msgpack.encode(obj1));
fs.writeSync(fd, msgpack.encode(obj2));
});
Lire un exemple de code
const fs = require('fs');
const msgpack = require('msgpack-lite');
var rs = fs.createReadStream('data.msg');
var ds = msgpack.createDecodeStream();
rs.pipe(ds).on('data', (msg) => {
console.log(msg);
});
La bibliothèque msgpackc
est requise. Pour macOS, vous pouvez l'installer avec brew.
$ brew install msgpack
Écrire un exemple de code
#include <msgpack.hpp>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd = open("data.msg", O_WRONLY | O_CREAT, 0600);
msgpack::sbuffer buf1, buf2;;
msgpack::packer<msgpack::sbuffer> pk1(&buf1), pk2(&buf2);
pk1.pack_map(3);
pk1.pack("name"); pk1.pack("Alice");
pk1.pack("age"); pk1.pack(27);
pk1.pack("hist");
pk1.pack_array(3);
pk1.pack(5); pk1.pack(3); pk1.pack(1);
write(fd, buf1.data(), buf1.size());
pk2.pack_map(3);
pk2.pack("name"); pk2.pack("Bob");
pk2.pack("age"); pk2.pack(33);
pk2.pack("hist");
pk2.pack_array(2);
pk2.pack(4); pk2.pack(5);
write(fd, buf2.data(), buf2.size());
close(fd);
return 0;
}
Lire un exemple de code
#include <msgpack.hpp>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
static const size_t BUFSIZE = 4; //Osez réduire la taille du tampon
int rc;
char buf[BUFSIZE];
int fd = open("data.msg", O_RDONLY);
msgpack::unpacker unpkr;
while (0 < (rc = read(fd, buf, sizeof(buf)))) {
unpkr.reserve_buffer(rc);
memcpy(unpkr.buffer(), buf, rc);
unpkr.buffer_consumed(rc);
msgpack::object_handle result;
while (unpkr.next(result)) {
const msgpack::object &obj = result.get();
if (obj.type == msgpack::type::MAP) {
printf("{\n");
msgpack::object_kv* p(obj.via.map.ptr);
for(msgpack::object_kv* const pend(obj.via.map.ptr + obj.via.map.size);
p < pend; ++p) {
std::string key;
p->key.convert(key);
if (key == "name") {
std::string value;
p->val.convert(value);
printf(" %s: %s,\n", key.c_str(), value.c_str());
}
if (key == "age") {
int value;
p->val.convert(value);
printf(" %s: %d,\n", key.c_str(), value);
}
if (key == "hist") {
msgpack::object arr = p->val;
printf (" %s, [", key.c_str());
for (int i = 0; i < arr.via.array.size; i++) {
int value;
arr.via.array.ptr[i].convert(value);
printf("%d, ", value);
}
printf ("],\n");
}
}
printf("}\n");
}
result.zone().reset();
}
}
return 0;
}
Au fait, si vous lancez le format msgpack :: object dans ʻostream (
std :: cout` etc.), le format sera formaté et affiché sans permission, mais il est difficile comme décrit ci-dessus de récupérer la valeur par programme. La procédure est décrite comme un exemple.
Recommended Posts