Table of Contents
Introduction
Recently we published an article discussing the benefits of distance matrix services for logistics and delivery optimization. In addition, the article provided some excellent comparisons between NextBillion.ai and distance matrix services from other providers like Google Maps and Mapbox. If you haven’t had a chance to read this excellent resource, take a look here.
Of late, we’ve been having a growing number of conversations with prospects who are evaluating their current distance matrix service providers. Most evaluation discussions cover multiple areas of consideration, but the consistent themes that we hear are relating to price, scalability, supported matrix size, ETA accuracy and switching costs. The article referenced above does a good job of addressing all but the last — switching costs. Carving out developer time to evaluate changes to APIs that are already in place is tough to justify, especially when the scope of the changes is unknown.
In this article, we’ll take a look at the ease with which a developer can take an application service that uses either Google Maps or Mapbox distance matrix APIs and transition it to NextBillion.ai. You’ll see that with just a few modifications, your service can be switched to NextBillion.ai’s Distance Matrix API, and you can take advantage of all that it has to offer related to price, scalability, matrix size and ETAs that are customized to your business operations.
Let’s jump right in…..
Switch from Google Maps Distance Matrix
If you are currently using the Google Maps distance matrix service, you may have some API calls that present similarly to the code shown below. Here we are using the Axios library to fetch from the Google Maps API endpoint with a set of origins and destinations. The implementation is pretty straightforward, and in this example, we output the results to the terminal to show the travel time between each origin and destination.
let axios = require('axios');
const colorize = require('./utils');
module.exports = async function dm(originArray, destArray, orig_pts, dest_pts, precision)
{
// GOOGLE DISTANCE MATRIX - GET https://maps.googleapis.com/maps/api/distancematrix
let config = {
method: 'get',
url: `https://maps.googleapis.com/maps/api/distancematrix/json?origins=${orig_pts}&destinations=${dest_pts}&units=imperial&key=${process.env['GOOGLE_API_KEY']}`,
headers: {}
};
await axios(googConfig)
.then( resp => {
process.stdout.write(colorize(44,'...Google Map result... '));
process.stdout.write('\n');
process.stdout.write(colorize(91, ' '.toString().padStart(19, ' ')));
destArray.forEach( pt => {
process.stdout.write('|' + colorize(91, pt.padStart(19, ' ')));
});
process.stdout.write('|' + '\n');
let idx = 0;
const dm = resp.data;
dm.rows.forEach( row => {
process.stdout.write(colorize(93, originArray[idx++].padStart(19, ' ') + '|'));
row.elements.forEach( element => {
process.stdout.write(colorize(92, element.duration.value.toString().padStart(precision + 15, ' ')));
process.stdout.write('|');
});
process.stdout.write('\n');
});
})
.catch (error => {
console.log(error);
});
}
Output from the Google API call will look similar to this.
...Google Map result...
| 37.6948,-122.4799| 37.6788,-122.4429| 37.6933,-122.4756|
37.6875,-122.4586| 449| 262| 384|
37.5900,-122.3711| 1195| 1103| 1131|
37.6741,-122.4043| 1207| 746| 1142|
We’ve highlighted the code block in bold where changes are made in order to switch to using NextBillion.ai for the same set of points. The required changes are minimal; the code block below shows the changes highlighted in bold and the resulting output.
With NextBillion.ai, we use an HTTP POST with the body containing the origins, destinations, travel profile (car, truck etc.) and optional departure timestamp. Using a POST and body allows us to present large matrix problems (in the order of thousands) to our endpoint without exceeding URI length limits.
let axios = require('axios');
const colorize = require('./utils');
module.exports = async function dm(originArray, destArray, orig_pts, dest_pts, precision)
{
// NBAI JSON will use POST endpoint (concise)
const apiKey = process.env['API_KEY'];
const apiHost = process.env['API_HOST'];
// With NBAI, you can set departure time and it will
// use historic traffic patterns for this date/time
// Change mode to other transport modes as needed
let bodyRequest = {
"departure_time": Math.round(new Date().getTime() / 1000),
"origins": orig_pts,
"destinations": dest_pts,
"mode": "car"
};
let config = {
method: 'post',
url: `${apiHost}/distancematrix/json-concise?key=${apiKey}`,
data: bodyRequest
}
await axios(config)
.then((res) => {
process.stdout.write(colorize(45,'...NB.ai result... '));
process.stdout.write('\n');
process.stdout.write(colorize(91, ' '.toString().padStart(19, ' ')));
destArray.forEach( pt => {
process.stdout.write('|' + colorize(91, pt.padStart(19, ' ')));
});
process.stdout.write('|' + '\n');
var idx = 0;
var dm = res.data;
dm.rows.forEach( row => {
process.stdout.write(colorize(93, originArray[idx++].padStart(19, ' ') + '|'));
row.forEach( element => {
process.stdout.write(colorize(92, element[0].toString().padStart(precision + 15, ' ')));
process.stdout.write('|');
});
process.stdout.write('\n');
});
}).catch((err) => {
console.log(err);
})
}
Output from the NB.ai API call will look similar to this.
...NB.ai result...
| 37.6735,-122.4531| 37.6157,-122.4595| 37.6825,-122.4387|
37.7109,-122.4893| 551| 1125| 775|
37.6431,-122.4792| 538| 699| 745|
37.7401,-122.4408| 703| 1277| 927|
Switch From Mapbox Distance Matrix
The switch from using Mapbox distance matrix services is nearly as easy as the Google migration. In our example, we needed to modify the inputs and outputs a bit more to deal with the returned elements from Mapbox and lat/lon input ordering but the overall solution is equally straightforward and with minimal changes. Take a look at the module `mb_dm.js` in the code repository for the reference implementation from Mapbox that we modified and transitioned to NextBillion.ai with ease.
var axios = require('axios');
const colorize = require('./utils');
module.exports = async function dm(originArray, destArray, points_origins, points_destinations, precision)
{
let idx = 0;
let origin_index = '';let dest_index = '';
orig_pts = '', dest_pts = '';
points_origins.forEach(pt => {
orig_pts += pt.geometry.coordinates[0].toFixed(precision) + ',' + pt.geometry.coordinates[1].toFixed(precision) + ';';
origin_index += idx++ + ';';
});
points_destinations.forEach(pt => {
dest_pts += pt.geometry.coordinates[0].toFixed(precision) + ',' + pt.geometry.coordinates[1].toFixed(precision) + ';';
dest_index += idx++ + ';';
});
dest_pts = dest_pts.slice(0, dest_pts.length - 1);
origin_index = origin_index.slice(0, origin_index.length - 1);
dest_index = dest_index.slice(0, dest_index.length - 1);
let mbUrl = `https://api.mapbox.com/directions-matrix/v1/mapbox/driving-traffic/${orig_pts}${dest_pts}?sources=${origin_index}&destinations=${dest_index}&access_token=${process.env['MAPBOX_TOKEN']}`;
var config = {
method: 'get',
url: mbUrl,
headers: {}
}
await axios(config)
.then( res => {
process.stdout.write(colorize(44,'...Mapbox result... '));
process.stdout.write('\n');
……..
Output from the Mapbox API call will look similar to this.
...Mapbox result...
| 37.7027,-122.4330| 37.7373,-122.4477| 37.7698,-122.4552|
37.6195,-122.4756| 1198| 1180| 1695|
37.6334,-122.4450| 1122| 1104| 1555|
37.5791,-122.3562| 1547| 1373| 1829|
Again, in order to migrate to NextBillion.ai distance matrix services, we are just making some changes to the API endpoint, HTTP method and the request body. The sample code shown in the Google example above applies to this migration as well.
Benefits
Hopefully, we’ve provided a sense of the ease with which a developer can migrate from using Google Maps or Mapbox distance matrix services. Once you’ve eliminated the technical barrier of a migration, you can begin to explore and potentially realize the added benefits that the NextBillion.ai services deliver. The image below from the original article is an excellent summary.
Check out the sample project in our repo here where we have the three implementations side by side for comparison.
Keep on mapping!
Ready to get started?
Request a DemoTable of Contents