def get_geohash_where_clause(coord_geoint, precision, geoint_col_name): ''' Given an unsigned 64-bit int geohash, a precision, and the SQL table column name of the geohash field, returns a SQL WHERE clause that would select all rows within the distance bounded by the specified precision. If the precision is low enough such that no WHERE clauses can be generated, empty str is returned. coord_geoint: unsigned 64-bit int, geohash value of the coordinates around which to query for. precision: the precision to search within, the lower the value the larger the distance to search for. Must be between 0 and 64. geoint_col_name: the name of the geohash int column in the SQL database table to search in. ''' sub_clauses = [] for bound_range in geohash.expand_uint64(coord_geoint, precision): if bound_range[0] and bound_range[1]: sub_clauses.append("(" + geoint_col_name + ">=" + str(bound_range[0]) + " AND " + geoint_col_name + "<" + str(bound_range[1]) + ")") elif bound_range[0]: sub_clauses.append("(" + geoint_col_name + ">=" + str(bound_range[0]) + ")") elif bound_range[1]: sub_clauses.append("(" + geoint_col_name + "<" + str(bound_range[1]) + ")") if len(sub_clauses) == 0: return "" else: return "(" + " OR ".join(sub_clauses) + ")"
def get_nearest_stops(key, lng, lat, radius=150, units='m', with_dist=False, with_coord=False, with_hash=False, sort=None): if not api_redis.exists('locations'): set_cache_stops() pieces = [key, lng, lat, radius, units] # XXX Can modify precision based on user radius. Default to 36 (~150m) ranges = geohash.expand_uint64(geohash.encode_uint64(float(lat), float(lng)), precision=36) # XXX This has no affect at this time if with_dist: pieces.append('WITHDIST') if with_coord: pieces.append('WITHCOORD') if with_hash: pieces.append('WITHHASH') if sort: pieces.append(sort) # TODO Some day this can be done with the Geo Redis commands pipe = api_redis.pipeline(transaction=False) for r in ranges: pipe.zrangebyscore(key, r[0], r[1]) # TODO This will require some intermediate steps if scores are returned stops = [stop for stop_list in pipe.execute() for stop in stop_list] # TODO Implement filtering by radius and units return get_stop_details(stops)
def apply_filters(self, request, applicable_filters): r = applicable_filters.pop('range') if not 'geohash__exact' in applicable_filters: return super(BeatResource, self).apply_filters(request, applicable_filters) gh = long(applicable_filters.pop('geohash__exact')) # Use Q object to query the neighbors of the geohash qobj = Q() for nb in geohash.expand_uint64(gh, r): qobj |= Q(geohash__gt=nb[0], geohash__lt=nb[1]) return super(BeatResource, self).apply_filters(request, applicable_filters).filter(qobj)
def _expand(self, ui64, depth): return geohash.expand_uint64(ui64, depth)