Frage

Ich versuche, eine GQL Abfrage zu schreiben, die N zufällige Datensätze einer bestimmten Art zurückgibt. Meine aktuelle Implementierung arbeitet aber erfordert N auf den Datenspeicher aufruft. Ich mag es 1 Aufruf an den Datenspeicher, wenn möglich machen.

I zuweisen derzeit eine Zufallszahl auf jede Art, die ich in den Datenspeicher setzen. Wenn ich für einen zufälligen Datensatz Abfrage generieren ich eine andere Zufallszahl und Abfrage für Datensätze> rand ORDER BY ASC LIMIT 1.

Das funktioniert aber es gibt nur 1 Datensatz so I N-Abfragen müssen tun. Alle Ideen, wie diese eine Abfrage zu machen? Danke.

War es hilfreich?

Lösung

„Unter der Haube“ ein einzelne Suchabfrage Anruf kann nur eine Reihe von aufeinander folgenden Zeilen aus irgendeinem Index zurück. Aus diesem Grund einige GQL Abfragen, einschließlich der Verwendung von! =, Um mehrere Datenspeicher Anrufe erweitern.

N unabhängige einheitliche Zufallsauswahlen sind nicht (im Allgemeinen) in Folge in einem Index.

QED.

Sie könnten wahrscheinlich memcache verwenden, um die Einheiten zu speichern und reduzieren die Kosten für Grabbing N von ihnen. Oder wenn Sie die „random“ Auswahlen nichts dagegen nahe beieinander in dem Index ist, wählen Sie einen zufällig gewählten Block von (sagen wir) 100 in einer Abfrage, dann wählen N zufällig aus diesen. Da Sie ein Feld haben, die bereits randomisiert ist, wird es nicht sofort für einen Außenstehenden klar sein, dass die N Artikel in Zusammenhang stehen. Zumindest nicht, bis sie sehen eine Menge von Proben und beachten Sie, dass Gegenstände A und Z nie in der gleichen Gruppe erscheinen, weil sie mehr als 100 auseinander in dem randomisierten Index ist. Und wenn die Leistung zulässt, können Sie Ihre Einheiten von Zeit zu Zeit neu randomisieren.

Andere Tipps

Welche Art von Kompromissen suchen Sie? Wenn Sie bereit sind, mit einer kleinen Leistung beim Einsetzen dieser Einheiten getroffen zu setzen, können Sie eine Lösung erstellen N von ihnen zu bekommen sehr schnell.

Hier ist, was Sie tun müssen:

Wenn Sie Ihre Entities einfügen, den Schlüssel angeben. Sie wollen Schlüssel zu Ihrem Unternehmen, um geben, beginnend mit 1 und von dort hinauf. (Dies wird einige Anstrengungen erfordern, wie App Engine nicht autoincrement hat (), so müssen Sie den Überblick über die letzten id, um Sie in einem anderen Unternehmen verwendet werden, nennen wir es eine IdGenerator)

Wenn Sie nun N zufällige Einheiten benötigen, erzeugen N Zufallszahlen zwischen 1 und was auch immer der letzte id Sie war erzeugt (Ihre IdGenerator dies wissen). Anschließend können Sie eine Charge von Schlüsseln mit dem N Schlüssel erhalten tun, die nur eine Reise in die Datenspeichern benötigen, und wird schneller sein als eine Abfrage als auch, da Schlüssel sind in der Regel schneller als Anfrage bekommen, AFAIK.

Diese Methode erfordert mit ein paar lästigen Details beschäftigen:

  1. Ihr IdGenerator könnte zu einem Engpass werden, wenn Sie viele dieser Elemente on the fly (mehr als ein paar Sekunden) einfügen, die eine Art von sharded IdGenerator Implementierung erfordern würde. Wenn alle diese Daten vorgespannt ist, oder nicht hochvolumige, haben Sie es einfach.
  2. Sie können feststellen, dass einige Id nicht wirklich eine Einheit mit ihm mehr verknüpft haben, weil Sie sie gelöscht oder weil eine Put () fehlgeschlagen irgendwo. Wenn dies geschehen würde Sie eine andere zufällige Einheit greifen müssen. (Wenn Sie wollten Lust bekommen und reduzieren die Wahrscheinlichkeit von dieser Sie diese ID dem IdGenerator zur Verfügung stellen könnte, um die Wiederverwendung zu „füllen die Löcher“)

