Relevance metadata for Google
This commit is contained in:
@@ -6,8 +6,7 @@ from cartodb_services.google import GoogleMapsGeocoder
|
|||||||
|
|
||||||
|
|
||||||
def async_geocoder(geocoder, address, components):
|
def async_geocoder(geocoder, address, components):
|
||||||
results = geocoder.geocode(address=address, components=components)
|
return geocoder.geocode(address=address, components=components)
|
||||||
return results if results else []
|
|
||||||
|
|
||||||
|
|
||||||
class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
||||||
@@ -26,12 +25,9 @@ class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
|||||||
results = []
|
results = []
|
||||||
for search in searches:
|
for search in searches:
|
||||||
(cartodb_id, street, city, state, country) = search
|
(cartodb_id, street, city, state, country) = search
|
||||||
address = compose_address(street, city, state, country)
|
lng_lat, metadata = self.geocode_meta(street, city, state, country)
|
||||||
components = self._build_optional_parameters(city, state, country)
|
self._logger.debug('--> lng_lat: {}. metadata: {}'.format(lng_lat, metadata))
|
||||||
result = self.geocoder.geocode(address=address, components=components)
|
results.append((cartodb_id, lng_lat, metadata))
|
||||||
lng_lat = self._extract_lng_lat_from_result(result[0]) if result else []
|
|
||||||
self._logger.debug('--> lng_lat: {}'.format(lng_lat))
|
|
||||||
results.append((cartodb_id, lng_lat, []))
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _batch_geocode(self, searches):
|
def _batch_geocode(self, searches):
|
||||||
@@ -39,16 +35,13 @@ class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
|||||||
pool = Pool(processes=self.PARALLEL_PROCESSES)
|
pool = Pool(processes=self.PARALLEL_PROCESSES)
|
||||||
for search in searches:
|
for search in searches:
|
||||||
(cartodb_id, street, city, state, country) = search
|
(cartodb_id, street, city, state, country) = search
|
||||||
components = self._build_optional_parameters(city, state, country)
|
self._logger.debug('async geocoding --> {}'.format(search))
|
||||||
# Geocoding works better if components are also inside the address
|
|
||||||
address = compose_address(street, city, state, country)
|
address = compose_address(street, city, state, country)
|
||||||
if address:
|
if address:
|
||||||
self._logger.debug('async geocoding --> {} {}'.format(address.encode('utf-8'), components))
|
components = self._build_optional_parameters(city, state, country)
|
||||||
result = pool.apply_async(async_geocoder,
|
result = pool.apply_async(async_geocoder,
|
||||||
(self.geocoder, address, components))
|
(self.geocoder, address, components))
|
||||||
else:
|
bulk_results[cartodb_id] = result
|
||||||
result = []
|
|
||||||
bulk_results[cartodb_id] = result
|
|
||||||
pool.close()
|
pool.close()
|
||||||
pool.join()
|
pool.join()
|
||||||
|
|
||||||
@@ -56,13 +49,12 @@ class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
|||||||
results = []
|
results = []
|
||||||
for cartodb_id, bulk_result in bulk_results.items():
|
for cartodb_id, bulk_result in bulk_results.items():
|
||||||
try:
|
try:
|
||||||
result = bulk_result.get()
|
lng_lat, metadata = self._process_results(bulk_result.get())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error('Error at Google async_geocoder', e)
|
self._logger.error('Error at Google async_geocoder', e)
|
||||||
result = []
|
lng_lat, metadata = [[], {}]
|
||||||
|
|
||||||
lng_lat = self._extract_lng_lat_from_result(result[0]) if result else []
|
results.append((cartodb_id, lng_lat, metadata))
|
||||||
results.append((cartodb_id, lng_lat, []))
|
|
||||||
return results
|
return results
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
self._logger.error('KeyError error', exception=e)
|
self._logger.error('KeyError error', exception=e)
|
||||||
@@ -70,4 +62,3 @@ class GoogleMapsBulkGeocoder(GoogleMapsGeocoder, StreetPointBulkGeocoder):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._logger.error('General error', exception=e)
|
self._logger.error('General error', exception=e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,15 @@ from cartodb_services.geocoder import compose_address
|
|||||||
from cartodb_services.google.exceptions import InvalidGoogleCredentials
|
from cartodb_services.google.exceptions import InvalidGoogleCredentials
|
||||||
from client_factory import GoogleMapsClientFactory
|
from client_factory import GoogleMapsClientFactory
|
||||||
|
|
||||||
|
EMPTY_RESPONSE = [[], {}]
|
||||||
|
PARTIAL_FACTOR = 0.8
|
||||||
|
RELEVANCE_BY_LOCATION_TYPE = {
|
||||||
|
'ROOFTOP': 1,
|
||||||
|
'GEOMETRIC_CENTER': 0.9,
|
||||||
|
'RANGE_INTERPOLATED': 0.8,
|
||||||
|
'APPROXIMATE': 0.7
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GoogleMapsGeocoder():
|
class GoogleMapsGeocoder():
|
||||||
|
|
||||||
@@ -19,26 +28,49 @@ class GoogleMapsGeocoder():
|
|||||||
self.geocoder = GoogleMapsClientFactory.get(self.client_id, self.client_secret, self.channel)
|
self.geocoder = GoogleMapsClientFactory.get(self.client_id, self.client_secret, self.channel)
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
|
|
||||||
def geocode(self, searchtext, city=None, state=None,
|
def geocode(self, searchtext, city=None, state=None, country=None):
|
||||||
country=None):
|
return self.geocode_meta(searchtext, city, state, country)[0]
|
||||||
|
|
||||||
|
def geocode_meta(self, searchtext, city=None, state=None, country=None):
|
||||||
try:
|
try:
|
||||||
address = compose_address(searchtext, city, state, country)
|
address = compose_address(searchtext, city, state, country)
|
||||||
opt_params = self._build_optional_parameters(city, state, country)
|
opt_params = self._build_optional_parameters(city, state, country)
|
||||||
results = self.geocoder.geocode(address=address,
|
results = self.geocoder.geocode(address=address,
|
||||||
components=opt_params)
|
components=opt_params)
|
||||||
if results:
|
return self._process_results(results)
|
||||||
return self._extract_lng_lat_from_result(results[0])
|
except KeyError as e:
|
||||||
else:
|
self._logger.error('params: {}, {}, {}, {}'.format(
|
||||||
return []
|
searchtext.encode('utf-8'), city.encode('utf-8'),
|
||||||
except KeyError:
|
state.encode('utf-8'), country.encode('utf-8')
|
||||||
|
), e)
|
||||||
raise MalformedResult()
|
raise MalformedResult()
|
||||||
|
|
||||||
|
def _process_results(self, results):
|
||||||
|
if results:
|
||||||
|
self._logger.debug('--> results: {}'.format(results[0]))
|
||||||
|
return [
|
||||||
|
self._extract_lng_lat_from_result(results[0]),
|
||||||
|
self._extract_metadata_from_result(results[0])
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
return EMPTY_RESPONSE
|
||||||
|
|
||||||
def _extract_lng_lat_from_result(self, result):
|
def _extract_lng_lat_from_result(self, result):
|
||||||
location = result['geometry']['location']
|
location = result['geometry']['location']
|
||||||
longitude = location['lng']
|
longitude = location['lng']
|
||||||
latitude = location['lat']
|
latitude = location['lat']
|
||||||
return [longitude, latitude]
|
return [longitude, latitude]
|
||||||
|
|
||||||
|
def _extract_metadata_from_result(self, result):
|
||||||
|
location_type = result['geometry']['location_type']
|
||||||
|
base_relevance = RELEVANCE_BY_LOCATION_TYPE[location_type]
|
||||||
|
partial_match = result.get('partial_match', False)
|
||||||
|
partial_factor = PARTIAL_FACTOR if partial_match else 1
|
||||||
|
return {
|
||||||
|
'relevance': base_relevance * partial_factor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _build_optional_parameters(self, city=None, state=None,
|
def _build_optional_parameters(self, city=None, state=None,
|
||||||
country=None):
|
country=None):
|
||||||
optional_params = {}
|
optional_params = {}
|
||||||
|
|||||||
@@ -83,8 +83,13 @@ class TestStreetFunctionsSetUp(TestCase):
|
|||||||
'Plaza España, Barcelona': 0.85
|
'Plaza España, Barcelona': 0.85
|
||||||
})
|
})
|
||||||
|
|
||||||
|
GOOGLE_RELEVANCES = HERE_RELEVANCES.copy()
|
||||||
|
GOOGLE_RELEVANCES.update({
|
||||||
|
'Plaza España, Barcelona': 0.9
|
||||||
|
})
|
||||||
|
|
||||||
RELEVANCES = {
|
RELEVANCES = {
|
||||||
'google': HERE_RELEVANCES,
|
'google': GOOGLE_RELEVANCES,
|
||||||
'here': HERE_RELEVANCES,
|
'here': HERE_RELEVANCES,
|
||||||
'tomtom': TOMTOM_RELEVANCES,
|
'tomtom': TOMTOM_RELEVANCES,
|
||||||
'mapbox': MAPBOX_RELEVANCES
|
'mapbox': MAPBOX_RELEVANCES
|
||||||
@@ -331,7 +336,7 @@ class TestBulkStreetFunctions(TestStreetFunctionsSetUp):
|
|||||||
self.fixture_points['Plaza España, Barcelona'])
|
self.fixture_points['Plaza España, Barcelona'])
|
||||||
|
|
||||||
def _test_known_table(self):
|
def _test_known_table(self):
|
||||||
subquery = 'select * from known_table where cartodb_id < 1100'
|
subquery = 'select * from unknown_table where cartodb_id < 1100'
|
||||||
subquery_count = 'select count(1) from ({}) _x'.format(subquery)
|
subquery_count = 'select count(1) from ({}) _x'.format(subquery)
|
||||||
count = self._run_authenticated(subquery_count)['rows'][0]['count']
|
count = self._run_authenticated(subquery_count)['rows'][0]['count']
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user