You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mu...@apache.org on 2020/09/29 14:12:20 UTC

[lucene-solr] 01/03: SOLR-14333: Implement toString in Collapse filter (#1371)

This is an automated email from the ASF dual-hosted git repository.

munendrasn pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit abe0163b271a76c255e8aa31aaa7673207723d61
Author: Guna Sekhar Dora Kovvuru <gu...@gmail.com>
AuthorDate: Tue Sep 29 19:19:49 2020 +0530

    SOLR-14333: Implement toString in Collapse filter  (#1371)
---
 solr/CHANGES.txt                                   |   4 +
 .../solr/search/CollapsingQParserPlugin.java       | 147 +++++++++++++--------
 .../search/TestRandomCollapseQParserPlugin.java    |  53 ++++++--
 3 files changed, 144 insertions(+), 60 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 548c236..b5fc489 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -160,6 +160,10 @@ Other Changes
 
 * SOLR-14876: Upgrade to zookeeper 3.6.2 (odidev via Erick Erickson)
 
+* SOLR-14333: Implement toString in Collapse filter so that proper parsed queries returned in debug response.
+  Also, Deprecate unused constants NULL_COLLAPSE, NULL_IGNORE, NULL_EXPAND, HINT_MULTI_DOCVALUES in collapse parser.
+  (Guna Sekhar Dora Kovvuru, Munendra S N, Mike Drob)
+
 ==================  8.6.2 ==================
 
 Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release.
diff --git a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
index 05ae26e..9a1e740 100644
--- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
@@ -122,12 +122,57 @@ import static org.apache.solr.common.params.CommonParams.SORT;
 public class CollapsingQParserPlugin extends QParserPlugin {
 
   public static final String NAME = "collapse";
+  public static final String HINT_TOP_FC = "top_fc";
+
+  /**
+   * @deprecated use {@link NullPolicy} instead.
+   */
+  @Deprecated
   public static final String NULL_COLLAPSE = "collapse";
+  @Deprecated
   public static final String NULL_IGNORE = "ignore";
+  @Deprecated
   public static final String NULL_EXPAND = "expand";
-  public static final String HINT_TOP_FC = "top_fc";
+  @Deprecated
   public static final String HINT_MULTI_DOCVALUES = "multi_docvalues";
 
+  public enum NullPolicy {
+    IGNORE("ignore", 0),
+    COLLAPSE("collapse", 1),
+    EXPAND("expand", 2);
+
+    private final String name;
+    private final int code;
+
+    NullPolicy(String name, int code) {
+      this.name = name;
+      this.code = code;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public int getCode() {
+      return code;
+    }
+
+    public static NullPolicy fromString(String nullPolicy) {
+      if (StringUtils.isEmpty(nullPolicy)) {
+        return DEFAULT_POLICY;
+      }
+      switch (nullPolicy) {
+        case "ignore": return IGNORE;
+        case "collapse": return COLLAPSE;
+        case "expand": return EXPAND;
+        default:
+          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Invalid nullPolicy: " + nullPolicy);
+      }
+    }
+
+    static NullPolicy DEFAULT_POLICY = IGNORE;
+  }
+
 
   public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest request) {
     return new CollapsingQParser(qstr, localParams, params, request);
@@ -188,6 +233,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
       return 17 * (31 + selectorText.hashCode()) * (31 + type.hashCode());
     }
 
+    @Override
+    public String toString(){
+      return "GroupHeadSelector(selectorText=" + this.selectorText + ", type=" +this.type + ")";
+    }
+
     /**
      * returns a new GroupHeadSelector based on the specified local params
      */
@@ -221,11 +271,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
     public String hint;
     private boolean needsScores = true;
     private boolean needsScores4Collapsing = false;
-    private int nullPolicy;
+    private NullPolicy nullPolicy;
     private Set<BytesRef> boosted; // ordered by "priority"
-    public static final int NULL_POLICY_IGNORE = 0;
-    public static final int NULL_POLICY_COLLAPSE = 1;
-    public static final int NULL_POLICY_EXPAND = 2;
     private int size;
 
     public String getField(){
@@ -254,7 +301,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
       int hashCode = classHash();
       hashCode = 31 * hashCode + collapseField.hashCode();
       hashCode = 31 * hashCode + groupHeadSelector.hashCode();
-      hashCode = 31 * hashCode + nullPolicy;
+      hashCode = 31 * hashCode + nullPolicy.hashCode();
       return hashCode;
     }
 
@@ -279,7 +326,12 @@ public class CollapsingQParserPlugin extends QParserPlugin {
     }
 
     public String toString(String s) {
-      return s;
+      return "CollapsingPostFilter(field=" + this.collapseField +
+          ", nullPolicy=" + this.nullPolicy.getName() + ", " +
+          this.groupHeadSelector +
+          (hint == null ? "": ", hint=" + this.hint) +
+          ", size=" + this.size
+          + ")";
     }
 
     public CollapsingPostFilter(SolrParams localParams, SolrParams params, SolrQueryRequest request) {
@@ -354,16 +406,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
         }
       }
 
-      String nPolicy = localParams.get("nullPolicy", NULL_IGNORE);
-      if(nPolicy.equals(NULL_IGNORE)) {
-        this.nullPolicy = NULL_POLICY_IGNORE;
-      } else if (nPolicy.equals(NULL_COLLAPSE)) {
-        this.nullPolicy = NULL_POLICY_COLLAPSE;
-      } else if(nPolicy.equals((NULL_EXPAND))) {
-        this.nullPolicy = NULL_POLICY_EXPAND;
-      } else {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Invalid nullPolicy:"+nPolicy);
-      }
+      this.nullPolicy = NullPolicy.fromString(localParams.get("nullPolicy"));
     }
 
     @SuppressWarnings({"unchecked"})
@@ -392,7 +435,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
         return collectorFactory.getCollector(this.collapseField,
                                              this.groupHeadSelector,
                                              this.sortSpec,
-                                             this.nullPolicy,
+                                             this.nullPolicy.getCode(),
                                              this.hint,
                                              this.needsScores4Collapsing,
                                              this.needsScores,
@@ -552,7 +595,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
       this.ords = new IntIntDynamicMap(valueCount, -1);
       this.scores = new IntFloatDynamicMap(valueCount, -Float.MAX_VALUE);
       this.nullPolicy = nullPolicy;
-      if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      if(nullPolicy == NullPolicy.EXPAND.getCode()) {
         nullScores = new FloatArrayList();
       }
 
@@ -620,13 +663,13 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           ords.put(ord, globalDoc);
           scores.put(ord, score);
         }
-      } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         float score = scorer.score();
         if(score > nullScore) {
           nullScore = score;
           nullDoc = globalDoc;
         }
