views:

76

answers:

3
q = WorldObject.all()
# define boundaries
# left
q.filter('x >=', x)
# right
q.filter('x <', x + width)
# top
q.filter('y >=', y)
# bottom
q.filter('y <', y + height)

#q.filter('world', world_key)

wobjects = q.fetch(1000)

I got an error saying I can't use multiple sorts

q = WorldObject.all()

q.filter('xy >=', db.GeoPt(1, 1))
q.filter('xy <', db.GeoPt(4, 4))

wobjects = q.fetch(1000)

I've found this http://www.spatialdatabox.com/ it might be interesting as it uses the Amazon EC3 for retriving geo data.

this query gives me wrong world objects: with lat=9 why? if i limit between 1 and 4? thanks


Blockquote

+2  A: 

google's datastore indexes are sequential. furthermore, the datastore refuses to satisfy range queries that require more than one index. You can either implement a GiS index on top of the datastore (hard) or just do the range query on one axis and exclude out of range results in your application code (easy).

So if you want to go the hard way, you can get that using geohash

Example of the easy way:

myquery = MyModel.all()
myquery.filter("x >=" x)
myquery.filter("x <" x+delta_x)

resultset = [result for result in myquery.fetch(1000) if y <= result.y < y+delta_y]
TokenMacGuy
Witch one is faster? I think is the geohash, im right?
Totty
They both work in basically the same way, they're probably about equal in terms of speed.
TokenMacGuy
can you give me an example of "just do the range query on one axis and exclude out of range results in your application code (easy)" please? thanks
Totty
thx! but it will be frequent to have more than 1000 world objects between x and x+delta_x. so the filter on y axis will not be that efficient as there will not be all the results.
Totty
so, the result set will be sorted with respect to x, so you can run the query again, bumping the minimum up from that, and keep running the query until it doesn't return any results. If the number of false positives are too high, then you shouldn't use this method.
TokenMacGuy
+2  A: 

App Engine does not currently support the type of querying you are trying to do. Although they have mentioned that a solution is in the works.

But Google does have a nice walk through on how to build something like what you are asking about. Also see one of Nick Johnson's blog posts for some interesting discussion on the general topic.

Robert Kluin
Thanks ;) I've saw the posts but there is any easy implementation just for numbers. If not I will make the numbers / 10000. Is that ok?
Totty
I am not totally sure what you mean by an implementation just for numbers. A geohash-like technique will certainly work for generic numbers; all you are doing is storing progressively less precise pairs of numbers, allowing you to find matches "within a range." What do you mean by make the numbers / 10000?
Robert Kluin
I mean if the x=9 then when I create the object I convert it by dividing it by 10000 or more to get something like that: 0.00009 then this will be saved in the database. Then when I want pixels between 1 and 10, will be pixels between 0.00009 and 0.00010 is that ok?I do that because the numbers Will start from P(0;0) so in geo is GEOPT(0.00001;0.00001)
Totty
First: If you are *not* using latitude and longitude, then don't use GeoPt. It is really just two floats with a little validation on top. Second: The idea behind the geohash approach is that you loose resolution in known ways, allowing you to find other "nearby things." So if you have something at position (1.111, 2.333), you might store (1.11, 2.33) which allows you to find other "things" within the same area. Likewise, if you have something at position (1111, 2333), you might store (1100, 2300). So it is not clear to me what scaling the numbers up or down really gets you.
Robert Kluin
A: 

I got to work it in some way, thanks to GeoModel. What do you think? it might work on large scale? I would like to know how many queries it does under the hood if possible. thanks for all your help:

def get_world_objects_in_area(input):
    try:
        x = input.x
        y = input.y
        width = input.w
        height = input.h
        world_key = input.k
    except:
        return False

    # boundaries
    top = to_map_unit(y)
    bottom = to_map_unit(y-height) # this is "-" because in flash the vertical axis is inverted
    left = to_map_unit(x)
    right = to_map_unit(x+width)

    bounding_box = geo.geotypes.Box(top, right, bottom, left)

    query = WorldObject.all()
    query.filter('world', world_key)

    r = WorldObject.bounding_box_fetch(query,
                                       bounding_box,
                                       max_results=1000)

    return r

def to_map_unit(n):
    if n is not 0:
        divide_by = 1000000000000
        r = Decimal(n) / Decimal(divide_by)
        return float(r)
    else:
        return 0
Totty
If you want to know what is happening under the hood check out Appstats (http://code.google.com/appengine/docs/python/tools/appstats.html).
Robert Kluin