Die Frage kommt darauf an, wie schnell müssen Sie diese N Artikel vs wie oft Sie sie werden das Hinzufügen und Löschen, und ob ein wenig zusätzliche Komplexität ist, dass Leistungssteigerung wert.

Sieht aus wie die einzige Methode ist durch den Zufall ganzzahligen Wertes Speicherung in jedem speziellen Eigenschaft des Unternehmens und die Abfrage, dass auf. Dies kann ganz automatisch erfolgen, wenn Sie nur eine automatisch initialisiert Eigenschaft hinzuzufügen.

Leider Verarbeitung aller Einheiten erfordert dies sofort, wenn der Datenspeicher bereits ausgefüllt ist.

Es ist komisch, ich weiß.

ich auf die Antwort von Steve einverstanden sind, gibt es keine solche Art und Weise N zufällige Zeilen in einer Abfrage.

abrufen

Aber auch das Verfahren eine einzige Einheit des Abrufens der Regel nicht so arbeiten, dass der prbability der zurückgegebenen Ergebnisse gleichmäßig verteilt. Die Wahrscheinlichkeit, eine bestimmte Einheit zurückkehrt, hängt von der Lücke davon zufällig zugewiesen wird Nummer und die nächsthöhere Zufallszahl. Z.B. Wenn Zufallszahlen 1,2 und 10 zugewiesen wurden (und keine der Nummern 3-9), wird der Algorithmus zurück „2“ 8 mal häufiger als „1“.

Ich habe dieses Problem behoben in einer etwas expensice Art und Weise. Wenn jemand interessiert ist, ich bin zu teilen glücklich

Ich hatte gerade das gleiche Problem. Ich beschloss, nicht-IDs zu meinen bereits vorhandenen Einträge in Datenspeicher zuweisen und tat dies, wie ich schon die totalcount von einem sharded Zähler hatte.

Diese wählt "count" Einträge aus "totalcount" Einträge, sortiert nach Taste .

    # select $count from the complete set
    numberlist = random.sample(range(0,totalcount),count)
    numberlist.sort()

    pagesize=1000

    #initbuckets
    buckets = [ [] for i in xrange(int(max(numberlist)/pagesize)+1) ]
    for k in numberlist:
        thisb = int(k/pagesize)
        buckets[thisb].append(k-(thisb*pagesize))
    logging.debug("Numbers: %s. Buckets %s",numberlist,buckets)

    #page through results.

    result = []
    baseq =  db.Query(MyEntries,keys_only=True).order("__key__")
    for b,l in enumerate(buckets):
        if len(l) > 0: 
            result += [ wq.fetch(limit=1,offset=e)[0] for e in l ]

        if b < len(buckets)-1: # not the last bucket
            lastkey  = wq.fetch(1,pagesize-1)[0]
            wq = baseq.filter("__key__ >",lastkey)

Beachten Sie, dass mir diese etwas komplex ist, und ich bin immer noch nicht conviced, dass ich off-by-one nicht oder off-by-x Fehler.

Und passen Sie auf, wenn Zählung der Nähe ist dies sehr teuer sein kann Totalcount. Und passen Sie auf, auf Millionen von Zeilen, die es nicht möglich wäre, innerhalb appengine Zeitgrenzen zu tun.

Wenn ich richtig verstehe, müssen Sie N zufällige Instanz abgerufen werden.

Es ist einfach. Nur nicht nur mit Schlüssel abfragen. Und tut random.choice N-mal auf der Liste Ergebnis von Schlüsseln. Dann Ergebnisse erhalten, indem Sie auf Tasten abgerufen werden.

keys = MyModel.all(keys_only=True)

n = 5 # 5 random instance

all_keys = list(keys)
result_keys = []

for _ in range(0,n) 
    key = random.choice(all_keys)
    all_keys.remove(key)
    result_keys.append(key)

# result_keys now contain 5 random keys.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top