JSON Request API

Solr supports an alternate request API which accepts requests composed in part or entirely of JSON objects. This alternate API can be preferable in some situations, where its increased readability and flexibility make it easier to use than the entirely query-param driven alternative. There is also some functionality which can only be accessed through this JSON request API, such as much of the analytics capabilities of JSON Faceting

Building JSON Requests

The core of the JSON Request API is its ability to specify request parameters as JSON in the request body, as shown by the example below:

curl

curl http://localhost:8983/solr/techproducts/query -d '
{
  "query" : "memory",
  "filter" : "inStock:true"
}'

SolrJ

final JsonQueryRequest simpleQuery = new JsonQueryRequest()
    .setQuery("memory")
    .withFilter("inStock:true");
QueryResponse queryResponse = simpleQuery.process(solrClient, COLLECTION_NAME);

JSON objects are typically sent in the request body, but they can also be sent as values for json-prefixed query parameters. This can be used to override or supplement values specified in the request body. For example the query parameter json.limit=5 will override any limit value provided in the JSON request body. You can also specify the entire JSON body in a single json query parameter, as shown in the example below:

curl http://localhost:8983/solr/techproducts/query -d 'json={"query":"memory"}'

JSON Parameter Merging

If multiple json parameters are provided in a single request, Solr attempts to merge the parameter values together before processing the request.

The JSON Request API has several properties (filter, fields, etc) which accept multiple values. During the merging process, all values for these "multivalued" properties are retained. Many properties though (query, limit, etc.) can have only a single value. When multiple parameter values conflict with one another a single value is chosen based on the following precedence rules:

  • Traditional query parameters (q, rows, etc.) take first precedence and are used over any other specified values.
  • json-prefixed query parameters are considered next.
  • Values specified in the JSON request body have the lowest precedence and are only used if specified nowhere else.

This layered merging gives the best of both worlds. Requests can be specified using readable, structured JSON. But users also have the flexibility to separate out parts of the request that change often. This can be seen at work in the following example, which combines json.-style parameters to override and supplement values found in the main JSON body.

curl

curl 'http://localhost:8983/solr/techproducts/query?json.limit=5&json.filter="cat:electronics"' -d '
{
  query: "memory",
  limit: 10,
  filter: "inStock:true"
}'

SolrJ

final ModifiableSolrParams overrideParams = new ModifiableSolrParams();
final JsonQueryRequest queryWithParamOverrides = new JsonQueryRequest(overrideParams)
    .setQuery("memory")
    .setLimit(10)
    .withFilter("inStock:true");
overrideParams.set("json.limit", 5);
overrideParams.add("json.filter", "\"cat:electronics\"");
QueryResponse queryResponse = queryWithParamOverrides.process(solrClient, COLLECTION_NAME);

This is equivalent to:

curl

curl http://localhost:8983/solr/techproducts/query -d '
{
  "query": "memory",
  "limit": 5,     // this single-valued parameter was overwritten.
  "filter": ["inStock:true","cat:electronics"]    // this multi-valued parameter was appended to.
}'

SolrJ

final JsonQueryRequest query = new JsonQueryRequest()
    .setQuery("memory")
    .setLimit(5)
    .withFilter("inStock:true")
    .withFilter("cat:electronics");
QueryResponse queryResponse = query.process(solrClient, COLLECTION_NAME);

Similarly, smart merging can be used to create JSON API requests which have no proper request body at all, such as the example below:

curl

curl http://localhost:8983/solr/techproducts/query -d 'q=*:*&rows=1&
  json.facet.avg_price="avg(price)"&
  json.facet.top_cats={type:terms,field:"cat",limit:3}'

SolrJ

final ModifiableSolrParams params = new ModifiableSolrParams();
final SolrQuery query = new SolrQuery("*:*");
query.setRows(1);
query.setParam("json.facet.avg_price", "\"avg(price)\"");
query.setParam("json.facet.top_cats", "{type:terms,field:\"cat\",limit:3}");
QueryResponse queryResponse = solrClient.query(COLLECTION_NAME, query);

That is equivalent to the following request:

curl

curl http://localhost:8983/solr/techproducts/query -d '
{
  "query": "*:*",
  "limit": 1,
  "facet": {
    "avg_price": "avg(price)",
    "top_cats": {
      "type": "terms",
      "field": "cat",
      "limit": 5
    }
  }
}
'

SolrJ

final JsonQueryRequest jsonQueryRequest = new JsonQueryRequest()
    .setQuery("*:*")
    .setLimit(1)
    .withStatFacet("avg_price", "avg(price)")
    .withFacet("top_cats", new TermsFacetMap("cat").setLimit(3));
QueryResponse queryResponse = jsonQueryRequest.process(solrClient, COLLECTION_NAME);

See the JSON Facet API for more on faceting and analytics commands.

Supported Properties and Syntax

Right now, only some of Solr’s traditional query parameters have first class JSON equivalents. Those that do are shown in the table below:

Table 1. Standard query parameters to JSON field
Query parametersJSON field equivalent
qquery
fqfilter
startoffset
rowslimit
flfields
sortsort
json.facetfacet
json.<param_name><param_name>

Parameters not specified in the table above can still be used in the main body of JSON API requests, but they must be put within a params block as shown in the example below.

curl

curl "http://localhost:8983/solr/techproducts/query?fl=name,price"-d '
{
  params: {
    q: "memory",
    rows: 1
  }
}'

SolrJ

final ModifiableSolrParams params = new ModifiableSolrParams();
params.set("fl", "name", "price");
final JsonQueryRequest simpleQuery = new JsonQueryRequest(params)
    .withParam("q", "memory")
    .withParam("rows", 1);
QueryResponse queryResponse = simpleQuery.process(solrClient, COLLECTION_NAME);

Parameters placed in a params block act as if they were added verbatim to the query-parameters of the request. The request above is equivalent to:

curl "http://localhost:8983/solr/techproducts/query?fl=name,price&q=memory&rows=1"

Parameter Substitution / Macro Expansion

Of course request templating via parameter substitution works fully with JSON request bodies or parameters as well. For example:

curl

curl "http://localhost:8983/solr/techproducts/query?FIELD=text&TERM=memory" -d '
{
  query:"${FIELD}:${TERM}",
}'

SolrJ

final ModifiableSolrParams params = new ModifiableSolrParams();
params.set("FIELD", "text");
params.set("TERM", "memory");
final JsonQueryRequest simpleQuery = new JsonQueryRequest(params)
    .setQuery("${FIELD}:${TERM}");
QueryResponse queryResponse = simpleQuery.process(solrClient, COLLECTION_NAME);

JSON Extensions

Solr uses the Noggit JSON parser in its request API. Noggit is capable of more relaxed JSON parsing, and allows a number of deviations from the JSON standard:

  • bare words can be left unquoted
  • single line comments can be inserted using either // or #
  • Multi-line ("C style") comments can be inserted using /* and */
  • strings can be single-quoted
  • special characters can be backslash-escaped
  • trailing (extra) commas are silently ignored (e.g., [9,4,3,])
  • nbsp (non-break space, \u00a0) is treated as whitespace.

Debugging

If you want to see what your merged/parsed JSON looks like, you can turn on debugging (debug=timing), and it will come back under the "json" key along with the other debugging information. Note that debug=true and debugQuery=true can often have significant performance implications, and should be reserved for debugging. Also note that debug=query has no effect on JSON facets in SolrCloud.