Ten years ago, computers mostly sat still under our desks, quietly humming to themselves. And then, suddenly, as the prices of gyroscopes and accelerometers and GPS radios plummeted, our computers crawled out from their stationary hiding places, into our backpacks and pockets, and onto our wrists. A typical new car has more than 50 microprocessors under the hood. Every photo you snap has an embedded longitude and latitude, and if you’re a fitness buff, your morning bike ride probably traces a digital path through your neighborhood streets.

Starting today, you can capture those real-world locations in your Orchestrate collections and use our powerful geospatial search API to help you make sense of the data.

paris-phoneFor example, let’s pretend I’m building a mobile photo-sharing application. For every photo taken by one of my users, you can imagine generating a JSON item like one of these:

{
  "created_by" : "BenjiSmith",
  "timestamp" : "2014-09-27T18:35:07.167-07:00",
  "description" : "Me and Emily, at the Eiffel Tower",
  "location" : {
    "country" : "France",
    "latitude" : 48.85885,
    "longitude" : 2.29583
  }
}

orchestrate-paris-phone

For starters, we could plot all the photos on a map, showing where each was taken. Ideally, the application would let the user pan and zoom around on the map, which would update to include only the photos snapped within the current bounding box of the map viewport. But until now, there hasn’t been an efficient way to write geospatial queries (especially in areas of the world near the poles or crossing the international date line).

To solve that problem, we’re happy to introduce a new kind of query, the “Geo Bounding Box Query” to the Orchestrate search API. The syntax looks like this:

curl -i https://api.orchestrate.io/v0/photos?query=
        value.location:IN:{north:49.2 south:48.5 east:2.8 west:1.9}
     -u '12345678-1234-1234-1234-123456789012'

Using the parameters “north”, “south”, “east”, and “west”, you create a bounding box, and the search engine will find all photos snapped within those boundaries.

orchestrate-paris-box

You can also get the same results by using single-letter abbreviations for each of the cardinal directions:

curl -i https://api.orchestrate.io/v0/photos
        ?query=value.location:IN:{n:49.2 s:48.5 e:2.8 w:1.9}
     -u '12345678-1234-1234-1234-123456789012'

With bounding-box queries, I can easily build a map view and populate it with pictures. But what if I’d also like to show each user a collection of photos taken near by their current location? For those kinds of situations, we’ve created another new kind of query, called the “Geo Distance Query”. For example, if I had a friend near me, checking out the art exhibits at the Louvre, she could find my picture at the Eiffel Tower by executing this search using her own local coordinates and a distance argument of 10 kilometers:

curl -i https://api.orchestrate.io/v0/photos
        ?query=value.location:NEAR:{lat:48.861 lon:2.336 dist:10km}
     -u '12345678-1234-1234-1234-123456789012'

orchestrate-paris-radius.png

The query syntax recognizes a variety of different abbreviations for the anchor-point coordinates (latitude, lat; longitude, lon, long, lng) as well as for the cutoff radius (distance, dist, dst, radius, rad). The distance argument should include a number with a distance-unit suffix. Possible suffixes include metric units (km, m, cm, mm) as well as imperial units (mi, yd, ft, in). You can even specify the radius in nautical miles (nmi) and show all those landlubbers who’s boss.

Anyhow, since the Louvre is only about 3.1 km from the Eiffel Tower, my picture would definitely be included in her search results. But in a busy area like downtown Paris, there might be thousands of photos within this 10 km radius, and without specifying a sort clause, the results will be returned in essentially random order. We can solve the problem by including a special distance sorting clause with our query, like this:

curl -i https://api.orchestrate.io/v0/photos
        ?query=value.location:NEAR:{lat:48.861 lon:2.336 dist:10km}
        &sort=location:distance:asc
     -u '12345678-1234-1234-1234-123456789012'

The :distance syntax is an extension to the field sorting syntax we recently introduced, and of course, you can only use it when your query includes a NEAR clause as shown above.

Whenever a distance-sort is in effect, the API server will generate a slightly different response than what you’re used to seeing:

{
  "count" : 1,
  "total_count" : 1,
  "results" : [
    {
      "path" : {
        "collection" : "photos",
        "key" : "abc123",
        "ref" : "cdfac1c04f3fa321"
      },
      "value" : {
        "created_by" : "BenjiSmith",
        "timestamp" : "2014-09-27T18:35:07.167-07:00",
        "description" : "Me and Emily, at the Eiffel Tower",
        "location" : {
          "country" : "France",
          "latitude" : 48.85885,
          "longitude" : 2.29583
        }
      },
      "distance" : 3.082
    }
  ]
}

Normally, the response items from the search API contain three fields: path, value, and score. But in this case, since we’re using a Geo Distance Query with a distance sort, the score is omitted and in its place, a distance value is returned. This is the distance between the anchor point specified in the query and the coordinates embedded in the item, using whichever the same units of measurement as the original query.

In this case, we used kilometers. If we had formulated our original query in miles, then the distance result would have been about 1.915 (since 3.082 km == 1.915 mi).

So how can you make your own data compatible with these queries?

Behind the scenes, Orchestrate creates a specialized geospatial index for any set of coordinates it finds within your JSON data. The recognition is based on a simple heuristic:

Any JSON object, at any level of depth within an object hierarchy, will be recognized by the geospatial engine if it contains a latitude and longitude field with numerical values. Latitude fields must be named either “latitude” or “lat”, while longitude fields must be named “longitude”, “long”, “lon”, or “lng”. Names are case-insensitive, so you can use fields named “LAT” or “Long” too.

For example, consider the following item JSON:

{
  "message" : "hello world!",
  "lat" : 12.34,
  "lon" : 56.78
}

Since the “lat” and “lon” values are nested at the root level of the object, our query will use the root-level field name “value”, like this:

curl -i https://api.orchestrate.io/v0/collection
        ?query=value:NEAR:{lat:12.34 lon:56.78 dist:10km}
     -u '12345678-1234-1234-1234-123456789012'

In many cases, the geo coordinates will be deeply nested within the structure of the JSON. There might even be multiple distinct sets of coordinates within the same JSON item, and we can write queries that target them individually.

For example, imagine a database of hiking trails, with entries that all look something like this:

{
  "route" : "Appalachian Trail",
  "description" : "The trail was conceived by Benton MacKaye...",
  "miles" : 2168.1,
  "start" : {
    "name" : "Springer Mountain",
    "state" : "Georgia",
    "trailhead" : {
      "latitude" : 34.6267,
      "longitude" : -84.1936
    }
  },
  "end" : {
    "name" : "Mount Katahdin",
    "state" : "Maine",
    "trailhead" : {
      "latitude" : 45.9044,
      "longitude" : -68.9213
    }
  }
}

To find hiking trails that start and end within 100 miles of Portland, OR, having a total distance of less than 50 miles and lots of waterfalls, I might execute a query like this:

curl -i https://api.orchestrate.io/v0/collection?query=
      value.start.trailhead:NEAR:{lat:45.52 lon:-122.68 dist:100mi}
      AND
      value.end.trailhead:NEAR:{lat:45.52 lon:-122.68 dist:100mi}
      AND
      value.miles[* TO 50]
      AND
      value.description:waterfall
     -u '12345678-1234-1234-1234-123456789012'

Building complex, sophisticated applications with the Orchestrate platform is incredibly easy. Especially now, with the addition of the Geo Bounding Box Query and the Geo Distance Query, the search API is more powerful than ever.

We can’t wait to see what you build!