From 2c8cfa678b27bb68912d5333ec2f0cb5a2d23017 Mon Sep 17 00:00:00 2001 From: Mikhail Khludnev Date: Sun, 26 Apr 2020 23:04:00 +0300 Subject: [PATCH] SOLR-14419: adding {param:ref} to Query DSL --- solr/CHANGES.txt | 2 + .../solr/request/json/JsonQueryConverter.java | 50 ++++++++++++------- .../solr/search/json/TestJsonRequest.java | 39 ++++++++++++++- 3 files changed, 73 insertions(+), 18 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index aeb79454643..28d855288ad 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -125,6 +125,8 @@ Improvements themselves. The collection hints are pushed down to the policy engine so operations for non-matching collections are not computed at all. (ab, shalin) +* SOLR-14419: json.queries as well as other parameters might be referred via {"param":"ref"} in Query DSL (Mikhail Khludnev) + Optimizations --------------------- * SOLR-8306: Do not collect expand documents when expand.rows=0 (Marshall Sanders, Amelia Henderson) diff --git a/solr/core/src/java/org/apache/solr/request/json/JsonQueryConverter.java b/solr/core/src/java/org/apache/solr/request/json/JsonQueryConverter.java index 22e15c7af2f..e7367500e55 100644 --- a/solr/core/src/java/org/apache/solr/request/json/JsonQueryConverter.java +++ b/solr/core/src/java/org/apache/solr/request/json/JsonQueryConverter.java @@ -98,6 +98,18 @@ private void buildLocalParams(StringBuilder builder, Object val, boolean isQPars qtype = map.keySet().iterator().next(); // FUTURE: might want to recurse here instead to handle nested tags (and add tagName as a parameter?) } + } else { + if (qtype.equals("param")) { + boolean toplevel; + if (toplevel=(builder.length() == 0)) { + builder.append("{!v="); + } + builder.append("$").append(map.get("param")); + if (toplevel) { + builder.append("}"); + } + return; + } } StringBuilder subBuilder = useSubBuilder ? new StringBuilder() : builder; @@ -114,26 +126,30 @@ private void buildLocalParams(StringBuilder builder, Object val, boolean isQPars builder.append('$').append(putParam(subBuilder.toString(), additionalParams)); } } else { - for (Map.Entry entry : map.entrySet()) { - String key = entry.getKey(); - if (entry.getValue() instanceof List) { - if (key.equals("query")) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, - "Error when parsing json query, value of query field should not be a list, found : " + entry.getValue()); - } - List l = (List) entry.getValue(); - for (Object subVal : l) { + if(map.size()==1 && map.keySet().iterator().next().equals("param")) { + builder.append("v").append("=$").append(map.get("param")).append(" "); + } else { + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + if (entry.getValue() instanceof List) { + if (key.equals("query")) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, + "Error when parsing json query, value of query field should not be a list, found : " + entry.getValue()); + } + List l = (List) entry.getValue(); + for (Object subVal : l) { + builder.append(key).append("="); + buildLocalParams(builder, subVal, true, additionalParams); + builder.append(" "); + } + } else { + if (key.equals("query")) { + key = "v"; + } builder.append(key).append("="); - buildLocalParams(builder, subVal, true, additionalParams); + buildLocalParams(builder, entry.getValue(), true, additionalParams); builder.append(" "); } - } else { - if (key.equals("query")) { - key = "v"; - } - builder.append(key).append("="); - buildLocalParams(builder, entry.getValue(), true, additionalParams); - builder.append(" "); } } } diff --git a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java index 2ab19e98ac3..9451ddf9ec7 100644 --- a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java +++ b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java @@ -24,6 +24,7 @@ import org.apache.solr.SolrTestCaseHS; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.CaffeineCache; import org.apache.solr.search.DocSet; @@ -179,7 +180,7 @@ public static void doJsonRequest(Client client, boolean isDistrib) throws Except , "response/docs==[{id:'5', x:5.5},{id:'4', x:5.5}]" ); - + doParamRefDslTest(client); // test templating before parsing JSON client.testJQ( params("json","${OPENBRACE} query:'cat_s:A' ${CLOSEBRACE}", "json","${OPENBRACE} filter:'where_s:NY'${CLOSEBRACE}", "OPENBRACE","{", "CLOSEBRACE","}") @@ -407,6 +408,42 @@ public static void doJsonRequest(Client client, boolean isDistrib) throws Except } + private static void doParamRefDslTest(Client client) throws Exception { + // referencing in dsl //nestedqp + client.testJQ( params("json","{query: {query: {param:'ref1'}}}", "ref1","{!field f=cat_s}A") + , "response/numFound==2" + ); + // referencing json string param + client.testJQ( params("json", random().nextBoolean() ? + "{query:{query:{param:'ref1'}}}" // nestedqp + : "{query: {query: {query:{param:'ref1'}}}}", // nestedqp, v local param + "json",random().nextBoolean() + ? "{params:{ref1:'{!field f=cat_s}A'}}" // string param + : "{queries:{ref1:{field:{f:cat_s,query:A}}}}" ) // qdsl + , "response/numFound==2" + ); + { // shortest top level ref + final ModifiableSolrParams params = params("json","{query:{param:'ref1'}}"); + if (random().nextBoolean()) { + params.add("ref1","cat_s:A"); // either to plain string + } else { + params.add("json","{queries:{ref1:{field:{f:cat_s,query:A}}}}");// or to qdsl + } + client.testJQ( params, "response/numFound==2"); + } // ref in bool must + client.testJQ( params("json","{query:{bool: {must:[{param:fq1},{param:fq2}]}}}", + "json","{params:{fq1:'cat_s:A', fq2:'where_s:NY'}}", "json.fields", "id") + , "response/docs==[{id:'1'}]" + );// referencing dsl&strings from filters objs&array + client.testJQ( params("json.filter","{param:fq1}","json.filter","{param:fq2}", + "json", random().nextBoolean() ? + "{queries:{fq1:{lucene:{query:'cat_s:A'}}, fq2:{lucene:{query:'where_s:NY'}}}}" : + "{params:{fq1:'cat_s:A', fq2:'where_s:NY'}}", + "json.fields", "id", "q", "*:*") + , "response/docs==[{id:'1'}]" + ); + } + private static void testFilterCachingLocally(Client client) throws Exception { if(client.getClientProvider()==null) { final SolrQueryRequest request = req();