We’ve all learned a lot about search engines over the last ten years or so. Everybody knows that the top Google result is the most relevant page for a given search term. By and large, search engines generally sort their results in order of decreasing relevance score.

So it makes sense that the Orchestrate search API does the same thing: every item in the result set gets a score, based on TF/IDF relevance, and the first results are those with the highest scores. If you’re adding full-text search functionality to your application, it’s extremely convenient.

But the Orchestrate platform is much more than just a schemaless database with a full-text search engine on the side. The search API is the primary mechanism for retrieving Orchestrate data for your application. With the Lucene query syntax, you can execute numerical and chronological filters (not just text queries), and in those cases, it doesn’t make much sense to use text relevance scoring to sort your results.

That’s why we’re happy to announce the release of an important new feature on the Orchestrate platform: Field Sorting for Search Results. You guys have been asking for it, and we’re ecstatically pleased to deliver.

With this new feature, whenever you use the search API, you can now request your search results to be sorted based on the values of any field. It’s an enormously powerful feature, and we think it will make it even easier to develop applications with Orchestrate.

Let me show you how it works.

First, I’ll post a few new JSON items to a collection:

{ "name" : "eggs", "calories" : 200 }
{ "name" : "spam", "calories" : 400 }
{ "name" : "eggs and spam", "calories" : 600 }
{ "name" : "spam and spam", "calories" : 800 }

Now I’ll execute a query to retrieve all the results where the item name contains the word “spam”:

curl -i https://api.orchestrate.io/v0/menu
             ?query=value.name:spam
     -u '12345678-1234-1234-1234-123456789012'

The results will be sorted by score, which is roughly proportional to the frequency of the word “spam” in the “name” field of each item. The items with the most relevant text show up first. That’s how the Orchestrate API has always worked:

HTTP/1.1 200 OK
X-ORCHESTRATE-REQ-ID: d66bbbc0-3f6c-11e4-b5bf-12313d2f7cdc
Content-Type: application/json

{
  "count": 3,
  "total_count": 3,
  "results": [{
    "path": {
      "collection": "menu",
      "key": "spam",
      "ref": "9dbe7618bd54a482"
    },
    "value": {
      "name": "spam",
      "calories": 400
    },
    "score": 13.784000396728516
  },{
    "path": {
      "collection": "menu",
      "key": "spam-and-spam",
      "ref": "0398cbde5d3b1a67"
    },
    "value": {
      "name": "spam and spam",
      "calories": 800
    },
    "score": 0.6570988893508911
  },{
    "path": {
      "collection": "menu",
      "key": "eggs-and-spam",
      "ref": "41c93a383e5cb826"
    },
    "value": {
      "name": "eggs and spam",
      "calories": 600
    },
    "score": 0.5931234359741211
  }]
}

But what if you want to sort the results alphabetically by name, or numerically by calorie count? Starting today, you can add a “sort” parameter to your query, specifying the field name and sort order, and your results will be returned in the order you expected. For example, we can find all the items containing “eggs” and sort them by ascending calorie count, like this:

curl -i https://api.orchestrate.io/v0/menu
             ?query=value.name:eggs
             &sort=value.calories:asc
     -u '12345678-1234-1234-1234-123456789012'

And the results will be exactly what you’d expect:

HTTP/1.1 200 OK
X-ORCHESTRATE-REQ-ID: aa7479b0-3f6e-11e4-9a10-22000a0d84a1
Content-Type: application/json

{
  "count": 2,
  "total_count": 2,
  "results": [{
    "path": {
      "collection": "menu",
      "key": "eggs",
      "ref": "9ccddbea058a5a7e"
    },
    "value": {
      "name": "eggs",
      "calories": 200
    },
    "score": null
  },{
    "path": {
      "collection": "menu",
      "key": "eggs-and-spam",
      "ref": "41c93a383e5cb826"
    },
    "value": {
      "name": "eggs and spam",
      "calories": 600
    },
    "score": null
  }]
}

As you can see, the results are sorted in ascending numeric order, according to the calorie count of each item. Nice! You’ll also probably notice that the scores are all null, since we skip relevance scoring whenever sorting by field values.

We could also sort in descending order by using “desc” as the suffix of the sort clause, instead of “asc”. If we omit the suffix completely, the results will be sorted in ascending order, since “asc” is the default.

You can even create cascading sorts, where a secondary sort field is used as a tie-breaker whenever multiple documents have identical values for the primary sort field. For example, consider the following list of users:

{ "name" : { "first" : "John", "last" : "Smith" }, "age" : 39 }
{ "name" : { "first" : "Anne", "last" : "Smith" }, "age" : 26 }
{ "name" : { "first" : "Mark", "last" : "Jones" }, "age" : 48 }
{ "name" : { "first" : "Anne", "last" : "Jones" }, "age" : 32 }

We could sort these users first by last name, and then by first name, using the following query:

curl -i https://api.orchestrate.io/v0/menu
             ?query=*
             &sort=value.name.last:asc,value.name.first:asc
     -u '12345678-1234-1234-1234-123456789012'

…which would return results in the correct order: Anne Jones, Mark Jones, Anne Smith, John Smith.

We could even sort on the “age” field and the results would then be sorted numerically.

We’re thrilled to have this feature in production, available today, on the Orchestrate platform. We can’t wait to see what you build with it.