Search and Discovery with the HERE Geocoder API
In the previous article, we examined how you can use the HERE geocoding API to locate places by address, name, or postal code. This article demonstrates how to use the HERE discover service to find places using a location, the name of a chain or a category of a place, by a phone number, and places along a route.
We’ll use Python and places in Manhattan, New York for the examples. Let’s go!
Note: These examples assume you have an OAuth token to query the geocoder. The OAuth token is part of the header in the HTTP GET request. See the Identity & Access Management Guide to learn about using oauth with HERE services.
Place search
To search for "Central Park" when in Manhattan (40.7831,-73.9712), we can send a GET request to the "service" endpoint, e.g., https://geocode.search.hereapi.com/v1/service:
# parameters
base_url = "https://geocode.search.hereapi.com/v1/service"
# Place Search
place = "q=Central Park&at=40.7831,-73.9712"
url = (base_url+"?"+place)
geocode = json.loads(requests.get(url, headers=headers).text)
print("Number of items returned: " + str(len(geocode["items"])))
Number of items returned: 3
The discovery service returns several results as a list and we can get the result we want by iterating through the list and finding the result that has a resultType of “place.”
# Find place
for item in geocode["items"]:
if item["resultType"] == "place":
result =item
print("Place")
pprint(result)
The result provides the location coordinates and a lot of metadata such as contacts, categories, and food types that can be used to enhance an application.
Place
{'access': [{'lat': 40.76747, 'lng': -73.97067}],
'address': {'city': 'New York',
'countryCode': 'USA',
'countryName': 'United States',
'county': 'New York',
'district': 'Central Park',
'houseNumber': '830',
'label': 'Central Park, 830 5th Ave, New York, NY 10065-7001, '
'United States',
'postalCode': '10065-7001',
'state': 'New York',
'stateCode': 'NY',
'street': '5th Ave'},
'categories': [{'id': '550-5510-0202',
'name': 'Park-Recreation Area',
'primary': True},
{'id': '100-1000-0000', 'name': 'Restaurant'},
{'id': '100-1100-0010', 'name': 'Coffee Shop'},
{'id': '200-2100-0019', 'name': 'Cinema'}],
'contacts': [{'email': [{'categories': [{'id': '100-1000-0000'}],
'value': 'info@thecentralparkboathouse.com'}],
'fax': [{'categories': [{'id': '100-1000-0000'}],
'value': '+12127443949'}],
'phone': [{'value': '+12123106600'},
{'categories': [{'id': '100-1000-0000'}],
'value': '+12125172233'},
{'categories': [{'id': '100-1000-0000'}],
'value': '+16465976700'}],
'www': [{'categories': [{'id': '100-1100-0010'},
{'id': '550-5510-0202'}],
'value': 'http://www.centralparknyc.org'},
{'categories': [{'id': '100-1000-0000'}],
'value': 'http://www.thecentralparkboathouse.com'}]}],
'distance': 1732,
'foodTypes': [{'id': '101-000', 'name': 'American', 'primary': True}],
'id': 'here:pds:place:840dr5ru-0aec64649aa14bbaa63bf9c03570a862',
'language': 'en','position': {'lat': 40.76753, 'lng': -73.97081},
'references': [{'id': '34460664', 'supplier': {'id': 'core'}}],
'resultType': 'place',
'title': 'Central Park'}
Category search
You can search for places using their category. For example, to search for museums around Central Park (40.76753,-73.97081) within a radius of 500 meters. We’ll also limit it to just one result.
# Category Search
category = "in=circle:40.78272016069529,-73.9655032748007;r=500&q=museum&limit=1"
url = (base_url+"?"+category)
geocode = json.loads(requests.get(url, headers=headers).text)
print("Category search")
pprint(geocode)
The closest museum is the Metropolitan Museum of Art. The result includes metadata such as contacts and references.
{'items': [{'access': [{'lat': 40.77873, 'lng': -73.96247}],
'address': {'city': 'New York',
'countryCode': 'USA',
'countryName': 'United States',
'county': 'New York',
'district': 'Central Park',
'houseNumber': '1000',
'label': 'The Metropolitan Museum of Art, 1000 5th '
'Ave, New York, NY 10028, United States',
'postalCode': '10028',
'state': 'New York',
'stateCode': 'NY',
'street': '5th Ave'},
'categories': [{'id': '300-3100-0000',
'name': 'Museum',
'primary': True},
{'id': '100-1000-0000', 'name': 'Restaurant'},
{'id': '100-1100-0010', 'name': 'Coffee Shop'},
{'id': '200-2000-0011', 'name': 'Bar or Pub'},
{'id': '300-3000-0024', 'name': 'Gallery'},
{'id': '300-3100-0029', 'name': 'Art Museum'}],
'contacts': [{'phone': [{'categories': [{'id': '300-3000-0024'},
{'id': '300-3100-0000'}],
'value': '+12122498998'},
{'value': '+12125357710'},
{'categories': [{'id': '300-3000-0024'},
{'id': '300-3100-0000'}],
'value': '+12125703894'}],
'www': [{'categories': [{'id': '100-1000-0000'},
{'id': '200-2000-0011'},
{'id': '300-3100-0000'},
{'id': '300-3100-0029'}],
'value': 'http://www.metmuseum.org'},
{'categories': [{'id': '100-1000-0000'},
{'id': '100-1100-0010'}],
'value': 'http://www.metmuseum.org/visit/met-fifth-avenue'},
{'categories': [{'id': '100-1000-0000'},
{'id': '100-1100-0010'},
{'id': '200-2000-0011'}],
'value': 'http://www.metmuseum.org/visit/plan-your-visit/dining-at-the-museum/roof-garden-cafe-and-martini-bar'},
{'categories': [{'id': '100-1100-0010'}],
'value': 'http://www.metmuseum.org/visit/plan-your-visit/dining-at-the-museum/the-cafeteria'}]}],
'distance': 407,
'foodTypes': [{'id': '101-000', 'name': 'American'}],
'id': 'here:pds:place:840dr5ru-d8287ded2fa94ad6bbdf8843a18249be',
'language': 'en',
'ontologyId': 'here:cm:ontology:museum',
'position': {'lat': 40.77942, 'lng': -73.96342},
'references': [{'id': '17262072', 'supplier': {'id': 'core'}},
{'id': '105125', 'supplier': {'id': 'tripadvisor'}},
{'id': '2161607', 'supplier': {'id': 'tripadvisor'}},
{'id': '6785199', 'supplier': {'id': 'tripadvisor'}},
{'id': '8519917', 'supplier': {'id': 'tripadvisor'}},
{'id': '3VkktzThpBnJzPLxpl4FEg',
'supplier': {'id': 'yelp'}},
{'id': '7mgLLxrR6Tl26RkaWHGNGg',
'supplier': {'id': 'yelp'}},
{'id': '95Z7jocaCmj4Q26IA3rAHA',
'supplier': {'id': 'yelp'}},
{'id': 'GwKAivSXP70bN2ojKiH2LA',
'supplier': {'id': 'yelp'}},
{'id': 'NAgVENm8F0MHQvVxNvkzDA', 'supplier': {'id': 'yelp'}},
{'id': 'jVncyqXwlx_D9f2xZn05tg',
'supplier': {'id': 'yelp'}},
{'id': 'zfuLhNFNikUu4YczQ1T3FQ',
'supplier': {'id': 'yelp'}}],
'resultType': 'place',
'title': 'The Metropolitan Museum of Art'}]}
Chain search
You can search for businesses by their brand or chain name. Let’s imagine we are in Times Square and craving breadsticks. We can use the geocoder’s “service” endpoint to find the nearest Olive Garden.
# Chain Search
chain = "at=40.7580,-73.9855&q=Olive Garden&limit=2&ring=100"
url = (base_url+"?"+chain)
geocode = json.loads(requests.get(url, headers=headers).text)
print("Chain search")
# number of results
print(“Number of Olive Gardens found: %2d“ % (len(geocode[“items”])))
The query returns two results. The HERE geocoder API returns results as a list ordered by nearest distance. This means the first result will be the closest to the current position.
pprint(geocode[“items”][0])
{'access': [{'lat': 40.75929, 'lng': -73.98453}],
'address': {'city': 'New York',
'countryCode': 'USA',
'countryName': 'United States',
'county': 'New York',
'district': 'Theater District-Times Square',
'houseNumber': '2',
'label': 'Olive Garden, 2 Times Sq, New York, NY 10036, United '
'States',
'postalCode': '10036',
'state': 'New York',
'stateCode': 'NY',
'street': 'Times Sq'},
'categories': [{'id': '100-1000-0000', 'name': 'Restaurant', 'primary': True}],
'chains': [{'id': '1572', 'name': 'Olive Garden'}],
'contacts': [{'email': [{'value': 'olivegarden@news.olivegarden.com'}],
'fax': [{'value': '+12126641952'}],
'phone': [{'value': '+12123333254'}],
'www': [{'value': 'http://www.olivegarden.com'},
{'value': 'http://www.olivegarden.com/locations/new-york/nyc-times-square/700356'},
{'value': 'http://www.olivegarden.com/locations/ny/new-york/nyc-times-square/1451'},
{'value': 'https://www.olivegarden.com/home'},
{'value': 'https://www.olivegarden.com/locations/location-search'},
{'value': 'https://www.olivegarden.com/locations/ny/new-york/nyc-times-square/1451'},
{'value': 'https://www.olivegarden.com/menu?setRestaurant=1451'},
{'value': 'https://www.olivegarden.com/order-online?setRestaurant=1451'}]}],
'distance': 167,
'foodTypes': [{'id': '304-000', 'name': 'Italian', 'primary': True}],
'id': 'here:pds:place:840dr5ru-0d5455cb98b1422fb953f20c769e3eba',
'language': 'en',
'ontologyId': 'here:cm:ontology:olive_garden',
'openingHours': [{'isOpen': True,
'structured': [{'duration': 'PT13H00M',
'recurrence': 'FREQ:DAILY;BYDAY:MO,TU,WE,TH,SU',
'start': 'T110000'},
{'duration': 'PT14H00M',
'recurrence': 'FREQ:DAILY;BYDAY:FR,SA',
'start': 'T110000'}],
'text': ['Mon-Thu, Sun: 11:00 - 24:00',
'Fri, Sat: 11:00 - 01:00']}],
'position': {'lat': 40.75941, 'lng': -73.98482},
'references': [{'id': '16986272', 'supplier': {'id': 'core'}},
{'id': '617221', 'supplier': {'id': 'tripadvisor'}},
{'id': 'XPuCR_UaPliuNQMzU2pNlQ', 'supplier': {'id': 'yelp'}}],
'resultType': 'place',
'title': 'Olive Garden'}
The result contains rich metadata that is useful for enriching a search application.
Combined chain and category search
The geocoder also supports combining chain and category searches. Suppose you are feeling a little sleepy after eating all those breadsticks and want a coffee. You had a great coffee at a chain in Toronto but can’t quite remember the name. We can send a query for “Tim” and “coffee” to find the closest store.
# Category/Chain search
category_chain = "at=40.7580,-73.9855&q=Tim+coffee&limit=2"
url = (base_url+"/"+version+"/"+service+"?"+category_chain)
geocode = json.loads(requests.get(url, headers=headers).text)
print("Chain or Chain search")
pprint(geocode[“itmes”][0])
The geocoder returns results for Tim Hortons, a Canadian fast-food chain.
{'access': [{'lat': 40.75678, 'lng': -73.98872}],
'address': {'city': 'New York',
'countryCode': 'USA',
'countryName': 'United States',
'county': 'New York',
'district': 'Theater District-Times Square',
'houseNumber': '253',
'label': 'Tim Hortons, 253 W 42nd St, New York, NY 10036-7201, '
'United States',
'postalCode': '10036-7201',
'state': 'New York',
'stateCode': 'NY',
'street': 'W 42nd St'},
'categories': [{'id': '100-1100-0010', 'name': 'Coffee Shop', 'primary': True},
{'id': '600-6300-0246', 'name': 'Doughnut Shop'}],
'chains': [{'id': '1397', 'name': 'Tim Hortons'}],
'contacts': [{'fax': [{'value': '+14803624812'}],
'phone': [{'value': '+12123981882'},
{'categories': [{'id': '100-1100-0010'}],
'value': '+12123981938'}],
'www': [{'value': 'http://www.timhortons.com'},
{'value': 'http://www.timhortons.com/us/en/index.html'}]}],
'distance': 290,
'foodTypes': [{'id': '800-060', 'name': 'Sandwich', 'primary': True},
{'id': '800-063', 'name': 'Ice Cream'}],
'id': 'here:pds:place:840dr5ru-1cf9a577a55f99223e53f399fac6f4f0',
'language': 'en',
'openingHours': [{'isOpen': True,
'structured': [{'duration': 'PT16H00M',
'recurrence': 'FREQ:DAILY;BYDAY:MO,TU,WE,TH,SU',
'start': 'T070000'},
{'duration': 'PT16H59M',
'recurrence': 'FREQ:DAILY;BYDAY:FR,SA',
'start': 'T070000'}],
'text': ['Mon-Thu, Sun: 07:00 - 23:00',
'Fri, Sat: 07:00 - 23:59']}],
'position': {'lat': 40.75692, 'lng': -73.98863},
'references': [{'id': '1069684312', 'supplier': {'id': 'core'}},
{'id': '3756350', 'supplier': {'id': 'tripadvisor'}},
{'id': 'qOvpCZgcb4WeXrofSfl1Zw', 'supplier': {'id': 'yelp'}}],
'resultType': 'place',
'title': 'Tim Hortons'}
Route Search: Putting it all together
Let’s combine these services in a hypothetical use case. Meadow lives in North Jersey and she’s going shopping at Bergdorff’s in Manhattan. She’s picking up a friend in Tenafly, New Jersey, which adds to her drive. Meadow is feeling sleepy when she is close to her friend’s house, and she wants a macchiato from Starbucks.
We can use the HERE geocoding search and discovery services to create a route to and from Meadow’s house to Bergdorffs in Manhattan, and locate Starbucks when she’s near her friend’s house in Tenafly. We can use the geocoder to get the start point of the route.
# Search along a route
# get origin
service = "geocode"
place = "q=14 Aspen Dr, Caldwell, NJ 07006"
url = (base_url+"/"+version+"/"+service+"?"+place)
geocode = json.loads(requests.get(url, headers=headers).text)
origin = ",".join([str(geocode["items"][0]["position"]['lat']),str(geocode["items"][0]["position"]['lng'])])
Next, we can use chain search to locate Bergdorffs.
# get destination
# place = "q=Bergdorf Goodman, 754 5th Ave, New York, NY 10019"
place = "q=Bergdorf Goodman, Manhattan&limit=1"
url = (base_url+"/"+version+"/"+service+"?"+place)
geocode = json.loads(requests.get(url, headers=headers).text)
destination = ",".join([str(geocode["items"][0]["position"]["lat"]),str(geocode["items"][0]["position"]['lng'])])
We’ll need to create a route. The HERE routing service is beyond the scope if this article, but you can see that generating a route is straight forward. We need the routeHandle to search along a route.
# create route
routing_service = "https://router.hereapi.com/v8/routes?"
url = (routing_service+"origin="+origin+"&destination="+destination+"&return=routeHandle&transportMode=car")
route = json.loads(requests.get(url, headers=headers).text)
route_handle = route["routes"][0]["routeHandle"]
Now that we have a routeHandle, we can call the discover service endpoint to find the Starbucks along the route near Tenafly, NJ.
# find Starbucks along route by Tenafly (40.9254,-73.9629)
route_search = "at=40.9254,-73.9629&limit=10&q=Starbucks&route="+route_handle
url = (base_url+"/"+version+"/"+service+"?"+route_search)
geocode = json.loads(requests.get(url, headers=headers).text)
print("Search along a route")
pprint(geocode)
The discover service returns the location of the Starbucks along Meadow’s route. Using the position field from the response, we can map the locations along the route. Routing and displaying maps are outside the scope of this article but stay tuned for future articles on routing and mapping.
Conclusion
The HERE geocoder API offers search and discovery services in addition to address geocoding. You can combine these services to build rich mapping applications complete with metadata such as working hours, services, and cuisine.
Learn more about HERE’s geocoding API with the HERE Geocoding & Search API User Guide and the API Reference.
Articles in the geocoding series:
Have your say
Sign up for our newsletter
Why sign up:
- Latest offers and discounts
- Tailored content delivered weekly
- Exclusive events
- One click to unsubscribe