Entity groups - consistency, performance

85 views
Skip to first unread message

Petr Voldán

unread,
Mar 4, 2014, 5:02:28 PM3/4/14
to objectify...@googlegroups.com
Hello,
I’d like to avoid some misunderstanding so I’d like to confirm some stuff.
I’m developing some kind of e-commerce for android outdoor app. There is entity UserEntity which keeps reference to all users purchases and downloads.
 
public class UserEntity {
  ...
private ArrayList<String> downloadIds;
private ArrayList<Long> purchaseIds;
  private ArrayList<Long> inAppPurchaseId;
  ...
}

Mentioned list of Ids are entities: Download, Purchase, InAppPurchase that describe user’s activity in e-commerce app. These entities do NOT contain any @Parent reference to UserEntity. I’ve decided for this solution because I was worried in limitation 1 write / sec for entity group (However I read that real value is about 5-10 writes).
On the other hand I need to guarantee consistency of user’s purchases. I’ve read articles about strong consistency in Entity Group, so I guess that described structure is wrong. 

Q1
Should I change the entities: Download Purchase InAppPurchase to ancestor of UserEntity to maintain strong consistency? Is it possible to say how important is the performance impact for writing such type of entity group?

Q2
Entity group is defined per instance. Let’s says  I would have 5 different users. Do they represent five different entity groups? So I will be able to perform more than 1 write/second?

Q3
In case that Purchase entity will be ancestor of UserEntity, what is the best approach for getting all purchases for particular user 
a) ofy().load().type(Purchase.class).ids(ids);
b) ofy().load().type(PurchaseClass).ancestor(userKey).list();

Thank you for suggestions
Petr

Jeff Schnitzer

unread,
Mar 4, 2014, 8:37:32 PM3/4/14
to objectify...@googlegroups.com
It's hard to answer your question without knowing what your query
profile will be like. Do you often need to display all the purchases
of a user? Or are you just hit-testing them?

In my ecommerce systems:

* Yes, purchases are parented by the User entity. There are a lot of
reasons to do this but the most important is that you can get a
strongly consistent view of the purchases of a single user. Thus, the
user never sees an out-of-date list of their purchases.

* I don't include a Set/List of purchases in the User entity. If you
want a list of them, use an ancestor() query. This isn't a super
common use so I don't worry about the cost of it, and if I did, I'd
probably cache the query result rather than trying to put unbounded
collections into the User object. The User object almost always gets
loaded every time (in my case, every single page request or ajax call)
so keeping it svelte is a good idea.

* Don't use primitive types to track entity references. It may be a
tiny bit cheaper than using Key<?> but you lose all type safety and
you *will* screw it up, producing horrible data corrupting bugs when
you confuse a downloadId with a purchaseId somewhere. Or get some
method parameters backwards.

* "One entity group per user" is almost always the right granularity
for an application. Yes, it generally means that a user can't buy more
than one thing per second, download more than one thing per second,
etc. That's rarely an issue. Entity group transaction limits become
painful when you try to do things like track the number of a product
purchased; it's perfectly reasonable for 100 people to purchase the
same product at the same time.

Jeff
> --
> You received this message because you are subscribed to the Google Groups
> "objectify-appengine" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to objectify-appen...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Petr Voldán

unread,
Mar 11, 2014, 4:57:26 AM3/11/14
to objectify...@googlegroups.com
Hi Jeff,

thank you for superior answer. I've changed the structure of entities based on your suggestions. I've also implemented some internal caching system because we need to know user's purchase history every-time he visit the store. We "personalize" items in e-commerce so we can notify user that he has already purchased particular items.

Thank you
Petr
Message has been deleted

Petr Voldán

unread,
Mar 14, 2014, 10:38:44 AM3/14/14
to objectify...@googlegroups.com
Would I have one additional question please? I’d like to create something like directory structure using entity group.

public class RegionEntity {
@Id
String id;
@Parent
private Key<RegionEntity> parent;
//…
}

The question is how to load the top parent entities? Should I create some non-exist key (only key without entity)
Key<RegionEntity> topParentKey = Key.create(RegionEntity.class, “top_parent_region_identificator”);
So this key would be used only as identificator for loading the root entities? 

Jeff Schnitzer

unread,
Mar 14, 2014, 12:10:23 PM3/14/14
to objectify...@googlegroups.com
If you wanted to create a tree structure in a single entity group and
use "uplinks" (instead of "downlinks", ie arrays of children keys), I
would recommend something like this:

public class Region {
@Parent Key<RegionGroup> group; // could be _anything_ but
Region would probably be confusing

@Id String id;
@Index Ref<Region> parent; // maybe call it 'up' to be less confusing
// ...
}

Make sure that all Region entities have the same @Parent entity -
*don't* encode the real tree hierarchy in the key. Always use a
separate non-@Parent indexed field for that. This way you can move
around subtrees arbitrarily; if you encoded the hierarchy in the key
(using @Parents) then moving subtrees would require deleting and
recreating every single node in the subtree.

As far as what the @Parent should be, yes, pick anything. Make up your
own entity class. No, the entity doesn't have to exist, it just has to
have a stable key.

Jeff
> --
> You received this message because you are subscribed to the Google Groups
> "objectify-appengine" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to objectify-appen...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages