2009-12-29 13 views
3

J'envisage d'utiliser MongoDB ou CouchDB sur un projet qui doit maintenir des enregistrements historiques. Mais je ne suis pas sûr à quel point il sera difficile de stocker des données historiques dans ces bases de données. Par exemple, dans son livre "Développer des applications de base de données orientées temps-SQL", Richard Snodgrass propose des outils permettant de récupérer l'état des données à un instant donné, et il montre comment créer des schémas qui permettent la manipulation de données (c'est-à-dire la manipulation de données qui rend difficile la saisie de données invalide).Quelles sont les ressources ou les outils utilisés pour gérer les données temporelles dans les magasins de valeurs-clés?

Existe-t-il des outils ou des bibliothèques qui facilitent l'interrogation, la manipulation ou la définition de structures temporelles/historiques pour les magasins de valeurs-clés?

modifier:

Notez que ce que j'entends, les données « version » qui stocke CouchDB est effacée lors d'une utilisation normale, et que je aurais besoin de conserver les données historiques, je ne pense pas que ce soit un solution viable.

P.S. Voici une question similaire qui n'a jamais été résolue: key-value-store-for-time-series-data

Répondre

2

Il y a deux options si vous voulez stocker les données dans MongoDB. Vous pouvez simplement stocker chaque version en tant que document séparé, car vous pouvez interroger pour obtenir l'objet à un certain moment, l'objet à tout moment, les objets sur plusieurs plages de temps, etc. Chaque document ressemble à:

{ 
    object : whatever, 
    date : new Date() 
} 

Vous pouvez stocker toutes les versions d'un document dans le document lui-même, comme suggéré par mikeal, en utilisant des mises à jour pour pousser l'objet lui-même dans un tableau d'historique. Dans Mongo, cela ressemblerait à ceci:

db.foo.update({object: obj._id}, {$push : {history : {date : new Date(), object : obj}}}) 

// make changes to obj 
... 

db.foo.update({object: obj._id}, {$push : {history : {date : new Date(), object : obj}}}) 

Un refroidisseur (je pense) et plus moyen efficace d'espace, bien que moins de temps efficace, peut-être pour stocker une histoire dans l'objet lui-même au sujet de ce qui a changé dans l'objet à chaque fois. Ensuite, vous pouvez rejouer l'historique pour construire l'objet à un certain moment. Par exemple, vous pourriez avoir:

{ 
    object : startingObj, 
    history : [ 
     { date : d1, addField : { x : 3 } }, 
     { date : d2, changeField : { z : 7 } }, 
     { date : d3, removeField : "x" }, 
     ... 
    ] 
} 

Alors, si vous voulez voir ce que l'objet ressemblait entre le temps d2 et d3, vous pouvez prendre le startingObj, ajouter le champ x avec la valeur 3, définissez le champ z à la valeur de 7, et ce serait l'objet à ce moment-là.

Chaque fois que l'objet a changé, vous pouvez pousser atomiquement actions au tableau de l'histoire:

db.foo.update({object : startingObj}, {$push : {history : {date : new Date(), removeField : "x"}}}) 
+0

Merci Kristina. C'est une façon vraiment géniale de faire les changements.Nous cherchons également à pouvoir interroger des données sous la forme Oracle de: SELECT * FROM X AS aaaa-mm-jj. Ou quelque chose qui serait aussi simple. Le problème avec la méthode que vous avez proposée, alors, serait que nous aurions à recréer chaque objet chaque fois que la requête est exécutée. Nous rencontrons un problème similaire avec notre base de données SQL existante qui a également été conçue en pensant à l'espace. Mais puisque l'espace n'est pas vraiment un problème, garder une copie complète répond probablement un peu plus à nos besoins. Merci quand même! – btelles

1

Oui, dans CouchDB les révisions d'un document sont là pour la réplication et sont généralement perdues pendant le compactage. Je pense qu'UbuntuOne a fait quelque chose pour les garder plus longtemps mais je ne sais pas exactement ce qu'ils ont fait.

J'ai un document dont j'ai besoin des données historiques et c'est ce que je fais.

Dans CouchDB j'ai une fonction _update. Le document a un attribut "history" qui est un tableau. Chaque fois que j'appelle la fonction _update pour mettre à jour le document que j'ajoute au tableau d'historique le document courant (moins l'attribut history), je mets à jour le document avec les changements dans le corps de la requête. De cette façon, j'ai l'historique complet des révisions du document.

Ceci est un peu lourd pour les documents volumineux, il y a quelques outils de diff de javascript que j'étudiais et je pensais à ne stocker que la différence entre les documents mais je ne l'ai pas encore fait.

http://wiki.apache.org/couchdb/How_to_intercept_document_updates_and_perform_additional_server-side_processing

espoir qui aide.

+0

Merci Mike. Cela ressemble à une solution raisonnable, et semble certainement assez facile. Je me demande s'il y a des articles ou des articles qui explorent ce sujet par rapport aux magasins à valeur-clé en plus de détails. – btelles

+0

Le problème est un peu plus compliqué car certains magasins de valeur-clé gardent une trace des changements (comme CouchDB) mais leur système interne de suivi des changements peut ne pas être bon pour stocker les changements de façon permanente (CouchDB) :) Le système d'indexation de MongoDB être pénible à utiliser si vous avez besoin d'indexer l'historique, alors que la carte/réduire de CouchDB est suffisamment flexible. Je ne pense pas que cela puisse être généralisé à une question sur les magasins de valeurs-clés en général. – mikeal

+0

Gotchya. Merci. – btelles

1

Je ne peux pas parler pour mongodb mais pour couchdb tout dépend vraiment de la façon dont vous écrivez vos points de vue. Je ne connais pas les détails de ce dont vous avez besoin, mais si vous avez un identifiant unique pour un document tout au long de sa durée de vie et stockez un horodatage dans ce document, vous avez tout ce dont vous avez besoin pour interroger ce document.

Par exemple:

structure du document:

{ "docid" : "doc1", "ts" : <unix epoch> ...<set of key value pairs> } 
fonction de carte

:

function (doc) { 
    if (doc.docid && doc.ts) 
    emit([doc.docid, doc.ts], doc); 
    } 
} 

La vue sera désormais la sortie de chaque document et ses révisions dans l'ordre historique comme ceci:

["doc1", 1234567], ["doc1", 1234568], ["doc2", 1234567], ["doc2", 1234568] 

Vous pouvez utiliser l'affichage de collation et start_key ou end_key pour restreindre les documents renvoyés.

start_key=["doc1", 1] end_key=["doc1", 9999999999999] 

retournera toutes les copies historiques de doc1

start_key=["doc2", 1234567] end_key=["doc2", 123456715] 

renverra toutes les copies historiques de Doc2 entre 1234567 et 123456715 fois d'époque unix.

voir ViewCollation pour plus de détails