2012-02-16 10 views
7

Jestem dość nowy zobiektywizować, a miałem szybkie pytanie do najlepszy sposób, aby coś zrobić:Objectify Relationships: One-to-Many, Czy mogę to zrobić wydajnie?

powiedzmy, że mam aplikację, która pozwala ludziom na wysyłanie i odbieranie wiadomości (myślę e-mail prostota). Gdy aplikacja się ładuje, nie chcę, aby jedna wiadomość z każdego kontaktu, który jest , wysłała wiadomość do danego użytkownika. To byłoby marnotrawstwo. Zamiast tego chcę załadować wszystkie kontakty, z których użytkownik ma wiadomości z (odczyt lub nieprzeczytane), aby wyświetlić listę kontaktów w mojej aplikacji , a gdy użytkownik kliknie na dany kontakt, chcę załaduj wszystkie wiadomości z tego kontaktu, aby wyświetlić je użytkownikowi.

Nie mogę znaleźć dobrego sposobu na zrobienie tego bez załadowania wszystkich wiadomości dla konta. Czytam wiki Objectify w relacjach wiele do jednego i nadal nie mogę myśleć o dobrym sposobem na zrobienie tego, co nie jest wyjątkowo nieefektywne. Wyglądałoby to tak, jak zaleca strona objectify, że musiałbym załadować wszystkie wiadomości dla danego użytkownika, a następnie przeanalizować je pod kątem unikalnych kontaktów.

Próbuję użyć jako mało App Engine Czyta i pisze, jak to możliwe, a gdzie możliwe Próbuję użyć Smalls zamiast Odsłon (ogólny koszt uruchomić mój app jest wielkim problemem kopalni chwilę Robię to).

Na Objectify, jak mam to robić?

Odpowiedz

11

ten jest kopiowany z mojej odpowiedzi na zobiektywizować-interfejsu App Engine grupy dyskusyjne: https://groups.google.com/forum/?fromgroups#!topic/objectify-appengine/LlOyRJZRbnk

Istnieją trzy główne opcje gdy mamy do czynienia z „danych agregacji” jak to, co można opisać:

1) Oblicz ją, kiedy jej potrzebujesz

Uznałeś, słusznie, że jest to zbyt kosztowne.

2) Oblicz go w odstępach wsadowych i przechowywać ten wynik

Nie bardzo satysfakcjonujące, gdyż wiąże się z opóźnieniem. Poza tym nie chcesz codziennie przeczesywać całej bazy danych.

3) Aktualizacja agregację gdy dane zmienia

Takie podejście wymaga trochę więcej pracy przy każdej zmianie danych, ale jest to prawie na pewno to, co chcesz robić.

Utwórz kolekcję kontaktów dla każdego użytkownika. Po nadejściu wiadomości upewnij się, że kontakt nadawcy istnieje dla tego odbiorcy. Może chcesz również usunąć kontakt, gdy odbiorca usunie ostatnią wiadomość od nadawcy.

Należy uważać, aby nie przekroczyć limitów transakcji dla grup jednostek (jeden zapis na sekundę).Odprowadzę cię przez kilka opcji:

1) mógłby przechowywać listę kontaktów w każdej odbiorcy:

class Person { 
    @Id Long id; 
    Set<Key<Person>> contacts; 
} 

Byłby to wyraźny problem, jeśli, powiedzmy, odbiorca otrzymał wiadomość od 20 nowy ludzie naraz. To prawie na pewno zły pomysł. Z drugiej strony jest niesamowicie szybki i skuteczny, aby sprawdzić, kim są twoje kontakty. Niewielka poprawa byłoby przenieść to do odrębnego podmiotu wychowywane przez osobę, więc nie zawsze ładuje te dane:

class Contacts { 
    @Parent Key<Person> owner; 
    @Id long id = 1; // there's only ever one of these per person, and it should have a predictable key for fetching 
    Set<Key<Person>> contacts; 
} 

Oczywiście, mieszczący się w jedną całość daje limit 50.000 wejścia. Może być nieco mniejsza niż ta, jeśli najpierw przekroczysz limit wielkości jednostki 1M. Jeśli twoje klucze mają ~ 20 znaków, będzie mniej więcej tak samo. Jeśli jest to problem, możesz zezwolić na wiele jednostek Kontakty, w którym to momencie masz coś podobnego do Wzorca Podmiotu Relacji z Bretta Slatkina z Google 2009: http://www.youtube.com/watch?v=AgaL6NGpkB8

2) Możesz zapisać listę kontaktów w innym kierunku

class Person { 
    @Id Long id; 
    @Index Set<Key<Peson>> contactOf; 
} 

to sprawia, że ​​jest to nieco droższe, aby dowiedzieć się, kto kontakty są - trzeba tylko klucze zapytania, a nie klucza get-by-proste. Ale nie jesteś tak naprawdę ograniczony stopniem zapisu jednostki. Ludzie prawdopodobnie nie wysyłają więcej niż jednej wiadomości na sekundę, a jeśli wysyłają masowo 1000 wiadomości, można zaktualizować dane kontaktowe w pojedynczej transakcji.

Jak wyżej, prawdopodobnie chcesz przenieść ten wskaźnik do odrębnego podmiotu:

class Contacts { 
    @Parent Key<Person> person; 
    @Id long id = 1; // there's only ever one of these per person, and it should have a predictable key for fetching 
    Set<Key<Person>> of; 
} 

3) Można również zapisać te kontakty w zupełnie odrębny podmiot

class Contact { 
    @Parent Key<Person> person; 
    @Id Long id; 
    @Index Key<Person> owner; 
} 

To jest naprawdę mniej wydajny pod względem przestrzeni sposób rozwiązania # 2.

Ważne jest, aby aktualizować tę strukturę, gdy wszystkie wiadomości są wysyłane lub odbierane.

+0

Dziękujemy za kompleksową odpowiedź. Zadaję pytania uzupełniające w grupie google-appengine. – spierce7

+0

Jest to limit 5 000, a nie 50 000 - prawdopodobnie literówka. – gswierczynski