-      } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(nullPolicy == NullPolicy.EXPAND.getCode()) {
         collapsedSet.set(globalDoc);
         nullScores.add(scorer.score());
       }
@@ -716,9 +759,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           dummy.score = scores.get(ord);
         } else if(boosts && mergeBoost.boost(docId)) {
           //Ignore so it doesn't mess up the null scoring.
-        } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+        } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
           dummy.score = nullScore;
-        } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+        } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
           dummy.score = nullScores.get(++index);
         }
 
@@ -772,7 +815,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
       this.collapsedSet = new FixedBitSet(maxDoc);
       this.nullValue = nullValue;
       this.nullPolicy = nullPolicy;
-      if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      if(nullPolicy == NullPolicy.EXPAND.getCode()) {
         nullScores = new FloatArrayList();
       }
       this.cmap = new IntLongHashMap(size);
@@ -839,13 +882,13 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           long scoreDoc = (((long)Float.floatToRawIntBits(score))<<32)+globalDoc;
           cmap.indexInsert(idx, collapseValue, scoreDoc);
         }
-      } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         float score = scorer.score();
         if(score > this.nullScore) {
           this.nullScore = score;
           this.nullDoc = globalDoc;
         }
-      } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(nullPolicy == NullPolicy.EXPAND.getCode()) {
         collapsedSet.set(globalDoc);
         nullScores.add(scorer.score());
       }
@@ -917,9 +960,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           dummy.score = Float.intBitsToFloat((int)(scoreDoc>>32));
         } else if(boosts && mergeBoost.boost(globalDoc)) {
           //Ignore so boosted documents don't mess up the null scoring policies.
-        } else if (nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+        } else if (nullPolicy == NullPolicy.COLLAPSE.getCode()) {
           dummy.score = nullScore;
-        } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+        } else if(nullPolicy == NullPolicy.EXPAND.getCode()) {
           dummy.score = nullScores.get(nullScoreIndex++);
         }
 
@@ -1114,9 +1157,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           } else if (mergeBoost != null && mergeBoost.boost(globalDoc)) {
             //It's an elevated doc so no score is needed
             dummy.score = 0F;
-          } else if (nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+          } else if (nullPolicy == NullPolicy.COLLAPSE.getCode()) {
             dummy.score = nullScore;
-          } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+          } else if(nullPolicy == NullPolicy.EXPAND.getCode()) {
             dummy.score = nullScores.get(nullScoreIndex++);
           }
         }
@@ -1273,9 +1316,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
           } else if (mergeBoost != null && mergeBoost.boost(globalDoc)) {
             //Its an elevated doc so no score is needed
             dummy.score = 0F;
-          } else if (nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+          } else if (nullPolicy == NullPolicy.COLLAPSE.getCode()) {
             dummy.score = nullScore;
-          } else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+          } else if(nullPolicy == NullPolicy.EXPAND.getCode()) {
             dummy.score = nullScores.get(nullScoreIndex++);
           }
         }
