[Catalyst-commits] r7160 - trunk/examples/CatalystAdvent/root/2007

zby at dev.catalyst.perl.org zby at dev.catalyst.perl.org
Sun Nov 25 23:46:18 GMT 2007


Author: zby
Date: 2007-11-25 23:46:18 +0000 (Sun, 25 Nov 2007)
New Revision: 7160

Modified:
   trunk/examples/CatalystAdvent/root/2007/15.pod
Log:
Search by proximity added.


Modified: trunk/examples/CatalystAdvent/root/2007/15.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/15.pod	2007-11-25 21:49:30 UTC (rev 7159)
+++ trunk/examples/CatalystAdvent/root/2007/15.pod	2007-11-25 23:46:18 UTC (rev 7160)
@@ -182,7 +182,71 @@
 
 =head3 Full Text Search
 
+For full text search I use the PostgreSQL tsearch2 engine here.
+
 =head3 Search by Proximity
 
+For searching by proximity I use the PostgreSQL geometric functions 
+(http://www.postgresql.org/docs/8.2/interactive/functions-geometry.html).
+There is 
+one problem with it - the distance operator assumes planar coordinates, 
+while for the interesting thing is to search geografic data with the standard
+latitude/longitude coordinates.  In our solution we just don't care about
+being exact and just multiply the 'distance' in degrees by 50 to get approximate
+distance in miles.  The actual proportion is about 43 for latitude and 69 for
+longitude at about the London's longitude, it would be possible to get quite 
+good results by dividing the latitude and longitude by those numbers in the
+database - but I would rather have good data in the database then more exact
+results.  Maybe at some point we shell switch to use some real geografic 
+distance functions (I've seen a PosgreSQL extension to do that - but I was
+scared a bit by it's experimental status).
 
+So here is the function used to filter the results by proximity to a place:
 
+sub search_for_distance {
+    my ( $self, $rs, $params ) = @_;
+    my $lat_long = $params->{lat_long};
+    my $distance = $params->{distance} / 50;  
+    # around London the actual proportions are around 43 for latitude 
+    # and 69 for longitude 
+    return $rs->search( 
+        { "(lat_long <-> '$lat_long'::POINT) < " => \$distance },
+        { join => 'location' }
+    );
+}
+
+This function assumes there are two parameters on the $params hash: distance
+and lat_long (lattitude/logintude coordinates).  The location data in our
+database are in a separate table called 'location'.
+
+We also use another search extension:
+
+sub search_for_lat_long {
+    my ( $self, $rs, $params ) = @_;
+    my $lat_long = $params->{lat_long};
+    $rs = $rs->search( undef,        
+        { 
+            join => 'location',
+            '+select' => [ \"(lat_long <-> '$lat_long'::POINT) AS distance" ],
+            '+as' => 'distance',
+            order_by => 'distance ASC',
+        }
+    );
+    return $rs;
+}
+
+This function sorts the results by proximity to the point determined by the
+lat_long coordinates.  This way the user does not need to specify the
+maximum distance - the closest results are displayed on the first pages
+anyway - and that is enough for most of the searches.
+
+=head2 And Beyond
+
+In the search by proximity extension I've used ordering of the results.  There
+is one problem with this.  We use many 'search' calls on the resultset
+to cumulate the predicates - but we cannot do this with the order.  Only the 
+last 'order_by' parameter used in the 'search' calls is effective.  I believe
+it would be useful to have a similar 'cumulative' behaviour for 'order_by' 
+and we can add this to 'advanced_search' (or perhaps it can be added to
+the core DBIC search method).
+




More information about the Catalyst-commits mailing list