2016-09-22 3 views
2

Je traite des tables ayant jusqu'à quelques milliards de lignes et je fais beaucoup de recherches "where(numexpr_condition)" en utilisant pytables.Limiter le nombre de lignes renvoyées par `.where (...)` dans pytables

Nous avons réussi à optimiser le format HDF5 de sorte qu'une simple requête sur plus de 600 millions de lignes se fait sous 20s (nous avons encore du mal à trouver comment accélérer cela, mais c'est une autre histoire).

Cependant, étant donné qu'il est encore trop lent pour jouer autour, je besoin d'un moyen de limiter le nombre de résultats dans une requête comme dans cet exemple simple (la colonne foo est évidemment indexé):

[row['bar'] for row in table.where('(foo == 234)')] 

Donc, cela reviendrait à dire 100mio entrées et il faut 18s, ce qui est lent à prototyper et à jouer.

Comment voulez-vous limiter le résultat à 10000 permet de dire?

La base de données comme requête équivalente serait à peu près:

SELECT bar FROM row WHERE foo==234 LIMIT 10000 

En utilisant l'attribut stop= est pas le chemin, car il faut simplement les premières lignes n et applique la condition pour eux. Donc, dans le pire des cas, si la condition est pas remplie, je reçois un tableau vide:

[row['bar'] for row in table.where('(foo == 234)', stop=10000)] 

Utiliser tranche sur la compréhension de la liste est pas non plus dans le bon sens, car il va d'abord créer le tableau entier et appliquer ensuite la tranche , ce qui est bien sûr aucun gain de vitesse à tous:

[row['bar'] for row in table.where('(foo == 234)')][:10000] 

Cependant, l'itérateur doit connaître sa propre taille alors que l'épuisement de la compréhension de la liste donc il y a sûrement un moyen de pirater ensemble. Je ne pouvais pas trouver un moyen approprié de le faire.

Btw. J'ai aussi essayé d'utiliser zip et range pour forcer un StopIteration:

[row['bar'] for for _, row in zip(range(10000), table.where('(foo == 234)'))] 

Mais cela m'a donné des chiffres répétés de la même ligne.

+1

Est-ce que 'itertools.islice (table.where ('(foo == 234)'), 10000)' fonctionne? – Ryan

+0

J'ai eu une approche similaire en utilisant 'zip (plage (10000), table.where (...)', mais le résultat est étrange mais, votre solution fonctionne;.) Pourriez-vous ajouter comme une réponse? – tamasgal

Répondre

1

Comme il est un itérables et semble produire des lignes à la demande, vous devriez être en mesure d'accélérer avec itertools.islice.

rows = list(itertools.islice(table.where('(foo == 234)'), 10000)) 
+0

Merci pour ça! Il serait très agréable d'avoir ceci intégré dans 'table' comme par exemple un paramètre' limit';) Besoin de créer une requête de pull je suppose ... – tamasgal