2011-08-16 3 views
8

J'ai un fichier volumineux (100 millions de lignes de valeurs séparées par des tabulations - environ 1,5 Go de taille). Quelle est la manière la plus rapide de trier ceci en fonction de l'un des champs?tri des données de texte volumineuses

J'ai essayé la ruche. Je voudrais voir si cela peut être fait plus rapidement en utilisant python.

Répondre

16

Avez-vous envisagé d'utiliser le programme * nix sort? en termes bruts, il sera probablement plus rapide que la plupart des scripts Python.

Utilisez -t $'\t' pour spécifier qu'il est séparé par des tabulations, -k n pour spécifier le champ, où n est le numéro de champ et -o outputfile si vous voulez afficher le résultat dans un nouveau fichier. Exemple:

sort -t $'\t' -k 4 -o sorted.txt input.txt 

triera input.txt sur son 4ème champ et sortie le résultat à sorted.txt

+0

la commande de tri unix est en effet un outil très puissant. Vous pouvez contrôler le format du champ à trier (numérique, date, etc.) et la quantité de mémoire que le programme peut allouer, en effectuant un tri split + fusion si nécessaire. –

+0

alex pouvez-vous donner un exemple? Le programme de tri à lui seul prend beaucoup de temps ... de l'ordre de 40 minutes. Cela peut avoir quelque chose à voir avec l'allocation de mémoire ou l'E/S du disque. Je ne suis pas sûr de savoir quel est le goulot d'étranglement, mais je suppose que votre suggestion pourrait être utile. – fodon

+1

une erreur dans la solution ci-dessus: pour utiliser uniquement le 2ème champ, il faut -k 2,2 ... donc ce n'est pas zéro indexé (du moins pas sur la version de Kubuntu 11.04 du tri). – fodon

1

Je stocker le fichier dans une bonne base de données relationnelle, l'indexer sur le terrain qui vous intéresse et puis lire les articles commandés.

7

vous voulez construire un index en mémoire du fichier:

  1. créer une liste vide
  2. open le fichier
  3. lecture ligne par ligne (en utilisant f.readline(), et stocker dans la liste un tuple composé de la valeur sur laquelle vous voulez trier (extrait avec line.split('\t').strip()) et le décalage de la ligne dans le fichier (que vous pouvez obtenir en appelant f.tell() avant d'appeler f.readline())
  4. close le fichier
  5. sort la liste

Ensuite, pour imprimer le fichier triée, ouvrez à nouveau le fichier et pour chaque élément de votre liste, utilisez f.seek(offset) pour déplacer le pointeur de fichier au début de la ligne, f.readline() à lire la ligne et print la ligne. Optimisation: vous pouvez stocker la longueur de la ligne dans la liste, de sorte que vous pouvez utiliser f.read(length) dans la phase d'impression.

Exemple de code (optimisé pour une meilleure lisibilité, pas la vitesse):

def build_index(filename, sort_col): 
    index = [] 
    f = open(filename) 
    while True: 
     offset = f.tell() 
     line = f.readline() 
     if not line: 
      break 
     length = len(line) 
     col = line.split('\t')[sort_col].strip() 
     index.append((col, offset, length)) 
    f.close() 
    index.sort() 
    return index 

def print_sorted(filename, col_sort): 
    index = build_index(filename, col_sort) 
    f = open(filename) 
    for col, offset, length in index: 
     f.seek(offset) 
     print f.read(length).rstrip('\n') 

if __name__ == '__main__': 
    filename = 'somefile.txt' 
    sort_col = 2 
    print_sorted(filename, sort_col) 
3

subdivisée en types de fichiers qui peuvent être triés en mémoire. Triez chaque fichier en mémoire. Puis fusionnez les fichiers résultants.

Fusionnez en lisant une partie de chacun des fichiers à fusionner. La même quantité de chaque fichier laissant suffisamment d'espace en mémoire pour le résultat fusionné. Une fois fusionné en sauvegardant ceci. Répéter l'ajout de blocs de données fusionnées dans le fichier.

Ceci minimise l'entrée/sortie des fichiers et déplace le fichier sur le disque.

Questions connexes