lambda-taggable-geonames-indexer
v1.0.5
Published
Create Tags based on Geonames hierarchy
Downloads
16
Readme
Lambda Taggable Geonames
Why?
Locating Hotels and other content by searching for a place name is the heart of the Tagging system. We use Geonames to "reverse geocode" the Lat/Lon for each Hotel in the database and add "hierarchy" for that place.
See: How? > Detail section for detailed example
What?
Lambda function that accepts a set of Longitude & Latitude coordinates (lat/lon) and returns a list of Geo Tags. (corresponding to the elements in the Geonames hierarchy for that lat/lon).
How?
There are two ways to use this package:
Lambda
Deploy the Lambda function by running the deployment script:
npm run deploy
( see: https://github.com/numo-labs/aws-lambda-deploy for detail )Invoke in AWS Console:
Sample Event
{
"_id": "hotel:mhid.02tu1jz",
"displayName": "Elvis Presley's Heartbreak",
"location": {
"lat": "35.04850",
"lon": "-90.02710"
},
"tags": []
}
Will return an array of Geo Tags in the Taggable System format:
[
{
"_id": "geo:geonames.6295630",
"displayName": "Earth",
"location": {
"lat": "0",
"lon": "0"
},
"tags": []
},
{
"_id": "geo:geonames.6255149",
"displayName": "North America",
"location": {
"lat": "46.07323",
"lon": "-100.54688"
},
"tags": [
{
"tagId": "geo:geonames.6295630",
"displayName": "Earth",
"source": "geonames",
"inherited": false,
"active": true
}
]
},
{
"_id": "geo:geonames.6252001",
"displayName": "United States",
"location": {
"lat": "39.76",
"lon": "-98.5"
},
"tags": [
{
"tagId": "geo:geonames.6255149",
"displayName": "North America",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6295630",
"displayName": "Earth",
"source": "geonames",
"inherited": false,
"active": true
}
]
},
{
"_id": "geo:geonames.4662168",
"displayName": "Tennessee",
"location": {
"lat": "35.75035",
"lon": "-86.25027"
},
"tags": [
{
"tagId": "geo:geonames.6252001",
"displayName": "United States",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6255149",
"displayName": "North America",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6295630",
"displayName": "Earth",
"source": "geonames",
"inherited": false,
"active": true
}
]
},
{
"_id": "geo:geonames.4657046",
"displayName": "Shelby County",
"location": {
"lat": "35.184",
"lon": "-89.8956"
},
"tags": [
{
"tagId": "geo:geonames.4662168",
"displayName": "Tennessee",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6252001",
"displayName": "United States",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6255149",
"displayName": "North America",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6295630",
"displayName": "Earth",
"source": "geonames",
"inherited": false,
"active": true
}
]
},
{
"_id": "geo:geonames.4645760",
"displayName": "Nonconnah",
"location": {
"lat": "35.06204",
"lon": "-90.0362"
},
"tags": [
{
"tagId": "geo:geonames.4657046",
"displayName": "Shelby County",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.4662168",
"displayName": "Tennessee",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6252001",
"displayName": "United States",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6255149",
"displayName": "North America",
"source": "geonames",
"inherited": false,
"active": true
},
{
"tagId": "geo:geonames.6295630",
"displayName": "Earth",
"source": "geonames",
"inherited": false,
"active": true
}
]
}
]
Node Module
If you prefer to use this package as a node module e.g: as part of another lambda
npm install lambda-taggable-geonames-indexer --save
Then in your code:
var geonames = require('lambda-taggable-geonames-indexer');
var lat = '28.3852';
var lon = '81.5639';
geonames.find(lat, lon, function (err, geo) {
console.log(geo); // see Detail section below for example output
var geonames_id = geo.geonames[0].geonameId;
geonames.hierarchy(geonames_id, function (err, hierarchy) {
console.log(JSON.stringify(hierarchy, null, 2));
}); // see Detail for example hierarchy object
});
Detail
The best way to understand how this works is with a simple example:
Imagine we have a Hotel in Formenterra
{
"MID": "1234ABCD",
"Name": "Blanco Hotel Formentera",
"Country": "SPAIN",
"ISO-2": "ES",
"Address": "Calle Fonoll Marí, 50 07871 Es Pujols",
"Latitude": "38.7",
"Longitude": "1.467"
}
We would lookup this hotel in Geonames given its Latitude
and Longitude
values using the following query:
http://api.geonames.org/findNearbyPlaceNameJSON?lat=38.7&lng=1.467&username=demo&style=full&localCountry=true&maxrows=100&cities=15000
{
"geonames":[
{
"distance":"1.31434",
"timezone":{
"gmtOffset":1,
"timeZoneId":"Europe/Madrid",
"dstOffset":2
},
"asciiName":"Sant Ferran de ses Roques",
"countryId":"2510769",
"fcl":"P",
"adminId2":"6424360",
"adminId3":"6356033",
"countryCode":"ES",
"adminId1":"2521383",
"lat":"38.70762",
"fcode":"PPL",
"continentCode":"EU",
"elevation":0,
"adminCode2":"PM",
"adminCode3":"07024",
"adminCode1":"07",
"lng":"1.45543",
"geonameId":6696037,
"toponymName":"Sant Ferran de ses Roques",
"population":10757,
"adminName5":"",
"adminName4":"",
"adminName3":"Formentera",
"alternateNames":[
{
"name":"http://en.wikipedia.org/wiki/Sant_Ferran_de_ses_Roques",
"lang":"link"
}
],
"adminName2":"Balearic Islands",
"name":"Sant Ferran de ses Roques",
"fclName":"city, village,...",
"countryName":"Spain",
"fcodeName":"populated place",
"adminName1":"Balearic Islands"
}
]
}
From this response get the geonameId
which we can use to run the
hierarchy query:
http://api.geonames.org/hierarchyJSON?geonameId=6696037&username=demo
{
"geonames":[
{
"lng":"0",
"geonameId":6295630,
"name":"Earth",
"fclName":"parks,area, ...",
"toponymName":"Earth",
"fcodeName":"area",
"adminName1":"",
"lat":"0",
"fcl":"L",
"fcode":"AREA",
"population":6814400000
},
{
"lng":"9.14062",
"geonameId":6255148,
"name":"Europe",
"fclName":"parks,area, ...",
"toponymName":"Europe",
"fcodeName":"continent",
"adminName1":"",
"lat":"48.69096",
"fcl":"L",
"fcode":"CONT",
"population":0
},
{
"adminCode1":"00",
"lng":"-4",
"geonameId":2510769,
"toponymName":"Kingdom of Spain",
"countryId":"2510769",
"fcl":"A",
"population":46505963,
"countryCode":"ES",
"name":"Spain",
"fclName":"country, state, region,...",
"countryName":"Spain",
"fcodeName":"independent political entity",
"adminName1":"",
"lat":"40",
"fcode":"PCLI"
},
{
"adminCode1":"07",
"lng":"1.45871",
"geonameId":6356033,
"toponymName":"Formentera",
"countryId":"2510769",
"fcl":"A",
"population":10757,
"countryCode":"ES",
"name":"Formentera",
"fclName":"country, state, region,...",
"countryName":"Spain",
"fcodeName":"third-order administrative division",
"adminName1":"Balearic Islands",
"lat":"38.71905",
"fcode":"ADM3"
}
]
}
Expected Environment Variables
Running the Lambda/Script
Using this script requires that you set a GEONAMES_USERNAMES
environment variable (one or more usernames)
e.g:
export GEONAMES_USERNAME=yourusername,backupusername,etc
Deploying
Deploying to AWS requires that you set AWS_REGION
and AWS_IAM_ROLE
variables.
e.g:
export AWS_REGION=eu-west-1
export AWS_IAM_ROLE=arn:aws:iam::123456789:role/LambdaExecRole
see: https://github.com/numo-labs/aws-lambda-deploy#2-ensure-that-the-required-aws-environment-variables-are-set
Setup Geonames Account
To use this module you will require a Geonames account. If you have not already signed up, visit: http://www.geonames.org/login
Next, ensure that you have enabled the "Free Web Service" for your Geonames account:
Go to: http://www.geonames.org/manageaccount and scroll to the bottom of the page you will see a link "Click here to enable" click it.
Once enabled you should see a confirmation message:
Now everything should work as expected.
Running low on Geonames API Calls/Credits?
see: https://github.com/numo-labs/lambda-taggable-geonames-indexer/issues/5
Tests
to run the tests for this project execute the following command in your terminal:
npm test