This is an automated email from the ASF dual-hosted git repository.
eldenmoon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 04cae614aaa [feat](Variant) Support NestedGroup public config (#64680)
04cae614aaa is described below
commit 04cae614aaa967f41c25a4520f32bd116eb6e2f1
Author: lihangyu <[email protected]>
AuthorDate: Wed Jun 24 10:50:24 2026 +0800
[feat](Variant) Support NestedGroup public config (#64680)
This PR exposes `variant_enable_nested_group` as a public VARIANT
property and wires the related configuration through parser/type
serialization.
Main changes:
- Allow `variant_enable_nested_group` in VARIANT predefined fields.
- Disable doc mode and sparse-column related options when NestedGroup is
enabled.
- Serialize `variant_enable_nested_group` in `VariantType#toSql`.
- Add `variant_nested_group_max_depth` config and make the default
NestedGroup write provider explicitly return not-supported status when
the write path is unavailable.
- Update FE/BE tests for parser behavior, type serialization, and
disabled NestedGroup write-path handling.
---
be/src/common/config.cpp | 6 +++++-
.../segment/variant/nested_group_provider.cpp | 12 ++++++++----
.../storage/segment/nested_group_provider_test.cpp | 20 +++++++++++++++++++-
.../segment/variant_column_writer_reader_test.cpp | 14 ++++++++++++++
.../doris/nereids/parser/LogicalPlanBuilder.java | 7 +++++--
.../java/org/apache/doris/catalog/TypeTest.java | 4 ++--
.../doris/nereids/parser/NereidsParserTest.java | 21 +++++++++++++++++++--
.../java/org/apache/doris/catalog/VariantType.java | 5 +++++
.../variant_p0/test_variant_search_subcolumn.groovy | 2 ++
9 files changed, 79 insertions(+), 12 deletions(-)
diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp
index 86b7d12e0aa..b521fa57ec3 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -1172,7 +1172,11 @@ DEFINE_mBool(variant_enable_duplicate_json_path_check,
"false");
DEFINE_mInt32(variant_storage_parse_mode, "0");
DEFINE_mBool(enable_vertical_compact_variant_subcolumns, "true");
DEFINE_mBool(enable_variant_doc_sparse_write_subcolumns, "true");
-DEFINE_mBool(variant_nested_group_discard_scalar_on_conflict, "false");
+// Maximum depth of nested arrays to track with NestedGroup
+// Reserved for future use when NestedGroup expansion moves to storage layer
+// Deeper arrays will be stored as JSONB
+DEFINE_mInt32(variant_nested_group_max_depth, "10");
+DEFINE_mBool(variant_nested_group_discard_scalar_on_conflict, "true");
DEFINE_Validator(variant_max_json_key_length,
[](const int config) -> bool { return config > 0 && config <=
65535; });
diff --git a/be/src/storage/segment/variant/nested_group_provider.cpp
b/be/src/storage/segment/variant/nested_group_provider.cpp
index b2271bc6943..27a8abf681e 100644
--- a/be/src/storage/segment/variant/nested_group_provider.cpp
+++ b/be/src/storage/segment/variant/nested_group_provider.cpp
@@ -17,6 +17,10 @@
#include "storage/segment/variant/nested_group_provider.h"
+#include <algorithm>
+#include <string>
+#include <utility>
+
namespace doris::segment_v2 {
namespace {
@@ -123,7 +127,7 @@ public:
statistics == nullptr) {
return Status::InvalidArgument("NestedGroup provider input is
null");
}
- return Status::OK();
+ return Status::NotSupported("NestedGroup write path is not available
in this build");
}
Status prepare_with_built_groups(const NestedGroupsMap& /*nested_groups*/,
@@ -135,7 +139,7 @@ public:
statistics == nullptr) {
return Status::InvalidArgument("NestedGroup provider input is
null");
}
- return Status::OK();
+ return Status::NotSupported("NestedGroup write path is not available
in this build");
}
Status init_with_plan(const NestedGroupStreamingWritePlan& /*plan*/,
@@ -144,12 +148,12 @@ public:
if (tablet_column == nullptr || column_id == nullptr || statistics ==
nullptr) {
return Status::InvalidArgument("NestedGroup streaming init input
is null");
}
- return Status::OK();
+ return Status::NotSupported("NestedGroup write path is not available
in this build");
}
Status append_chunk(const NestedGroupStreamingWritePlan& /*plan*/,
const ColumnVariant& /*variant*/) override {
- return Status::OK();
+ return Status::NotSupported("NestedGroup write path is not available
in this build");
}
uint64_t estimate_buffer_size() const override { return 0; }
diff --git a/be/test/storage/segment/nested_group_provider_test.cpp
b/be/test/storage/segment/nested_group_provider_test.cpp
index 7baa6f51fcb..ef55d38cd5d 100644
--- a/be/test/storage/segment/nested_group_provider_test.cpp
+++ b/be/test/storage/segment/nested_group_provider_test.cpp
@@ -29,6 +29,7 @@
#include <roaring/roaring.hh>
#include "core/column/column_variant.h"
+#include "storage/iterator/olap_data_convertor.h"
#include "storage/segment/column_writer.h"
#include "storage/segment/variant/variant_column_reader.h"
#include "storage/segment/variant/variant_statistics.h"
@@ -48,7 +49,7 @@ TEST(NestedGroupProviderTest, DefaultReadProviderIsDisabled) {
EXPECT_FALSE(provider->should_enable_nested_group_read_path());
}
-TEST(NestedGroupProviderTest, DefaultWriteProviderIsNoOp) {
+TEST(NestedGroupProviderTest, DefaultWriteProviderRejectsNestedGroupWritePath)
{
auto write_provider = create_nested_group_write_provider();
ASSERT_TRUE(write_provider != nullptr);
@@ -66,6 +67,23 @@ TEST(NestedGroupProviderTest, DefaultWriteProviderIsNoOp) {
write_provider->prepare(*column_variant, nullptr, opts, nullptr,
nullptr, &statistics);
EXPECT_FALSE(status.ok());
EXPECT_TRUE(status.is<ErrorCode::INVALID_ARGUMENT>());
+
+ TabletColumn tablet_column;
+ OlapBlockDataConvertor converter;
+ int column_id = 0;
+ status = write_provider->prepare(*column_variant, &tablet_column, opts,
&converter, &column_id,
+ &statistics);
+ EXPECT_FALSE(status.ok());
+ EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
+ EXPECT_NE(status.to_string().find("not available"), std::string::npos);
+
+ NestedGroupsMap nested_groups;
+ status = write_provider->prepare_with_built_groups(nested_groups,
&tablet_column, opts,
+ &converter, &column_id,
&statistics);
+ EXPECT_FALSE(status.ok());
+ EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
+ EXPECT_NE(status.to_string().find("not available"), std::string::npos);
+
EXPECT_EQ(0, write_provider->estimate_buffer_size());
EXPECT_TRUE(write_provider->finish().ok());
EXPECT_TRUE(write_provider->write_data().ok());
diff --git a/be/test/storage/segment/variant_column_writer_reader_test.cpp
b/be/test/storage/segment/variant_column_writer_reader_test.cpp
index 737326ffbcd..8b92a1983af 100644
--- a/be/test/storage/segment/variant_column_writer_reader_test.cpp
+++ b/be/test/storage/segment/variant_column_writer_reader_test.cpp
@@ -34,6 +34,7 @@
#include "storage/segment/variant/binary_column_extract_iterator.h"
#include "storage/segment/variant/hierarchical_data_iterator.h"
#include "storage/segment/variant/nested_group_path.h"
+#include "storage/segment/variant/nested_group_provider.h"
#include "storage/segment/variant/nested_group_streaming_write_plan.h"
#include "storage/segment/variant/sparse_column_merge_iterator.h"
#include "storage/segment/variant/variant_column_reader.h"
@@ -85,6 +86,11 @@ static void construct_tablet_index(TabletIndexPB*
tablet_index, int64_t index_id
tablet_index->add_col_unique_id(col_unique_id);
}
+static bool nested_group_write_path_available() {
+ auto provider = segment_v2::create_nested_group_read_provider();
+ return provider != nullptr &&
provider->should_enable_nested_group_read_path();
+}
+
static void fill_nullable_variant_block(Block* block,
std::unordered_map<int, std::string>*
inserted_jsonstr,
variant_util::PathToNoneNullValues*
path_with_size) {
@@ -5236,6 +5242,10 @@ TEST_F(VariantColumnWriterReaderTest,
test_concurrent_load_external_meta_and_get
TEST_F(VariantColumnWriterReaderTest,
test_streaming_write_plan_collects_regular_paths_from_rowset_metadata) {
+ if (!nested_group_write_path_available()) {
+ GTEST_SKIP() << "NestedGroup write path is not available in this
build";
+ }
+
init_variant_tablet(41000, 10, true);
std::vector<RowsetSharedPtr> input_rowsets;
@@ -5267,6 +5277,10 @@ TEST_F(VariantColumnWriterReaderTest,
TEST_F(VariantColumnWriterReaderTest,
test_streaming_compaction_writer_streams_regular_array_paths_across_batches) {
+ if (!nested_group_write_path_available()) {
+ GTEST_SKIP() << "NestedGroup write path is not available in this
build";
+ }
+
init_variant_tablet(41001, 10, true);
std::vector<RowsetSharedPtr> input_rowsets;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index b01b62db5f3..34c69e97eee 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -5329,8 +5329,11 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
}
if (enableNestedGroup) {
- throw new NotSupportedException(
- "variant_enable_nested_group is not supported now");
+ enableVariantDocMode = false;
+ variantMaxSubcolumnsCount = 0;
+ enableTypedPathsToSparse = false;
+ variantMaxSparseColumnStatisticsSize = 0;
+ variantSparseHashShardCount = 0;
}
// When doc mode is enabled, disable subcolumn extraction and sparse
column features
diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
index 44e973e851e..7713519b383 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
@@ -129,11 +129,11 @@ public class TypeTest {
}
@Test
- public void
testVariantToSqlDoesNotSerializeUnsupportedNestedGroupProperty() {
+ public void testVariantToSqlSerializesNestedGroupProperty() {
VariantType variantType = new VariantType(new ArrayList<>(), 0, false,
10000, 0,
false, 0L, 64, true);
-
Assert.assertFalse(variantType.toSql().contains("variant_enable_nested_group"));
+
Assert.assertTrue(variantType.toSql().contains("\"variant_enable_nested_group\"
= \"true\""));
}
// ===================== Mixed Nesting & Precision =====================
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
index a64415480db..c87981ed368 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/NereidsParserTest.java
@@ -1444,14 +1444,31 @@ public class NereidsParserTest extends ParserTestBase {
}
@Test
- public void testCreateTableVariantNestedGroupPropertyIsRejected() {
+ public void testCreateTableVariantNestedGroupPropertyIsAccepted() {
NereidsParser parser = new NereidsParser();
String sql = "CREATE TABLE t_variant_ng (k1 INT, v VARIANT<PROPERTIES("
+ "\"variant_enable_nested_group\" = \"true\")>) "
+ "DISTRIBUTED BY HASH(k1) BUCKETS 1";
+ LogicalPlan logicalPlan = parser.parseSingle(sql);
+ Assertions.assertInstanceOf(CreateTableCommand.class, logicalPlan);
+ CreateTableCommand createTableCommand = (CreateTableCommand)
logicalPlan;
+ org.apache.doris.nereids.types.VariantType variantType =
+ (org.apache.doris.nereids.types.VariantType)
createTableCommand.getCreateTableInfo()
+ .getColumnDefinitions().get(1).getType();
+ Assertions.assertTrue(variantType.getEnableNestedGroup());
+ }
+
+ @Test
+ public void
testCreateTableVariantNestedGroupPropertyConflictsWithDocMode() {
+ NereidsParser parser = new NereidsParser();
+ String sql = "CREATE TABLE t_variant_ng (k1 INT, v VARIANT<PROPERTIES("
+ + "\"variant_enable_nested_group\" = \"true\", "
+ + "\"variant_enable_doc_mode\" = \"true\")>) "
+ + "DISTRIBUTED BY HASH(k1) BUCKETS 1";
NotSupportedException exception =
Assertions.assertThrowsExactly(NotSupportedException.class, ()
-> parser.parseSingle(sql));
-
Assertions.assertTrue(exception.getMessage().contains("variant_enable_nested_group
is not supported now"));
+ Assertions.assertTrue(exception.getMessage()
+ .contains("variant_enable_nested_group and
variant_enable_doc_mode cannot both be true"));
}
@Test
diff --git a/fe/fe-type/src/main/java/org/apache/doris/catalog/VariantType.java
b/fe/fe-type/src/main/java/org/apache/doris/catalog/VariantType.java
index b3b34b2a045..d93ef9894dc 100644
--- a/fe/fe-type/src/main/java/org/apache/doris/catalog/VariantType.java
+++ b/fe/fe-type/src/main/java/org/apache/doris/catalog/VariantType.java
@@ -187,6 +187,11 @@ public class VariantType extends ScalarType {
sb.append("\"variant_sparse_hash_shard_count\" = \"")
.append(String.valueOf(Math.max(1,
variantSparseHashShardCount))).append("\"");
}
+ if (enableNestedGroup) {
+ sb.append(",");
+ sb.append("\"variant_enable_nested_group\" = \"")
+ .append(String.valueOf(enableNestedGroup)).append("\"");
+ }
sb.append(")>");
return sb.toString();
}
diff --git
a/regression-test/suites/variant_p0/test_variant_search_subcolumn.groovy
b/regression-test/suites/variant_p0/test_variant_search_subcolumn.groovy
index 095d3fb84d6..3da6de106e1 100644
--- a/regression-test/suites/variant_p0/test_variant_search_subcolumn.groovy
+++ b/regression-test/suites/variant_p0/test_variant_search_subcolumn.groovy
@@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.
+// DORIS-25891: Variant SEARCH must bind subcolumn predicates to the real
stored
+// field names for direct, nested, and special-character paths.
suite("test_variant_search_subcolumn") {
def table_name = "test_variant_search_subcolumn"
sql "set default_variant_doc_materialization_min_rows = 0"
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]