Friday, July 30, 2010

Re: Re: Best way to find near people

A couple of possible optimizations:

First, because cos is single valued over the range of possible angles
(as measured
from the center of the earth, 0 <= d <= PI) distance is monotonic with
cos distance.
So you can pre-calculate the cos of the distance, and compare the
innder expression
to that:

th = cos(near_value_in_km / 6378.137)

Also, pre-calculate lat as radians, sin of long, and cos of long, so
that there's no
chance that the database will perform these calculations once per row
as opposed to
once per query. Then:

(cos_long * cos(radians(lattitude)) * cos(radians(longitude) -
rad_lat) + sin_long * sin(radians(latitude) > th

(Yes, greater than. Cos is max, +1, at minimum distance.)

Far fewer trig functions per row.

And if you're willing to denormalize, storing latitude as both its sin
and cos, and longitude
as its cos (possibly, further denormalization, also storing the
original degree values to
avoid dancing low order decimals in the UI), then you only need one
trig functionper row.
If you arrange to return the expression, you don't even have to
recalculate it on the python
side to get actual distance, if desired, for the items that are close
enough (take acos and
multiply by earth radius).

Note that you can still sort on cos(distance) in the DB if you're
interested in, for example,
a closest first presentation.

Applying the bounding box first means that you can avoid even that one
cos for items that
are outside the bounding box.

On Fri, Jul 30, 2010 at 4:06 AM, Henrik Genssen
<henrik.genssen@miadi.net> wrote:
> I use .extra(where=[where])
>
> and something like this (measures km, not miles):
> ( 6378.137 * acos( cos( radians(long) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(lat) ) + sin( radians(long) ) * sin( radians( latitude ) ) ) ) < 10
>
> latitude and logitude are db-fields, 6378.137 the radius of the earth, long/lat my current position, searches for objects in a 10 km circle
>
> regards
>
> Henrik
>
>
>>reply to message:
>>date: 30.07.2010 07:30:30
>>from: "Jani Tiainen" <redetin@gmail.com>
>>to: django-users@googlegroups.com
>>subject: Re: Best way to find near people
>>
>>> On Jul 29, 2010, at 2:58 PM, Alexandre González wrote:
>>> > Hi!
>>> >
>>> > I'm searching near people in my app. I'm doing it a this way:
>>> >
>>> > 37             people = Person.objects.all().exclude(user=request.user)
>>> > 38
>>> > 39             near_people = list()
>>> > 40             for person in people:
>>> > 41                 if self.is_near(me.coordinates, person.coordinates):
>>> > near_people.append(person)
>>> >
>>> > Now, I'm getting all the the Person objects. This is a inefficient way.
>>> >
>>> > The coordinates are latitude/longitude coordinates, so I think in test
>>> > the variation and get only latitude +/- 1 and longitude +/- 1 and after
>>> > this, do the test exactly (the funcion is_near).
>>> >
>>> > But instead this, can I "draw" a circle and search only Person objects
>>> > inside it?
>>>
>>> I'm not sure what database you are using, but if you are using PostgreSQL,
>>> it has built-in geometric operators specifically for this kind of thing.
>>> You might have to drop down into SQL, but in 1.2, that's nice and easy.
>>>
>>> The PostgreSQL documentation on this is at:
>>>
>>>      http://www.postgresql.org/docs/8.4/interactive/datatype-geometric.html
>>> --
>>> -- Christophe Pettus
>>>    xof@thebuild.com
>>
>>Or if spatial operations are really needed, why not to use real spatial
>>database and GeoDjango (django.contrib.gis). Spatialite, Postgis, Mysql or
>>oracle. All supports at spatial to some extent. And there you can do easily
>>simple filtering:
>>
>>Person.objects.filter(person_coordinates__dwithin(me.coordinates, distance))
>>
>>..and geodjango + spatial engine behind it will take care of all that complex
>>stuff.
>>
>>Note: you can still use GEOS parts from geodjango to do calculations so you
>>don't have to reinvent wheel if you want to keep coordinates as you already
>>have.
>>
>>--
>>
>>Jani Tiainen
>>
>>--
>>You received this message because you are subscribed to the Google Groups "Django users" group.
>>To post to this group, send email to django-users@googlegroups.com.
>>To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
>>For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
>>
>
> --
> You received this message because you are subscribed to the Google Groups "Django users" group.
> To post to this group, send email to django-users@googlegroups.com.
> To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
>
>

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

No comments:

Post a Comment