3 Stimmen

Beste Methode, um festzustellen, welche Schlüssel im Datenspeicher vorhanden sind

Ich habe ein paar hundert Schlüssel, alle vom gleichen Modell, die ich im Voraus berechnet habe:

candidate_keys = [db.Key(...), db.Key(...), db.Key(...), ...]

Einige dieser Schlüssel beziehen sich auf tatsächliche Entitäten im Datenspeicher, andere nicht. Ich möchte herausfinden, welche Schlüssel den Entitäten entsprechen.

Es ist nicht notwendig, die Daten innerhalb der Entitäten zu kennen, sondern nur, ob sie existieren.

Eine Lösung wäre die Verwendung von db.get():

keys_with_entities = set()
for entity in db.get(candidate_keys):
  if entity:
    keys_with_entities.add(entity.key())

Dieses Verfahren würde jedoch alle Entitätsdaten aus dem Speicher abrufen, was unnötig und kostspielig ist.

Eine zweite Idee ist die Verwendung einer Abfrage mit einer IN anfiltern key_name manuell in 30er-Paketen abrufen, um den Anforderungen der IN Pseudo-Filter. Reine Schlüsselabfragen sind jedoch mit dem IN Filter.

Gibt es einen besseren Weg?

3voto

Nick Johnson Punkte 99799

IN-Filter werden nicht direkt vom App-Engine-Datenspeicher unterstützt; sie sind eine praktische Funktion, die in der Client-Bibliothek implementiert ist. Eine IN-Abfrage mit 30 Werten wird in 30 Gleichheitsabfragen auf jeweils einen Wert übersetzt, was zu 30 regulären Abfragen führt!

Aufgrund der Roundtrip-Zeiten und des Aufwands selbst für reine Schlüsselabfragen werden Sie vermutlich feststellen, dass es am effizientesten ist, einfach zu versuchen, alle Entitäten in einem Batch-Abruf abzurufen. Wenn Ihre Entitäten jedoch groß sind, können Sie eine weitere Optimierung vornehmen: Fügen Sie für jede Entität, die Sie einfügen, eine leere "Präsenz"-Entität als Kind dieser Entität ein, und verwenden Sie diese in Abfragen. Zum Beispiel:

foo = AnEntity(...)
foo.put()
presence = PresenceEntity(key_name='x', parent=foo)
presence.put()
...
def exists(keys):
  test_keys = [db.Key.from_path('PresenceEntity', 'x', parent=x) for x in keys)
  return [x is not None for x in db.get(test_keys)]

0voto

JasonSmith Punkte 70486

Im Moment ist die einzige Lösung, die ich habe, eine manuelle Abfrage nach Schlüssel mit keys_only=True , einmal pro Taste.

for key in candidate_keys:
  if MyModel.all(keys_only=True).filter('__key__ =', key).count():
    keys_with_entities.add(key)

Dies kann in der Tat langsamer sein, als die Entitäten im Stapel zu laden und sie zu verwerfen, obwohl das Stapelladen auch die Data Received from API Quote.

0voto

JasonSmith Punkte 70486

Wie man es nicht machen sollte (Update basierend auf Nick Johnsons Antwort):

Ich denke auch darüber nach, einen Parameter hinzuzufügen, der speziell für die Suche nach diesem Parameter mit einem IN Filter.

class MyModel(db.Model):
  """Some model"""
  # ... all the old stuff
  the_key = db.StringProperty(required=True) # just a duplicate of the key_name

#... meanwhile back in the example

for key_batch in batches_of_30(candidate_keys):
  key_names = [x.name() for x in key_batch]
  found_keys = MyModel.all(keys_only=True).filter('the_key IN', key_names)
  keys_with_entities.update(found_keys)

Der Grund dafür, dass dies vermieden werden sollte, ist, dass der IN-Filter für eine Eigenschaft sequentiell einen Index-Scan durchführt, plus einmaliges Nachschlagen pro Element in Ihrer IN gesetzt. Jede Abfrage dauert 160-200 ms, so dass der Vorgang sehr schnell sehr langsam wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X