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:
Query parameters | JSON field equivalent |
---|---|
q | query |
fq | filter |
start | offset |
rows | limit |
fl | fields |
sort | sort |
json.facet | facet |
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.