2017-12-23 6 views
1

ich mit einem Queryset von mehr als 5 Millionen + Artikel (für Batch-ML Zwecke) zu tun habe, und ich muss die queryset gespalten (so kann ich die Multithreading-Operationen durchführen) ohne die queryset zu Auswertung wie ich nur je brauchen Um auf jedes Element in dem Abfrage-Set einmal zuzugreifen, und so möchte ich nicht die Abfrage-Set-Elemente zwischenspeichern, die das Auswerten verursacht.Wie teilen Sie ein Django-Abfrage-Set auf, ohne es zu bewerten?

Ist es möglich, die Elemente in einem Abfrage-Set auszuwählen und dieses ohne Auswertung zu teilen? oder muss ich mich an sie wenden, indem ich mit Limits [: size] nach mehreren Abfragegruppen suche, um dieses Verhalten zu erreichen?

NB: Ich bin mir bewusst, dass ein Iterable kann es ohne die Bewertung durch einen queryset zu Zyklus verwendet werden, aber meine Frage ist damit zusammen, wie ich kann ich eine queryset geteilt (wenn möglich), um dann eine iterable auf jedem laufen die geteilten Abfragesätze.

+1

Können Sie darüber iterieren und lassen Sie die Worker-Threads abholen? Nur so kann ich mir vorstellen, dass es mit einer einzigen Abfrage über Django funktioniert. (Ziemlich viel nur einen threadsicher Iterator herumreichen.) – Ryan

+1

Eine Django-Abfrage wird nicht ausgewertet, bis sie eine forcierende Auswertung trifft. Und es kann geschnitten werden. MyQuery [1000: 11000] würde Ihnen also einen Teil der Abfrage sehr sauber geben. Und nein, es bewertet nicht die ganze Sache, um diese Scheibe zu bekommen. –

Antwort

4

Django bietet ein paar Klassen, die Sie paginierte Daten verwalten helfen - das heißt, Daten, die sich über mehrere Seiten aufgeteilt ist, mit „Zurück/Weiter“ Links:

from django.core.paginator import Paginator 

object_list = MyModel.objects.all() 
paginator = Paginator(object_list, 10) # Show 10 objects per page, you can choose any other value 

for i in paginator.page_range(): # A 1-based range iterator of page numbers, e.g. yielding [1, 2, 3, 4]. 
    data = iter(paginator.get_page(i)) 
    # use data 
+1

Ich glaube für mein Problem scheint der Paginator die beste Lösung, Prost für die Hilfe! N.B .: für jeden, der die Artikel einer Seite liest, wird nicht bewertet, bis angefordert, d. H. Faule Bewertung – bmjrowe

1

Ja, Sie können, wie aus dieser gist

Per aktualisierten Antwort:

def queryset_iterator(queryset, chunk_size=1000): 
""" 
Iterate over a Django Queryset ordered by the primary key 
This method loads a maximum of chunk_size (default: 1000) rows in it's 
memory at the same time while django normally would load all rows in it's 
memory. Using the iterator() method only causes it to not preload all the 
classes. 
Note that the implementation of the iterator does not support ordered query sets. 
""" 
    try: 
     last_pk = queryset.order_by('-pk')[:1].get().pk 
    except ObjectDoesNotExist: 
     return 

    pk = 0 
    queryset = queryset.order_by('pk') 
    while pk < last_pk: 
     for row in queryset.filter(pk__gt=pk)[:chunk_size]: 
      pk = row.pk 
      yield row 
     gc.collect() 
1

Passing Abfrage setzt auf Themen Ich würde es nicht empfehlen. Ich kenne die Art der Sache, die Sie versuchen, und warum, aber es ist am besten, nur eine Art von Parametersatz an jeden Thread zu übergeben und dann den Thread die Teilabfrage durchführen zu lassen. Auf diese Weise unterscheiden sich Ihre Threads vom aufrufenden Code.

Wenn Sie versuchen, Threads als eine Arbeit für die Verzögerungen zu verwenden, die von hohen DB-Abfragen verursacht werden, finden Sie möglicherweise eine bessere Route mithilfe der Transaktionsverwaltung. Dieser Link link hat einige nützliche Tipps. Ich benutze dies anstelle von Threads

Verwandte Themen