2010-01-09 3 views
4

J'ai deux groupes de fichiers qui contiennent des données au format CSV avec une clé commune (Timestamp) - J'ai besoin de parcourir tous les enregistrements chronologiquement.Lecture synchronisée Python de fichiers triés

  • Groupe A: 'données sur l'environnement'

    • Les noms de fichiers sont au format A_0001.csv, A_0002.csv, etc.
    • croissant prétriés
    • Key est Horodatage, ieYYYY-MM-DD HH: MM: SS
    • Contient des données environnementales en format CSV/colonne
    • Très grand e, plusieurs données de valeur GBs
  • Groupe B: 'Données de l'événement'

    • noms de fichiers sont en format B_0001.csv, B_0002.csv
    • croissant pré-trié
    • La clé est l'horodatage, c'est-à-dire AAAA-MM-JJ HH: MM: SS
    • Contient des données basées sur les événements au format CSV/colonne
    • Relativement petite l par rapport aux fichiers du groupe A, < 100 MB

Quelle est la meilleure approche?

  • pré-fusion: Utilisez l'une des différentes recettes là-bas pour fusionner les fichiers en une seule sortie triée, puis le lire pour le traitement
  • fusion en temps réel: Mettre en œuvre le code pour « fusion 'les fichiers en temps réel

Je vais exécuter beaucoup d'itérations du côté post-traitement des choses. Des pensées ou des suggestions? J'utilise Python.

+0

Les numéros de fichier A et B correspondent-ils les uns aux autres? –

+0

Y at-il un fichier B pour chaque fichier A et vice versa? Tous les horodatages du fichier X_000i.csv sont-ils plus anciens que tous les horodatages du fichier X_000j.csv pour X dans (A, B) et i

+0

Il existe plusieurs centaines de fichiers du groupe A et seulement quelques fichiers du groupe B. Les données/enregistrements de chaque type de fichier sont aléatoires en termes de distribution des enregistrements dans le temps. Cependant, le groupe A a une très grande population d'enregistrements et, en tant que tel, chaque cachet est généralement couvert, mais les enregistrements du groupe B sont beaucoup plus petits en nombre, de sorte que les enregistrements sont largement dispersés. – belvoir

Répondre

0

Je suggérerais avant la fusion.

La lecture d'un fichier prend beaucoup de temps processeur. Lecture de deux fichiers, deux fois plus. Puisque votre programme traitera avec une grande entrée (beaucoup de fichiers, en particulier dans le groupe A), je pense qu'il vaudrait mieux en finir avec dans un fichier lu, et avoir toutes vos données pertinentes dans ce fichier. Cela réduirait également le nombre de variables et d'instructions dont vous aurez besoin.

Cela permettra d'améliorer l'exécution de votre algorithme, et je pense que c'est une raison suffisante dans ce scénario de décider d'utiliser cette approche

Hope this helps

2

im pensant l'importer dans un db (mysql , sqlite, etc) donnera de meilleures performances que la fusion dans un script. la base de données a généralement des routines optimisées pour le chargement de csv et la jointure sera probablement aussi rapide ou beaucoup plus rapide que la fusion de 2 dicts (l'un étant très grand) en python.

+0

J'y avais pensé mais nous parlons des niveaux d'enregistrements de l'entrepôt de données. Au total, j'ai plus de 100 Go de données (millions et millions d'enregistrements). Peut-être que j'étais trop rapide pour le rejeter mais je pensais que l'utilisation d'un db pour faire une fusion/tri pourrait être faite plus rapidement/élégamment dans Python en considérant la mise en place de fichiers/enregistrements. – belvoir

0

Vous pouvez lire à partir des fichiers en morceaux de, disons, 10000 enregistrements (ou tout autre nombre de profilage vous dit d'être optimal) et fusionner à la volée. Peut-être en utilisant une classe personnalisée pour encapsuler les E/S; les enregistrements réels pourraient alors être accédés par l'intermédiaire du protocole de générateur (__iter__ + next). Ceci serait facile à mémoriser, probablement très bon en termes de temps total pour terminer l'opération et vous permettrait de produire une sortie de façon incrémentielle.

Un croquis:

class Foo(object): 

    def __init__(self, env_filenames=[], event_filenames=[]): 
     # open the files etc. 

    def next(self): 
     if self._cache = []: 
      # take care of reading more records 
     else: 
      # return the first record and pop it from the cache 

    # ... other stuff you need ... 
2

"AAAA-MM-JJ HH: MM: SS" peut être triée avec un simple ascii comparer. Pourquoi ne pas réutiliser la logique de fusion externe? Si le premier champ est la clé, alors:

for entry in os.popen("sort -m -t, -k1,1 file1 file2"): 
    process(entry) 
1

Ceci est similaire à une jointure relationnelle. Comme vos horodatages n'ont pas à correspondre, cela s'appelle un non-équijoin. Sort-Merge est l'un des nombreux algorithmes populaires. Pour les non-équijoins, cela fonctionne bien. Je pense que ce serait ce que vous êtes appelé "pré-fusion". Je ne sais pas ce que vous voulez dire par "fusionner en temps réel", mais je pense que c'est toujours une simple fusion-tri, qui est une bonne technique, très utilisée par de vraies bases de données.

Les boucles imbriquées peuvent également fonctionner. Dans ce cas, vous lisez la plus petite table de la boucle externe. Dans la boucle interne, vous trouverez toutes les lignes "correspondantes" de la plus grande table. C'est effectivement une sorte de fusion, mais avec l'hypothèse qu'il y aura plusieurs lignes de la grande table qui correspondra à la petite table. Ceci, BTW, vous permettra d'attribuer plus correctement la signification à la relation entre les données d'événement et les données environnementales. Plutôt que de lire le résultat d'une fusion de tri massive et d'essayer de déterminer quel type d'enregistrement vous avez, les boucles imbriquées gèrent bien cela.

De même, vous pouvez faire des recherches dans la petite table tout en lisant la plus grande table.

Ceci est difficile lorsque vous effectuez des comparaisons non égales car vous n'avez pas de clé appropriée pour effectuer une extraction simple à partir d'une dict simple. Toutefois, vous pouvez facilement étendre dict (remplacer __contains__ et __getitem__) pour effectuer des comparaisons de plage sur une clé au lieu de simples tests d'égalité.