@@ -1538,7 +1581,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
 
       if (this.needsScores) {
         this.scores = new IntFloatDynamicMap(valueCount, 0.0f);
-        if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+        if(nullPolicy == NullPolicy.EXPAND.getCode()) {
           nullScores = new FloatArrayList();
         }
       }
@@ -1648,7 +1691,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(ord, scorer.score());
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullVal)) {
           nullVal = currentVal;
           nullDoc = globalDoc;
@@ -1656,7 +1699,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = scorer.score();
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           nullScores.add(scorer.score());
@@ -1729,7 +1772,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(ord, scorer.score());
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullVal)) {
           nullVal = currentVal;
           nullDoc = globalDoc;
@@ -1737,7 +1780,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = scorer.score();
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           nullScores.add(scorer.score());
@@ -1807,7 +1850,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(ord, scorer.score());
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullVal)) {
           nullVal = currentVal;
           nullDoc = globalDoc;
@@ -1815,7 +1858,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = scorer.score();
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           nullScores.add(scorer.score());
@@ -1900,7 +1943,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(ord, score);
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullVal)) {
           nullVal = currentVal;
           nullDoc = globalDoc;
@@ -1911,7 +1954,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = score;
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           if (!needsScores4Collapsing) {
@@ -2001,7 +2044,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             }
           }
         }
