Frage

Ich habe ein paar hundert Tasten, die alle vom gleichen Modell, das ich vorher berechnet:

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

Einige dieser Tasten beziehen sich auf tatsächliche Entitäten im Datenspeicher, und manche nicht. Ich möchte, um zu bestimmen, welche Tasten zu Entitäten tun entsprechen.

Es ist nicht notwendig, die Daten innerhalb der Einheiten zu wissen, nur ob sie vorhanden sind.

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

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

Allerdings würde dieses Verfahren alle Objektdaten aus dem Speicher holen, die unnötig und teuer ist.

Eine zweite Idee ist, eine Abfrage mit einem Filter auf IN key_name zu verwenden, manuell in Stücken von 30 Holen der Anforderungen des IN pseudo-Filters passen. Allerdings Schlüssel-only-Abfragen sind nicht mit dem IN Filter erlaubt.

Gibt es einen besseren Weg?

War es hilfreich?

Lösung

IN-Filter werden nicht direkt von der App Engine-Datenspeicher unterstützt; sie sind eine Bequemlichkeit, die in der Client-Bibliothek implementiert wird. Eine IN-Abfrage mit 30 Werten wird jeweils auf einem Wert in 30 Gleichheit Abfragen übersetzt, was in 30 regelmäßigen Abfragen!

Durch Umlaufzeiten und Kosten selbst Schlüssel-only-Abfragen, vermute ich, Sie werden feststellen, dass einfach finden zu versuchen alle Einheiten in einer Charge zu holen holen ist die effizienteste. Wenn Ihre Entitäten groß sind, können Sie jedoch eine weitere Optimierung machen: Für jedes Objekt, das Sie einfügen, legen Sie eine leere ‚Präsenz‘ Einheit als Kind dieser Einheit, und verwendet, die 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)]

Andere Tipps

An diesem Punkt ist die einzige Lösung, die ich habe, ist die manuelle Abfrage durch 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 nur die Entitäten im Batch-Laden und verwirft sie, obwohl die Verlade- auch die Data Received from API Quote hämmert.

Wie nicht, es zu tun (Update basiert auf Nick Johnson Antwort):

Ich erwäge auch speziell für diesen Zweck in der Lage zu scannen für sie mit einem IN Filter einen Parameter hinzuzufügen.

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, dies sollte vermieden werden, dass die IN-Filter auf einer Eigenschaft führen sequentiell einen Index-Scan plus Nachschlag einmal pro Element in Ihrem IN Set. Jede Lookup nimmt 160-200ms so dass sehr schnell ein sehr langsamer Vorgang wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top