I forgot to mention the most efficient solution:

GAE team provides a way to have composite indexes on unindexed properties.
This way the problem is solved quite elegantly:

Popularity.all(keys_only=True).order('-hourly').ancestor(db.Key.from_path('_DoesNotMatter',
'eu/Sweden')).fetch(N)

For global queries use:

Popularity.all(keys_only=True).order('-hourly').ancestor(db.Key.from_path('_DoesNotMatter',
'world')).fetch(N)

This is even more efficient than my hacky solution with the zillion models
since it would require just a single composite index per property for a
total of 5 indexes per write/update.

- alkis


2010/4/6 Ikai L (Google) <ika...@google.com>

> Well, I'm glad you've done your homework. Have you gone through our
> datastore article series yet?
>
> http://code.google.com/appengine/articles/datastore/overview.html
>
> <http://code.google.com/appengine/articles/datastore/overview.html>Let us
> know how this approach works for you. Could be a very interesting blog post.
>
> 2010/4/6 Alkis Evlogimenos ('Αλκης Ευλογημένος) <evlogime...@gmail.com>
>
> I want to build a popularity metric on a tree of entities. Say my
>> popularity model looks like this:
>>
>> class Popularity(db.Model):
>>   hourly = db.FloatProperty()
>>   daily = db.FloatProperty()
>>   weekly = db.FloatProperty()
>>   monthly = db.FloatProperty()
>>   yearly = db.FloatProperty()
>>
>> Now say I want to aggregate the downloads of a set of files. If I want to
>> do that globally that's easy. Keyname is the filename (or some unique id for
>> each file if names are not unique) and update the counter on each download.
>> When I want the most popular download in the last hour I can query for it
>> easily:
>>
>> Popularity.all(keys_only=True).order('-hourly').fetch(N) for the first N
>> filenames.
>>
>> So far so good, each property has 2 indices (which is overkill I only want
>> only 1).
>>
>> Now lets make the problem a bit more interesting. I want to aggregate
>> globally, but also on each region, country and city. So I need to setup a
>> "tree" of popularity metrics and update them individually. The keys are set
>> as a filenames so I cannot have the same key for all popularities. But I can
>> have an ancestor with keyname being the path down the tree (the entity of
>> the ancestor need not be realized in this case since it is irrelevant
>> anyway). Key for the 'eu' counter will be db.Key.from_path('_DoesNotMatter',
>> 'eu', 'Popularity', <filename>). For eu-Sweden it will
>> be db.Key.from_path('_DoesNotMatter', 'eu/Sweden', 'Popularity', <filename>)
>> and so on. Now I can query for the most popular downloads in Sweden like so:
>>
>> Popularity.all(keys_only=True).order('-hourly').ancestor(db.Key.from_path('_DoesNotMatter',
>> 'eu/Sweden')).fetch(N)
>>
>> But this will require a composite index for (ancestor, hourly, desc). For
>> all hourly, daily, ... queries I will need 5 composite indexes on top of the
>> 10 existing ones for a total of 15 indexes per write/update.
>>
>> The question is how to reduce the number of indexes required to do the
>> above. Since the model name of the popularity class does not matter at all,
>> I came up with the following:
>>
>> eu popularity: db.Key.from_path('Popularity_eu', <filename>)
>> Sweden popularity: db.Key.from_path('Popularity_eu_Sweden', <filename>)
>> global popularity: db.Key.from_path('Popularity', <filename>)
>>
>> This way I can use the following query for top N downloads in Sweden:
>>
>> db.Query('_'.join(['Popularity', 'eu', 'Sweden'],
>> keys_only=True).order('-hourly').fetch(N)
>>
>> This will still require 10 indexes (5 useless ones but still better than
>> 15) to implement but the number of models will be quite large (order of
>> cities in the world).
>>
>> - alkis
>>
>>
>> 2010/4/6 Nick Johnson (Google) <nick.john...@google.com>
>>
>>> Hi Alkis,
>>>
>>>
>>> 2010/4/5 Alkis Evlogimenos ('Αλκης Ευλογημένος) <evlogime...@gmail.com>
>>>
>>> Is there a limit in the number of model kinds per application? I am
>>>> considering a design where the number of models is going to be in the order
>>>> of 500k. I understand the model viewer in the admin console will be
>>>> completely unusable but other than that is there going to be a problem in
>>>> general?
>>>
>>>
>>> No. Other than the admin console datastore viewer likely timing out,
>>> there's no problem with doing this - though I can't think of a reason why
>>> you would actually want to do this, though.
>>>
>>> -Nick
>>>
>>>
>>>>
>>>> If that won't work, is there a plan to make unindexed properties able to
>>>> participate in composite indexes? There are cases where you only want an
>>>> (ancestor, property, descending) index and you do not care about the base
>>>> (property, ascending) and (property, descending) indexes but the current
>>>> design/api forces you to have at least 3 indexes where only 1 would just
>>>> work.
>>>>
>>>> - alkis
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Google App Engine" group.
>>>> To post to this group, send email to google-appeng...@googlegroups.com.
>>>> To unsubscribe from this group, send email to
>>>> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com>
>>>> .
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/google-appengine?hl=en.
>>>>
>>>
>>>
>>>
>>> --
>>> Nick Johnson, Developer Programs Engineer, App Engine Google Ireland Ltd.
>>> :: Registered in Dublin, Ireland, Registration Number: 368047
>>> Google Ireland Ltd. :: Registered in Dublin, Ireland, Registration
>>> Number: 368047
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Google App Engine" group.
>>> To post to this group, send email to google-appeng...@googlegroups.com.
>>> To unsubscribe from this group, send email to
>>> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/google-appengine?hl=en.
>>>
>>
>>  --
>> You received this message because you are subscribed to the Google Groups
>> "Google App Engine" group.
>> To post to this group, send email to google-appeng...@googlegroups.com.
>> To unsubscribe from this group, send email to
>> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/google-appengine?hl=en.
>>
>
>
>
> --
> Ikai Lan
> Developer Programs Engineer, Google App Engine
> http://googleappengine.blogspot.com | http://twitter.com/app_engine
>
> --
> You received this message because you are subscribed to the Google Groups
> "Google App Engine" group.
> To post to this group, send email to google-appeng...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-appengine+unsubscr...@googlegroups.com<google-appengine%2bunsubscr...@googlegroups.com>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-appengine?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To post to this group, send email to google-appeng...@googlegroups.com.
To unsubscribe from this group, send email to 
google-appengine+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to