-      } else if (this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if (this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if (-1 == nullDoc) {
           // we've never seen a doc with null collapse key yet, treat it as the null group head for now
           compareState.setNullGroupValues(contextDoc);
@@ -2024,7 +2067,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             }
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if (needsScores) {
           if (!needsScores4Collapsing) {
@@ -2094,7 +2137,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
 
       if(needsScores) {
         this.scores = new IntFloatDynamicMap(size, 0.0f);
-        if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+        if(nullPolicy == NullPolicy.EXPAND.getCode()) {
           nullScores = new FloatArrayList();
         }
       }
@@ -2236,7 +2279,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(index, scorer.score());
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullCompVal)) {
           nullCompVal = currentVal;
           nullDoc = globalDoc;
@@ -2244,7 +2287,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = scorer.score();
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           nullScores.add(scorer.score());
@@ -2329,7 +2372,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(index, scorer.score());
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullCompVal)) {
           nullCompVal = currentVal;
           nullDoc = globalDoc;
@@ -2337,7 +2380,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = scorer.score();
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           nullScores.add(scorer.score());
@@ -2445,7 +2488,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(index, score);
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if(comp.test(currentVal, nullCompVal)) {
           nullCompVal = currentVal;
           nullDoc = globalDoc;
@@ -2456,7 +2499,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             nullScore = score;
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if(needsScores) {
           if (!needsScores4Collapsing) {
@@ -2556,7 +2599,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             scores.put(index, score);
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+      } else if(this.nullPolicy == NullPolicy.COLLAPSE.getCode()) {
         if (-1 == nullDoc) {
           // we've never seen a doc with null collapse key yet, treat it as the null group head for now
           compareState.setNullGroupValues(contextDoc);
@@ -2579,7 +2622,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
             }
           }
         }
-      } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+      } else if(this.nullPolicy == NullPolicy.EXPAND.getCode()) {
         this.collapsedSet.set(globalDoc);
         if (needsScores) {
           if (!needsScores4Collapsing) {
diff --git a/solr/core/src/test/org/apache/solr/search/TestRandomCollapseQParserPlugin.java b/solr/core/src/test/org/apache/solr/search/TestRandomCollapseQParserPlugin.java
index 9149c19..e384d84 100644
--- a/solr/core/src/test/org/apache/solr/search/TestRandomCollapseQParserPlugin.java
+++ b/solr/core/src/test/org/apache/solr/search/TestRandomCollapseQParserPlugin.java
@@ -16,9 +16,10 @@
  */
 package org.apache.solr.search;
 
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.lucene.util.TestUtil;
 import org.apache.solr.CursorPagingTest;
@@ -27,14 +28,14 @@ import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.params.SolrParams;
-import static org.apache.solr.search.CollapsingQParserPlugin.NULL_IGNORE;
-import static org.apache.solr.search.CollapsingQParserPlugin.NULL_COLLAPSE;
-import static org.apache.solr.search.CollapsingQParserPlugin.NULL_EXPAND;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
+import static org.hamcrest.core.StringContains.containsString;
+
 public class TestRandomCollapseQParserPlugin extends SolrTestCaseJ4 {
 
   /** Full SolrServer instance for arbitrary introspection of response data and adding fqs */
@@ -43,7 +44,9 @@ public class TestRandomCollapseQParserPlugin extends SolrTestCaseJ4 {
   public static List<String> ALL_COLLAPSE_FIELD_NAMES;
 
   private static String[] NULL_POLICIES
-    = new String[] {NULL_IGNORE, NULL_COLLAPSE, NULL_EXPAND};
+    = new String[] {CollapsingQParserPlugin.NullPolicy.IGNORE.getName(),
+                    CollapsingQParserPlugin.NullPolicy.COLLAPSE.getName(),
+                    CollapsingQParserPlugin.NullPolicy.EXPAND.getName()};
   
   @BeforeClass
   public static void buildIndexAndClient() throws Exception {
@@ -143,7 +146,7 @@ public class TestRandomCollapseQParserPlugin extends SolrTestCaseJ4 {
           "" : " size=" + TestUtil.nextInt(random(),1,10000);
 
         final String nullPolicy = randomNullPolicy();
-        final String nullPs = NULL_IGNORE.equals(nullPolicy)
+        final String nullPs =  nullPolicy.equals(CollapsingQParserPlugin.NullPolicy.IGNORE.getName())
           // ignore is default, randomly be explicit about it
           ? (random().nextBoolean() ? "" : " nullPolicy=ignore")
           : (" nullPolicy=" + nullPolicy);
@@ -162,14 +165,14 @@ public class TestRandomCollapseQParserPlugin extends SolrTestCaseJ4 {
             final Object collapseVal = doc.getFieldValue(collapseField);
             
             if (null == collapseVal) {
-              if (NULL_EXPAND.equals(nullPolicy)) {
+              if (nullPolicy.equals(CollapsingQParserPlugin.NullPolicy.EXPAND.getName())) {
                 // nothing to check for this doc, it's in its own group
                 continue;
               }
               
               assertFalse(groupHeadId + " has null collapseVal but nullPolicy==ignore; " + 
                           "mainP: " + mainP + ", collapseP: " + collapseP,
-                          NULL_IGNORE.equals(nullPolicy));
+                          nullPolicy.equals(CollapsingQParserPlugin.NullPolicy.IGNORE.getName()));
             }
             
             // workaround for SOLR-8082...
@@ -204,6 +207,40 @@ public class TestRandomCollapseQParserPlugin extends SolrTestCaseJ4 {
       }
     }
   }
+  
+  public void testParsedFilterQueryResponse() throws Exception {
+    String nullPolicy = randomNullPolicy();
+    String groupHeadSort = "'_version_ asc'";
+    String collapseSize = "5000";
+    String collapseHint = "top_fc";
+    String filterQuery = "{!collapse field=id sort=" + groupHeadSort + " nullPolicy=" + nullPolicy + " size=" +
+                                collapseSize + " hint=" + collapseHint + "}";
+    SolrParams solrParams = params("q", "*:*", "rows", "0", "debug", "true", "fq", filterQuery);
+
+    QueryResponse response = SOLR.query(solrParams);
+    // Query name is occurring twice, this should be handled in QueryParsing.toString
+    String expectedParsedFilterString = "CollapsingPostFilter(CollapsingPostFilter(field=id, " +
+        "nullPolicy=" + nullPolicy + ", GroupHeadSelector(selectorText=" + groupHeadSort.substring(1,
+        groupHeadSort.length() - 1) + ", type=SORT" +
+        "), hint=" + collapseHint + ", size=" + collapseSize + "))";
+    List<String> expectedParsedFilterQuery = Collections.singletonList(expectedParsedFilterString);
+    assertEquals(expectedParsedFilterQuery, response.getDebugMap().get("parsed_filter_queries"));
+    assertEquals(Collections.singletonList(filterQuery), response.getDebugMap().get("filter_queries"));
+  }
+
+  public void testNullPolicy() {
+    String nullPolicy = "xyz";
+    String groupHeadSort = "'_version_ asc'";
+    String filterQuery = "{!collapse field=id sort=" + groupHeadSort + " nullPolicy=" + nullPolicy + "}";
+    SolrParams solrParams = params("q", "*:*", "fq", filterQuery);
+
+    SolrException e = expectThrows(SolrException.class, () -> SOLR.query(solrParams));
+    assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
+    assertThat(e.getMessage(), containsString("Invalid nullPolicy: " + nullPolicy));
+
+    // valid nullPolicy
+    assertQ(req("q", "*:*", "fq", "{!collapse field=id nullPolicy=" + randomNullPolicy() + "}"));
+  }
 
   private String randomNullPolicy() {
     return NULL_POLICIES[ TestUtil.nextInt(random(), 0, NULL_POLICIES.length-1) ];