From c3c9f36855253eada0c3009098bfa87c68b15fb6 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Tue, 6 Oct 2026 22:10:54 -0400 Subject: [PATCH 1/7] SOLR-8088: reject distributed grouping on a multiValued field with a clear 400 Hypothetical, unrun regression test; see SOLR-8088-TESTING.md. --- .../command/SearchGroupsFieldCommand.java | 16 +++++ .../command/TopGroupsFieldCommand.java | 1 + .../command/SearchGroupsFieldCommandTest.java | 61 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 solr/core/src/test/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommandTest.java diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java index c4d98a65a216..e915b14c78eb 100644 --- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java +++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommand.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.grouping.ValueSourceGroupSelector; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.mutable.MutableValue; +import org.apache.solr.common.SolrException; import org.apache.solr.schema.FieldType; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.grouping.Command; @@ -70,10 +71,25 @@ public SearchGroupsFieldCommand build() { throw new IllegalStateException("All fields must be set"); } + checkGroupable(field); return new SearchGroupsFieldCommand(field, groupSort, topNGroups, includeGroupCount); } } + /** + * Term based grouping reads single valued docValues; a multiValued field fails deep inside Lucene + * ("unexpected docvalues type SORTED_SET"), so reject it with a clear message instead. + */ + static void checkGroupable(SchemaField field) { + if (field.getType().getNumberType() == null && field.multiValued()) { + throw new SolrException( + SolrException.ErrorCode.BAD_REQUEST, + "Distributed grouping requires a single valued field, but '" + + field.getName() + + "' is multiValued; group on a single valued (e.g. copyField) field instead"); + } + } + private final SchemaField field; private final Sort groupSort; private final int topNGroups; diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java index dc9300c93e5f..4199f051cd8a 100644 --- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java +++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/command/TopGroupsFieldCommand.java @@ -106,6 +106,7 @@ public TopGroupsFieldCommand build() { throw new IllegalStateException("All required fields must be set"); } + SearchGroupsFieldCommand.checkGroupable(field); return new TopGroupsFieldCommand( query, field, diff --git a/solr/core/src/test/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommandTest.java b/solr/core/src/test/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommandTest.java new file mode 100644 index 000000000000..e8e46626a56d --- /dev/null +++ b/solr/core/src/test/org/apache/solr/search/grouping/distributed/command/SearchGroupsFieldCommandTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.solr.search.grouping.distributed.command; + +import org.apache.lucene.search.Sort; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.common.SolrException; +import org.apache.solr.schema.SchemaField; +import org.junit.BeforeClass; +import org.junit.Test; + +public class SearchGroupsFieldCommandTest extends SolrTestCaseJ4 { + + @BeforeClass + public static void beforeClass() throws Exception { + initCore("solrconfig.xml", "schema.xml"); + } + + @Test + public void testMultiValuedFieldIsRejected() { + SchemaField cat = h.getCore().getLatestSchema().getField("cat"); + assertTrue(cat.multiValued()); + + SolrException e = + expectThrows( + SolrException.class, + () -> + new SearchGroupsFieldCommand.Builder() + .setField(cat) + .setGroupSort(Sort.RELEVANCE) + .setTopNGroups(10) + .build()); + assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code()); + assertTrue(e.getMessage(), e.getMessage().contains("'cat' is multiValued")); + } + + @Test + public void testSingleValuedFieldIsAccepted() { + SchemaField id = h.getCore().getLatestSchema().getField("id"); + assertFalse(id.multiValued()); + new SearchGroupsFieldCommand.Builder() + .setField(id) + .setGroupSort(Sort.RELEVANCE) + .setTopNGroups(10) + .build(); + } +} From 6863082aa7c9b8c09be403c8375e1fbe87976b98 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Tue, 6 Oct 2026 22:10:56 -0400 Subject: [PATCH 2/7] SOLR-8088: add changelog fragment --- changelog/unreleased/SOLR-8088-grouping-multivalued.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changelog/unreleased/SOLR-8088-grouping-multivalued.yml diff --git a/changelog/unreleased/SOLR-8088-grouping-multivalued.yml b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml new file mode 100644 index 000000000000..d8a73a52d033 --- /dev/null +++ b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml @@ -0,0 +1,8 @@ +title: Distributed grouping on a multiValued field now fails with a clear 400 instead of an IllegalStateException from Lucene docValues. +type: fixed +authors: + - name: Nick Shanin + nick: nick-boss-tech +links: + - name: SOLR-8088 + url: https://issues.apache.org/jira/browse/SOLR-8088 From 2398c9bea08528c4ccccf255d3bd1205ff9ee79a Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Tue, 6 Oct 2026 22:10:57 -0400 Subject: [PATCH 3/7] SOLR-8088: add hypothetical-reproduction handoff doc --- SOLR-8088-TESTING.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 SOLR-8088-TESTING.md diff --git a/SOLR-8088-TESTING.md b/SOLR-8088-TESTING.md new file mode 100644 index 000000000000..65a8339581a6 --- /dev/null +++ b/SOLR-8088-TESTING.md @@ -0,0 +1,18 @@ +# SOLR-8088 - hypothetical reproduction (NOT RUN) + +Guessed, never compiled or executed. No Gradle was run. + +JIRA: distributed grouping on a (tokenized, multi-valued docValues) field fails with +`IllegalStateException: unexpected docvalues type SORTED_SET ... (expected=SORTED)`, while a single-shard request works. +Yonik: fallout of LUCENE-5666 (no uninverting); no general fix. Smaller piece done here: a clear 400 up front. + +Change: `SearchGroupsFieldCommand.checkGroupable` (also used by `TopGroupsFieldCommand.Builder`) throws BAD_REQUEST for a +non-numeric multiValued group field. Numeric fields use the ValueSource path and are unchanged. + +Test: new `SearchGroupsFieldCommandTest` (builder level, no cluster). + +Guesses to verify first: +- The failure is multiValued-related (SORTED_SET) rather than a missing-docValues case; a single-valued field without docValues is deliberately NOT rejected + because existing distributed tests may rely on it. +- schema.xml `cat` is multiValued string, `id` single valued. +- Whether a Builder-level check fires before the shard-side failure in the real request path (it is built per shard request). From 567efa9b78c32df3454ed431a40a04c06ed09d46 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Sat, 10 Oct 2026 01:19:40 +0000 Subject: [PATCH 4/7] SOLR-8088: remove handoff doc --- SOLR-8088-TESTING.md | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 SOLR-8088-TESTING.md diff --git a/SOLR-8088-TESTING.md b/SOLR-8088-TESTING.md deleted file mode 100644 index 65a8339581a6..000000000000 --- a/SOLR-8088-TESTING.md +++ /dev/null @@ -1,18 +0,0 @@ -# SOLR-8088 - hypothetical reproduction (NOT RUN) - -Guessed, never compiled or executed. No Gradle was run. - -JIRA: distributed grouping on a (tokenized, multi-valued docValues) field fails with -`IllegalStateException: unexpected docvalues type SORTED_SET ... (expected=SORTED)`, while a single-shard request works. -Yonik: fallout of LUCENE-5666 (no uninverting); no general fix. Smaller piece done here: a clear 400 up front. - -Change: `SearchGroupsFieldCommand.checkGroupable` (also used by `TopGroupsFieldCommand.Builder`) throws BAD_REQUEST for a -non-numeric multiValued group field. Numeric fields use the ValueSource path and are unchanged. - -Test: new `SearchGroupsFieldCommandTest` (builder level, no cluster). - -Guesses to verify first: -- The failure is multiValued-related (SORTED_SET) rather than a missing-docValues case; a single-valued field without docValues is deliberately NOT rejected - because existing distributed tests may rely on it. -- schema.xml `cat` is multiValued string, `id` single valued. -- Whether a Builder-level check fires before the shard-side failure in the real request path (it is built per shard request). From c36cfc094af45ef3209f2eefa0aab7621407fae0 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Wed, 14 Oct 2026 21:07:16 +0000 Subject: [PATCH 5/7] SOLR-8088: narrow the changelog title to multiValued non-numeric fields --- changelog/unreleased/SOLR-8088-grouping-multivalued.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/unreleased/SOLR-8088-grouping-multivalued.yml b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml index d8a73a52d033..04741201c607 100644 --- a/changelog/unreleased/SOLR-8088-grouping-multivalued.yml +++ b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml @@ -1,4 +1,4 @@ -title: Distributed grouping on a multiValued field now fails with a clear 400 instead of an IllegalStateException from Lucene docValues. +title: Distributed grouping on a multiValued non-numeric field now fails with a clear 400 instead of an IllegalStateException from Lucene docValues. type: fixed authors: - name: Nick Shanin From 0f473402de035508ec9c1b1cb9a2d5453ee72a29 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Thu, 15 Oct 2026 03:35:43 -0400 Subject: [PATCH 6/7] SOLR-8088: assert a distributed multiValued group field returns 400; drop nick from changelog --- .../SOLR-8088-grouping-multivalued.yml | 1 - .../apache/solr/TestDistributedGrouping.java | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/changelog/unreleased/SOLR-8088-grouping-multivalued.yml b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml index 04741201c607..38f8eae540f1 100644 --- a/changelog/unreleased/SOLR-8088-grouping-multivalued.yml +++ b/changelog/unreleased/SOLR-8088-grouping-multivalued.yml @@ -2,7 +2,6 @@ title: Distributed grouping on a multiValued non-numeric field now fails with a type: fixed authors: - name: Nick Shanin - nick: nick-boss-tech links: - name: SOLR-8088 url: https://issues.apache.org/jira/browse/SOLR-8088 diff --git a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java index 28fab47d83b9..cd0de762c0d1 100644 --- a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java +++ b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.solr.SolrTestCaseJ4.SuppressPointFields; import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrException; @@ -1727,6 +1728,23 @@ public void testShardRequestFactory() throws Exception { } } + @Test + public void testMultiValuedGroupFieldIsBadRequest() throws Exception { + index("id", "1", "cat", "a"); + commit(); + + ModifiableSolrParams params = new ModifiableSolrParams(); + params.set("q", "*:*"); + params.set("group", "true"); + params.set("group.field", "cat"); + setDistributedParams(params); + + SolrException e = + expectThrows( + SolrException.class, () -> new QueryRequest(params).process(clients.get(0))); + assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code()); + } + private QueryResponse simpleQuery(Object... queryParams) throws Exception { ModifiableSolrParams params = new ModifiableSolrParams(); for (int i = 0; i < queryParams.length; i += 2) { From 0a5eaf4b2cb61634a70dd3a309ca8b1222ab4bb8 Mon Sep 17 00:00:00 2001 From: Nick Shanin Date: Fri, 16 Oct 2026 00:18:29 +0000 Subject: [PATCH 7/7] SOLR-8088: apply tidy formatting to TestDistributedGrouping --- .../core/src/test/org/apache/solr/TestDistributedGrouping.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java index cd0de762c0d1..13173db55b40 100644 --- a/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java +++ b/solr/core/src/test/org/apache/solr/TestDistributedGrouping.java @@ -1740,8 +1740,7 @@ public void testMultiValuedGroupFieldIsBadRequest() throws Exception { setDistributedParams(params); SolrException e = - expectThrows( - SolrException.class, () -> new QueryRequest(params).process(clients.get(0))); + expectThrows(SolrException.class, () -> new QueryRequest(params).process(clients.get(0))); assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code()); }