Repository: squashql/squashql
Pull request #265 (2024-02-12 06:36:57)

Rename BucketColumnSet to GroupColumnSet


Patch:
diff --git a/core/src/main/java/io/squashql/query/ColumnSetKey.java b/core/src/main/java/io/squashql/query/ColumnSetKey.java
index 95b279e..bca02a9 100644
--- a/core/src/main/java/io/squashql/query/ColumnSetKey.java
+++ b/core/src/main/java/io/squashql/query/ColumnSetKey.java
@@ -1,5 +1,5 @@
 package io.squashql.query;
 
 public enum ColumnSetKey {
-  BUCKET,
+  GROUP,
 }
diff --git a/core/src/main/java/io/squashql/query/BucketComparisonExecutor.java b/core/src/main/java/io/squashql/query/GroupComparisonExecutor.java
similarity index 71%
rename from core/src/main/java/io/squashql/query/BucketComparisonExecutor.java
rename to core/src/main/java/io/squashql/query/GroupComparisonExecutor.java
index 6ffecb6..a43f5d0 100644
--- a/core/src/main/java/io/squashql/query/BucketComparisonExecutor.java
+++ b/core/src/main/java/io/squashql/query/GroupComparisonExecutor.java
@@ -1,6 +1,6 @@
 package io.squashql.query;
 
-import io.squashql.query.compiled.CompiledBucketColumnSet;
+import io.squashql.query.compiled.CompiledGroupColumnSet;
 import io.squashql.query.compiled.CompiledComparisonMeasure;
 import io.squashql.query.database.SqlUtils;
 import io.squashql.type.TypedField;
@@ -14,11 +14,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.BiPredicate;
 
-public class BucketComparisonExecutor extends AComparisonExecutor {
+public class GroupComparisonExecutor extends AComparisonExecutor {
 
-  final CompiledBucketColumnSet cSet;
+  final CompiledGroupColumnSet cSet;
 
-  public BucketComparisonExecutor(CompiledBucketColumnSet cSet) {
+  public GroupComparisonExecutor(CompiledGroupColumnSet cSet) {
     this.cSet = cSet;
   }
 
@@ -31,10 +31,10 @@ public class BucketComparisonExecutor extends AComparisonExecutor {
 
     final List<Pair<String, Object>> transformationByColumn;
     final ObjectIntMap<String> indexByColumn;
-    final Map<String, List<String>> valuesByBucket = new LinkedHashMap<>();
+    final Map<String, List<String>> valuesByGroup = new LinkedHashMap<>();
 
-    ShiftProcedure(CompiledBucketColumnSet cSet, Map<TypedField, String> referencePosition, ObjectIntMap<String> indexByColumn) {
-      this.valuesByBucket.putAll(cSet.values());
+    ShiftProcedure(CompiledGroupColumnSet cSet, Map<TypedField, String> referencePosition, ObjectIntMap<String> indexByColumn) {
+      this.valuesByGroup.putAll(cSet.values());
       this.indexByColumn = indexByColumn;
       this.transformationByColumn = new ArrayList<>();
       // Order does matter here
@@ -44,17 +44,17 @@ public class BucketComparisonExecutor extends AComparisonExecutor {
 
     @Override
     public boolean test(Object[] row, Header[] headers) {
-      Object bucketTransformation = this.transformationByColumn.get(0).getTwo();
-      int bucketIndex = this.indexByColumn.getIfAbsent(this.transformationByColumn.get(0).getOne(), -1);
-      if (bucketTransformation != null) {
-        throw new RuntimeException("comparison with a different bucket value is not yet supported");
+      Object groupTransformation = this.transformationByColumn.get(0).getTwo();
+      int groupIndex = this.indexByColumn.getIfAbsent(this.transformationByColumn.get(0).getOne(), -1);
+      if (groupTransformation != null) {
+        throw new RuntimeException("comparison with a different group value is not yet supported");
       }
 
       Object fieldTransformation = this.transformationByColumn.get(1).getTwo();
       if (fieldTransformation != null) {
         int fieldIndex = this.indexByColumn.getIfAbsent(this.transformationByColumn.get(1).getOne(), -1);
-        String b = (String) row[bucketIndex];
-        List<String> values = this.valuesByBucket.get(b);
+        String b = (String) row[groupIndex];
+        List<String> values = this.valuesByGroup.get(b);
         if (fieldTransformation instanceof Integer) {
           String fieldValue = (String) row[fieldIndex];
           int index = values.indexOf(fieldValue);
diff --git a/core/src/main/java/io/squashql/query/BucketerExecutor.java b/core/src/main/java/io/squashql/query/GrouperExecutor.java
similarity index 56%
rename from core/src/main/java/io/squashql/query/BucketerExecutor.java
rename to core/src/main/java/io/squashql/query/GrouperExecutor.java
index a6e7dd0..d8c8601 100644
--- a/core/src/main/java/io/squashql/query/BucketerExecutor.java
+++ b/core/src/main/java/io/squashql/query/GrouperExecutor.java
@@ -1,7 +1,7 @@
 package io.squashql.query;
 
 import io.squashql.query.database.SqlUtils;
-import io.squashql.query.dto.BucketColumnSetDto;
+import io.squashql.query.dto.GroupColumnSetDto;
 import io.squashql.table.ColumnarTable;
 import io.squashql.table.Table;
 import org.eclipse.collections.api.set.primitive.MutableIntSet;
@@ -10,22 +10,22 @@ import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet;
 import java.util.*;
 import java.util.function.Function;
 
-public class BucketerExecutor {
+public class GrouperExecutor {
 
-  public static Table bucket(Table table, BucketColumnSetDto bucketColumnSetDto) {
-    Function<Object[], List<Object[]>> bucketer = createBucketer(bucketColumnSetDto);
+  public static Table group(Table table, GroupColumnSetDto groupColumnSetDto) {
+    Function<Object[], List<Object[]>> grouper = createGrouper(groupColumnSetDto);
 
-    int[] indexColumnsToRead = new int[bucketColumnSetDto.getColumnsForPrefetching().size()];
-    for (int i = 0; i < bucketColumnSetDto.getColumnsForPrefetching().size(); i++) {
-      indexColumnsToRead[i] = table.columnIndex(SqlUtils.squashqlExpression(bucketColumnSetDto.getColumnsForPrefetching().get(i)));
+    int[] indexColumnsToRead = new int[groupColumnSetDto.getColumnsForPrefetching().size()];
+    for (int i = 0; i < groupColumnSetDto.getColumnsForPrefetching().size(); i++) {
+      indexColumnsToRead[i] = table.columnIndex(SqlUtils.squashqlExpression(groupColumnSetDto.getColumnsForPrefetching().get(i)));
     }
 
     MutableIntSet indexColsInPrefetch = new IntHashSet();
-    List<Field> newColumns = bucketColumnSetDto.getNewColumns();
+    List<Field> newColumns = groupColumnSetDto.getNewColumns();
     List<Header> finalHeaders = new ArrayList<>(table.headers());
     for (int i = 0; i < newColumns.size(); i++) {
       Field field = newColumns.get(i);
-      if (!bucketColumnSetDto.getColumnsForPrefetching().contains(field)) {
+      if (!groupColumnSetDto.getColumnsForPrefetching().contains(field)) {
         indexColsInPrefetch.add(i);
       }
       Header header = new Header(SqlUtils.squashqlExpression(field), String.class, false);
@@ -43,15 +43,15 @@ public class BucketerExecutor {
     Object[] buffer = new Object[indexColumnsToRead.length];
     for (List<Object> row : table) {
       transferValues(indexColumnsToRead, buffer, row);
-      List<Object[]> bucketValuesList = bucketer.apply(buffer);
-      for (Object[] bucketValues : bucketValuesList) {
+      List<Object[]> groupValuesList = grouper.apply(buffer);
+      for (Object[] groupValues : groupValuesList) {
         // Pure copy for everything before
         for (int i = 0; i < originalHeadersSize; i++) {
           newColumnValues.get(i).add(row.get(i));
         }
-        for (int i = 0; i < bucketValues.length; i++) {
+        for (int i = 0; i < groupValues.length; i++) {
           if (indexColsInPrefetch.contains(i)) {
-            newColumnValues.get(i + originalHeadersSize).add(bucketValues[i]);
+            newColumnValues.get(i + originalHeadersSize).add(groupValues[i]);
           }
         }
       }
@@ -63,21 +63,21 @@ public class BucketerExecutor {
             newColumnValues);
   }
 
-  private static Function<Object[], List<Object[]>> createBucketer(BucketColumnSetDto bucketColumnSetDto) {
-    Map<String, List<String>> bucketsByValue = new HashMap<>();
-    for (Map.Entry<String, List<String>> value : bucketColumnSetDto.values.entrySet()) {
+  private static Function<Object[], List<Object[]>> createGrouper(GroupColumnSetDto groupColumnSetDto) {
+    Map<String, List<String>> groupsByValue = new HashMap<>();
+    for (Map.Entry<String, List<String>> value : groupColumnSetDto.values.entrySet()) {
       for (String v : value.getValue()) {
-        bucketsByValue
+        groupsByValue
                 .computeIfAbsent(v, k -> new ArrayList<>())
                 .add(value.getKey());
       }
     }
-    Function<Object[], List<Object[]>> bucketer = toBucketColumnValues -> {
-      List<String> buckets = bucketsByValue.get(toBucketColumnValues[0]);
-      return buckets == null ? Collections.emptyList()
-              : buckets.stream().map(b -> new Object[] {b, toBucketColumnValues[0]}).toList();
+    Function<Object[], List<Object[]>> grouper = toGroupColumnValues -> {
+      List<String> groups = groupsByValue.get(toGroupColumnValues[0]);
+      return groups == null ? Collections.emptyList()
+              : groups.stream().map(b -> new Object[] {b, toGroupColumnValues[0]}).toList();
     };
-    return bucketer;
+    return grouper;
   }
 
   public static <T> void transferValues(int[] indices, Object[] buffer, List<T> list) {
diff --git a/core/src/main/java/io/squashql/query/MeasureUtils.java b/core/src/main/java/io/squashql/query/MeasureUtils.java
index 68ab24f..6383c70 100644
--- a/core/src/main/java/io/squashql/query/MeasureUtils.java
+++ b/core/src/main/java/io/squashql/query/MeasureUtils.java
@@ -77,12 +77,12 @@ public final class MeasureUtils {
 
   public static QueryExecutor.QueryScope getReadScopeComparisonMeasureReferencePosition(
           List<TypedField> columns,
-          List<TypedField> bucketColumns,
+          List<TypedField> groupColumns,
           CompiledComparisonMeasure cm,
           QueryExecutor.QueryScope queryScope) {
     AtomicReference<CompiledCriteria> copy = new AtomicReference<>(queryScope.whereCriteria() == null ? null : CompiledCriteria.deepCopy(queryScope.whereCriteria()));
     Consumer<TypedField> criteriaRemover = field -> copy.set(removeCriteriaOnField(field, copy.get()));
-    bucketColumns.forEach(criteriaRemover);
+    groupColumns.forEach(criteriaRemover);
     Optional.ofNullable(cm.period())
             .ifPresent(p -> getColumnsForPrefetching(p).forEach(criteriaRemover));
     Set<TypedField> rollupColumns = new LinkedHashSet<>(queryScope.rollupColumns()); // order does matter
diff --git a/core/src/main/java/io/squashql/query/QueryExecutor.java b/core/src/main/java/io/squashql/query/QueryExecutor.java
index 7603bac..a4e21d8 100644
--- a/core/src/main/java/io/squashql/query/QueryExecutor.java
+++ b/core/src/main/java/io/squashql/query/QueryExecutor.java
@@ -21,7 +21,7 @@ import java.util.*;
 import java.util.function.IntConsumer;
 import java.util.stream.Collectors;
 
-import static io.squashql.query.ColumnSetKey.BUCKET;
+import static io.squashql.query.ColumnSetKey.GROUP;
 import static io.squashql.query.agg.AggregationFunction.GROUPING;
 import static io.squashql.query.compiled.CompiledAggregatedMeasure.COMPILED_COUNT;
 
@@ -157,7 +157,7 @@ public class QueryExecutor {
 
     QueryResolver queryResolver = new QueryResolver(query, this.queryEngine.datastore().storesByName());
     DependencyGraph<QueryPlanNodeKey> dependencyGraph = computeDependencyGraph(
-            queryResolver.getColumns(), queryResolver.getBucketColumns(), queryResolver.getMeasures().values(), queryResolver.getScope());
+            queryResolver.getColumns(), queryResolver.getGroupColumns(), queryResolver.getMeasures().values(), queryResolver.getScope());
     // Compute what needs to be prefetched
     Map<QueryScope, DatabaseQuery> prefetchQueryByQueryScope = new HashMap<>();
     Map<QueryScope, Set<CompiledMeasure>> measuresByQueryScope = new HashMap<>();
@@ -211,11 +211,11 @@ public class QueryExecutor {
       tableByScope.put(scope, result);
     }
 
-    if (query.columnSets.containsKey(BUCKET)) {
+    if (query.columnSets.containsKey(GROUP)) {
       // Apply this as it modifies the "shape" of the result
-      BucketColumnSetDto columnSet = (BucketColumnSetDto) query.columnSets.get(BUCKET);
+      GroupColumnSetDto columnSet = (GroupColumnSetDto) query.columnSets.get(GROUP);
       // Reshape all results
-      tableByScope.replaceAll((scope, table) -> BucketerExecutor.bucket(table, columnSet));
+      tableByScope.replaceAll((scope, table) -> GrouperExecutor.group(table, columnSet));
     }
 
     // Here we take the global plan and execute the plans for a given scope one by one, in dependency order. The order
@@ -227,7 +227,7 @@ public class QueryExecutor {
         final ExecutionContext executionContext = new ExecutionContext(queryNode.queryScope,
                 tableByScope,
                 queryResolver.getColumns(),
-                queryResolver.getBucketColumns(),
+                queryResolver.getGroupColumns(),
                 queryResolver.getCompiledColumnSets(),
                 queryLimit);
         evaluator.accept(queryNode, executionContext);
@@ -266,11 +266,11 @@ public class QueryExecutor {
 
   private static DependencyGraph<QueryPlanNodeKey> computeDependencyGraph(
           List<TypedField> columns,
-          List<TypedField> bucketColumns,
+          List<TypedField> groupColumns,
           Collection<CompiledMeasure> measures,
           QueryScope queryScope) {
     GraphDependencyBuilder<QueryPlanNodeKey> builder = new GraphDependencyBuilder<>(nodeKey -> {
-      Map<QueryScope, Set<CompiledMeasure>> dependencies = nodeKey.measure.accept(new PrefetchVisitor(columns, bucketColumns, nodeKey.queryScope));
+      Map<QueryScope, Set<CompiledMeasure>> dependencies = nodeKey.measure.accept(new PrefetchVisitor(columns, groupColumns, nodeKey.queryScope));
       Set<QueryPlanNodeKey> set = new HashSet<>();
       for (Map.Entry<QueryScope, Set<CompiledMeasure>> entry : dependencies.entrySet()) {
         QueryScope key = entry.getKey();
@@ -336,7 +336,7 @@ public class QueryExecutor {
   public record ExecutionContext(QueryScope queryScope,
                                  Map<QueryScope, Table> tableByScope,
                                  List<TypedField> columns,
-                                 List<TypedField> bucketColumns,
+                                 List<TypedField> groupColumns,
                                  Map<ColumnSetKey, CompiledColumnSet> columnSets,
                                  int queryLimit) {
     public Table getWriteToTable() {
@@ -363,9 +363,9 @@ public class QueryExecutor {
     public static List<Field> cleanse(QueryDto query, List<Field> fields) {
       // ColumnSet is a special type of column that does not exist in the database but only in SquashQL. Totals can't be
       // computed. This is why it is removed from the axes.
-      ColumnSet columnSet = query.columnSets.get(BUCKET);
+      ColumnSet columnSet = query.columnSets.get(GROUP);
       if (columnSet != null) {
-        Field newField = ((BucketColumnSetDto) columnSet).newField;
+        Field newField = ((GroupColumnSetDto) columnSet).newField;
         if (fields.contains(newField)) {
           fields = new ArrayList<>(fields);
           fields.remove(newField);
diff --git a/core/src/main/java/io/squashql/query/QueryResolver.java b/core/src/main/java/io/squashql/query/QueryResolver.java
index 5c6535d..253aee0 100644
--- a/core/src/main/java/io/squashql/query/QueryResolver.java
+++ b/core/src/main/java/io/squashql/query/QueryResolver.java
@@ -15,7 +15,7 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static io.squashql.query.ColumnSetKey.BUCKET;
+import static io.squashql.query.ColumnSetKey.GROUP;
 import static io.squashql.query.compiled.CompiledAggregatedMeasure.COMPILED_COUNT;
 
 @Data
@@ -25,7 +25,7 @@ public class QueryResolver {
   private final Map<String, Store> storesByName;
   private final Set<String> cteTableNames = new HashSet<>();
   private final QueryExecutor.QueryScope scope;
-  private final List<TypedField> bucketColumns;
+  private final List<TypedField> groupColumns;
   private final List<TypedField> columns;
   private final CompilationCache cache = new CompilationCache();
   private final Map<Measure, CompiledMeasure> subQueryMeasures;
@@ -42,7 +42,7 @@ public class QueryResolver {
       }
     }
     this.columns = query.columns.stream().map(this::resolveField).toList();
-    this.bucketColumns = Optional.ofNullable(query.columnSets.get(ColumnSetKey.BUCKET))
+    this.groupColumns = Optional.ofNullable(query.columnSets.get(ColumnSetKey.GROUP))
             .stream().flatMap(cs -> cs.getColumnsForPrefetching().stream()).map(this::resolveField).toList();
     this.subQueryMeasures = query.subQuery == null ? Collections.emptyMap() : compileMeasures(query.subQuery.measures, false);
     this.scope = toQueryScope(query);
@@ -76,9 +76,9 @@ public class QueryResolver {
   public TypedField resolveField(final Field field) {
     return this.cache.computeIfAbsent(field, f -> {
       // Special case for the column that is created due to the column set.
-      ColumnSet columnSet = this.query.columnSets.get(BUCKET);
+      ColumnSet columnSet = this.query.columnSets.get(GROUP);
       if (columnSet != null) {
-        Field newField = ((BucketColumnSetDto) columnSet).newField;
+        Field newField = ((GroupColumnSetDto) columnSet).newField;
         if (field.equals(newField)) {
           return new TableTypedField(null, newField.name(), String.class, null, false);
         }
@@ -383,15 +383,15 @@ public class QueryResolver {
   private Map<ColumnSetKey, CompiledColumnSet> compiledColumnSets(Map<ColumnSetKey, ColumnSet> columnSets) {
     Map<ColumnSetKey, CompiledColumnSet> m = new HashMap<>();
     for (Map.Entry<ColumnSetKey, ColumnSet> entry : columnSets.entrySet()) {
-      if (entry.getKey() != BUCKET) {
+      if (entry.getKey() != GROUP) {
         throw new IllegalArgumentException("unexpected column set " + entry.getValue());
       }
-      BucketColumnSetDto bucket = (BucketColumnSetDto) entry.getValue();
-      m.put(entry.getKey(), new CompiledBucketColumnSet(
-              bucket.getColumnsForPrefetching().stream().map(this::resolveField).toList(),
-              bucket.getNewColumns().stream().map(this::resolveField).toList(),
+      GroupColumnSetDto group = (GroupColumnSetDto) entry.getValue();
+      m.put(entry.getKey(), new CompiledGroupColumnSet(
+              group.getColumnsForPrefetching().stream().map(this::resolveField).toList(),
+              group.getNewColumns().stream().map(this::resolveField).toList(),
               entry.getKey(),
-              bucket.values));
+              group.values));
     }
     return m;
   }
diff --git a/core/src/main/java/io/squashql/query/compiled/CompiledBucketColumnSet.java b/core/src/main/java/io/squashql/query/compiled/CompiledGroupColumnSet.java
similarity index 50%
rename from core/src/main/java/io/squashql/query/compiled/CompiledBucketColumnSet.java
rename to core/src/main/java/io/squashql/query/compiled/CompiledGroupColumnSet.java
index e56808b..37daca8 100644
--- a/core/src/main/java/io/squashql/query/compiled/CompiledBucketColumnSet.java
+++ b/core/src/main/java/io/squashql/query/compiled/CompiledGroupColumnSet.java
@@ -6,10 +6,10 @@ import io.squashql.type.TypedField;
 import java.util.List;
 import java.util.Map;
 
-public record CompiledBucketColumnSet(List<TypedField> columnsForPrefetching,
-                                      List<TypedField> newColumns,
-                                      ColumnSetKey columnSetKey,
-                                      Map<String, List<String>> values) implements CompiledColumnSet {
+public record CompiledGroupColumnSet(List<TypedField> columnsForPrefetching,
+                                     List<TypedField> newColumns,
+                                     ColumnSetKey columnSetKey,
+                                     Map<String, List<String>> values) implements CompiledColumnSet {
 
   public TypedField newField() {
     return this.newColumns.get(0);
diff --git a/core/src/main/java/io/squashql/query/compiled/Evaluator.java b/core/src/main/java/io/squashql/query/compiled/Evaluator.java
index a072ea9..3261066 100644
--- a/core/src/main/java/io/squashql/query/compiled/Evaluator.java
+++ b/core/src/main/java/io/squashql/query/compiled/Evaluator.java
@@ -15,7 +15,7 @@ import java.util.List;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 
-import static io.squashql.query.ColumnSetKey.BUCKET;
+import static io.squashql.query.ColumnSetKey.GROUP;
 
 public class Evaluator implements BiConsumer<QueryPlanNodeKey, ExecutionContext>, MeasureVisitor<Void> {
 
@@ -52,12 +52,12 @@ public class Evaluator implements BiConsumer<QueryPlanNodeKey, ExecutionContext>
   @Override
   public Void visit(CompiledComparisonMeasure cm) {
     AComparisonExecutor executor;
-    if (cm.columnSetKey() == BUCKET) {
-      CompiledColumnSet cs = this.executionContext.columnSets().get(BUCKET);
+    if (cm.columnSetKey() == GROUP) {
+      CompiledColumnSet cs = this.executionContext.columnSets().get(GROUP);
       if (cs == null) {
-        throw new IllegalArgumentException(String.format("columnSet %s is not specified in the query but is used in a comparison measure: %s", BUCKET, cm));
+        throw new IllegalArgumentException(String.format("columnSet %s is not specified in the query but is used in a comparison measure: %s", GROUP, cm));
       }
-      executor = new BucketComparisonExecutor((CompiledBucketColumnSet) cs);
+      executor = new GroupComparisonExecutor((CompiledGroupColumnSet) cs);
     } else if (cm.period() != null) {
       for (TypedField field : cm.period().getTypedFields()) {
         if (!this.executionContext.columns().contains(field)) {
@@ -72,7 +72,7 @@ public class Evaluator implements BiConsumer<QueryPlanNodeKey, ExecutionContext>
     }
 
     QueryExecutor.QueryScope readScope = MeasureUtils.getReadScopeComparisonMeasureReferencePosition(
-            this.executionContext.columns(), this.executionContext.bucketColumns(), cm, this.executionContext.queryScope());
+            this.executionContext.columns(), this.executionContext.groupColumns(), cm, this.executionContext.queryScope());
     Table readFromTable = this.executionContext.tableByScope().get(readScope); // Table where to read the aggregates
     if (readFromTable.count() == this.executionContext.queryLimit()) {
       throw new RuntimeException("Too many rows, some intermediate results exceed the limit " + this.executionContext.queryLimit());
@@ -132,7 +132,7 @@ public class Evaluator implements BiConsumer<QueryPlanNodeKey, ExecutionContext>
   @Override
   public Void visit(CompiledVectorAggMeasure measure) {
     // Retrieve the query scope use for the prefetch, the logic should be the same to retrieve the result.
-    QueryExecutor.QueryScope prefetchQueryScope = new PrefetchVisitor(this.executionContext.columns(), this.executionContext.bucketColumns(), this.executionContext.queryScope())
+    QueryExecutor.QueryScope prefetchQueryScope = new PrefetchVisitor(this.executionContext.columns(), this.executionContext.groupColumns(), this.executionContext.queryScope())
             .visit(measure)
             .keySet()
             .iterator()
@@ -146,7 +146,7 @@ public class Evaluator implements BiConsumer<QueryPlanNodeKey, ExecutionContext>
   @Override
   public Void visit(CompiledVectorTupleAggMeasure measure) {
     // Retrieve the query scope use for the prefetch, the logic should be the same to retrieve the result.
-    QueryExecutor.QueryScope prefetchQueryScope = new PrefetchVisitor(this.executionContext.columns(), this.executionContext.bucketColumns(), this.executionContext.queryScope())
+    QueryExecutor.QueryScope prefetchQueryScope = new PrefetchVisitor(this.executionContext.columns(), this.executionContext.groupColumns(), this.executionContext.queryScope())
             .visit(measure)
             .keySet()
             .iterator()
diff --git a/core/src/main/java/io/squashql/query/compiled/PrefetchVisitor.java b/core/src/main/java/io/squashql/query/compiled/PrefetchVisitor.java
index 4ff7401..b1ba3df 100644
--- a/core/src/main/java/io/squashql/query/compiled/PrefetchVisitor.java
+++ b/core/src/main/java/io/squashql/query/compiled/PrefetchVisitor.java
@@ -18,7 +18,7 @@ import static io.squashql.query.agg.AggregationFunction.*;
 public class PrefetchVisitor implements MeasureVisitor<Map<QueryScope, Set<CompiledMeasure>>> {
 
   private final List<TypedField> columns;
-  private final List<TypedField> bucketColumns;
+  private final List<TypedField> groupColumns;
   private final QueryScope originalQueryScope;
 
   private Map<QueryScope, Set<CompiledMeasure>> empty() {
@@ -46,7 +46,7 @@ public class PrefetchVisitor implements MeasureVisitor<Map<QueryScope, Set<Compi
 
   @Override
   public Map<QueryScope, Set<CompiledMeasure>> visit(CompiledComparisonMeasure cmrp) {
-    QueryScope readScope = MeasureUtils.getReadScopeComparisonMeasureReferencePosition(this.columns, this.bucketColumns, cmrp, this.originalQueryScope);
+    QueryScope readScope = MeasureUtils.getReadScopeComparisonMeasureReferencePosition(this.columns, this.groupColumns, cmrp, this.originalQueryScope);
     Map<QueryScope, Set<CompiledMeasure>> result = new HashMap<>(Map.of(this.originalQueryScope, Set.of(cmrp.measure())));
     result.put(readScope, Set.of(cmrp.measure()));
     return result;
diff --git a/core/src/main/java/io/squashql/query/dto/BucketColumnSetDto.java b/core/src/main/java/io/squashql/query/dto/GroupColumnSetDto.java
similarity index 75%
rename from core/src/main/java/io/squashql/query/dto/BucketColumnSetDto.java
rename to core/src/main/java/io/squashql/query/dto/GroupColumnSetDto.java
index 8780da7..0690f91 100644
--- a/core/src/main/java/io/squashql/query/dto/BucketColumnSetDto.java
+++ b/core/src/main/java/io/squashql/query/dto/GroupColumnSetDto.java
@@ -16,7 +16,7 @@ import java.util.Map;
 @ToString
 @EqualsAndHashCode
 @NoArgsConstructor // For Jackson
-public class BucketColumnSetDto implements ColumnSet {
+public class GroupColumnSetDto implements ColumnSet {
 
   public Field newField;
 
@@ -24,13 +24,13 @@ public class BucketColumnSetDto implements ColumnSet {
 
   public Map<String, List<String>> values = new LinkedHashMap<>();
 
-  public BucketColumnSetDto(String name, Field field) {
+  public GroupColumnSetDto(String name, Field field) {
     this.newField = new TableField(name);
     this.field = field;
   }
 
-  public BucketColumnSetDto withNewBucket(String bucketName, List<String> bucketValues) {
-    this.values.put(bucketName, new ArrayList<>(bucketValues));
+  public GroupColumnSetDto withNewGroup(String groupName, List<String> groupValues) {
+    this.values.put(groupName, new ArrayList<>(groupValues));
     return this;
   }
 
@@ -46,6 +46,6 @@ public class BucketColumnSetDto implements ColumnSet {
 
   @Override
   public ColumnSetKey getColumnSetKey() {
-    return ColumnSetKey.BUCKET;
+    return ColumnSetKey.GROUP;
   }
 }
diff --git a/core/src/main/java/io/squashql/table/TableUtils.java b/core/src/main/java/io/squashql/table/TableUtils.java
index 0e41257..e318cdf 100644
--- a/core/src/main/java/io/squashql/table/TableUtils.java
+++ b/core/src/main/java/io/squashql/table/TableUtils.java
@@ -6,7 +6,7 @@ import io.squashql.query.compiled.CompiledMeasure;
 import io.squashql.query.database.QueryEngine;
 import io.squashql.query.database.SQLTranslator;
 import io.squashql.query.database.SqlUtils;
-import io.squashql.query.dto.BucketColumnSetDto;
+import io.squashql.query.dto.GroupColumnSetDto;
 import io.squashql.query.dto.MetadataItem;
 import io.squashql.query.dto.QueryDto;
 import io.squashql.type.TypedField;
@@ -191,10 +191,10 @@ public class TableUtils {
     Map<String, Comparator<?>> copy = new HashMap<>(comparatorByColumnName);
 
     columnSets.forEach(columnSet -> {
-      if (columnSet.getColumnSetKey() != ColumnSetKey.BUCKET) {
+      if (columnSet.getColumnSetKey() != ColumnSetKey.GROUP) {
         throw new IllegalArgumentException("Unexpected column set type " + columnSet);
       }
-      BucketColumnSetDto cs = (BucketColumnSetDto) columnSet;
+      GroupColumnSetDto cs = (GroupColumnSetDto) columnSet;
       // Remove from the map of comparators to use default one when only none is defined for regular column
       copy.remove(cs.newField.name());
       copy.remove(cs.field.name());
@@ -221,7 +221,7 @@ public class TableUtils {
     int[] contextIndices = new int[args.size()];
     Arrays.fill(contextIndices, -1);
     for (ColumnSet columnSet : new HashSet<>(columnSets)) {
-      BucketColumnSetDto cs = (BucketColumnSetDto) columnSet;
+      GroupColumnSetDto cs = (GroupColumnSetDto) columnSet;
       // cs.field can appear multiple times in the table.
       table.columnIndices(cs.field).forEach(i -> contextIndices[i] = table.columnIndex(cs.newField.name()));
     }
diff --git a/core/src/main/java/io/squashql/util/Queries.java b/core/src/main/java/io/squashql/util/Queries.java
index 4a4bc57..cdacee1 100644
--- a/core/src/main/java/io/squashql/util/Queries.java
+++ b/core/src/main/java/io/squashql/util/Queries.java
@@ -28,10 +28,10 @@ public final class Queries {
       }
     });
 
-    // Special case for Bucket that defines implicitly an order.
-    ColumnSet bucket = queryDto.columnSets.get(ColumnSetKey.BUCKET);
-    if (bucket != null) {
-      BucketColumnSetDto cs = (BucketColumnSetDto) bucket;
+    // Special case for group that defines implicitly an order.
+    ColumnSet group = queryDto.columnSets.get(ColumnSetKey.GROUP);
+    if (group != null) {
+      GroupColumnSetDto cs = (GroupColumnSetDto) group;
       Map<Object, List<Object>> m = new LinkedHashMap<>();
       cs.values.forEach((k, v) -> {
         List<Object> l = new ArrayList<>(v);
diff --git a/documentation/QUERY.md b/documentation/QUERY.md
index eb6aec2..4ade79b 100644
--- a/documentation/QUERY.md
+++ b/documentation/QUERY.md
@@ -350,7 +350,7 @@ FROM myTable
        LEFT OUTER JOIN otherTable ON myTable.id = otherTable.key1 AND refTable.id = otherTable.key2
 ```
 
-### Joining on virtual created on-the-fly at query time
+### Joining on virtual table created on-the-fly at query time
 
 You can define and use a virtual table in the query by joining it to an existing table. Such table is not materialized
 in the database and only exists during the query execution time. Note the join operation is performed by the underlying
@@ -947,7 +947,7 @@ Result
 +-------------+-------------+-------------+------------+---------------------+
 ```
 
-##### Dynamic comparison - What-if - ColumnSet
+##### Group comparison - ColumnSet
 
 This type of comparison is mainly used for what-if comparison but not limited to it. It involves the creation of a new
 "virtual" column called `ColumnSet` that only exists in SquashQL to create groups among which the comparisons are
@@ -998,7 +998,7 @@ To do that, we start by creating those groups that we put in a dedicated object
 
 ```typescript
 import {
-  BucketColumnSet
+  GroupColumnSet
 } from "@squashql/squashql-js"
 
 const groups = new Map(Object.entries({
@@ -1007,17 +1007,17 @@ const groups = new Map(Object.entries({
   "group3": ["base", "s3"],
   "group4": ["s1", "s2", "s3"],
 }))
-const columnSet = new BucketColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
+const columnSet = new GroupColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
 ```
 
-The first argument of `BucketColumnSet` is the name of the new (virtual) column that will be created.
+The first argument of `GroupColumnSet` is the name of the new (virtual) column that will be created.
 The second argument is the name of the existing column whose values will be grouped together.
 The third argument is the defined groups to be used for the comparison. The orders of the keys (group1, group2....)
 and in the arrays are important.
 
-We can use the `BucketColumnSet` as follows
+We can use the `GroupColumnSet` as follows
 ```typescript
-import {BucketColumnSet, ExpressionMeasure, from} from "@squashql/squashql-js"
+import {GroupColumnSet, ExpressionMeasure, from} from "@squashql/squashql-js"
 
 const values = new Map(Object.entries({
   "group1": ["base", "s1"],
@@ -1028,7 +1028,7 @@ const values = new Map(Object.entries({
 const saleprice = new TableField("myTable.saleprice")
 const loavessold = new TableField("myTable.loavessold")
 const revenue = sum("revenue", saleprice.multiply(loavessold))
-const columnSet = new BucketColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
+const columnSet = new GroupColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
 const query = from("myTable")
         .select([], [columnSet], [revenue])
         .build()
@@ -1053,9 +1053,9 @@ Result
 As you can see, adding the column set to the query will add two columns in the result: group and scenario so that we 
 can remove scenario column from the first argument.
 
-Now to perform the comparison, use the built-in measure `comparisonMeasureWithBucket`
+Now to perform the comparison, use the built-in measure `comparisonMeasureWithinSameGroup`
 ```typescript
-import {BucketColumnSet, comparisonMeasureWithBucket, ComparisonMethod, ExpressionMeasure, from} from "@squashql/squashql-js"
+import {GroupColumnSet, comparisonMeasureWithinSameGroup, ComparisonMethod, ExpressionMeasure, from} from "@squashql/squashql-js"
 
 const values = new Map(Object.entries({
   "group1": ["base", "s1"],
@@ -1066,8 +1066,8 @@ const values = new Map(Object.entries({
 const saleprice = new TableField("myTable.saleprice")
 const loavessold = new TableField("myTable.loavessold")
 const revenue = sum("revenue", saleprice.multiply(loavessold))
-const columnSet = new BucketColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
-const revenueComparison = comparisonMeasureWithBucket("revenueComparison",
+const columnSet = new GroupColumnSet(new TableField("group"), new TableField("myTable.scenario"), groups)
+const revenueComparison = comparisonMeasureWithinSameGroup("revenueComparison",
         ComparisonMethod.ABSOLUTE_DIFFERENCE,
         revenue,
         new Map([[new TableField("myTable.scenario"), "s-1"]]))
diff --git a/js/typescript-library/src/columnsets.ts b/js/typescript-library/src/columnsets.ts
index 4fb3fb8..43dcf00 100644
--- a/js/typescript-library/src/columnsets.ts
+++ b/js/typescript-library/src/columnsets.ts
@@ -7,12 +7,12 @@ export interface ColumnSet {
 }
 
 export enum ColumnSetKey {
-  BUCKET = "BUCKET",
+  GROUP = "GROUP",
 }
 
-export class BucketColumnSet implements ColumnSet {
-  readonly class: string = PACKAGE + "dto.BucketColumnSetDto"
-  readonly key: ColumnSetKey = ColumnSetKey.BUCKET
+export class GroupColumnSet implements ColumnSet {
+  readonly class: string = PACKAGE + "dto.GroupColumnSetDto"
+  readonly key: ColumnSetKey = ColumnSetKey.GROUP
 
   constructor(private newField: Field, private field: Field, private values: Map<string, Array<string>>) {
   }
diff --git a/js/typescript-library/src/dependencies.ts b/js/typescript-library/src/dependencies.ts
index 2f16b74..55229c2 100644
--- a/js/typescript-library/src/dependencies.ts
+++ b/js/typescript-library/src/dependencies.ts
@@ -9,7 +9,7 @@ import {
 import {Condition, ConstantCondition, InCondition, LogicalCondition, SingleValueCondition} from "./conditions"
 import Criteria from "./criteria"
 import {BinaryOperationField, ConstantField, Field, TableField} from "./field"
-import {BucketColumnSet, ColumnSet, Month, Period, Quarter, Semester, Year} from "./columnsets"
+import {GroupColumnSet, ColumnSet, Month, Period, Quarter, Semester, Year} from "./columnsets"
 
 export const computeFieldDependencies = (field: Field, resultArray: TableField[] = []): TableField[] => {
   switch (field.constructor) {
@@ -33,8 +33,8 @@ export const computeFieldDependencies = (field: Field, resultArray: TableField[]
 
 export const computeColumnSetDependencies = (columnSet: ColumnSet, resultArray: TableField[] = []): TableField[] => {
   switch (columnSet.constructor) {
-    case BucketColumnSet:
-      computeFieldDependencies((columnSet as BucketColumnSet)["field"], resultArray)
+    case GroupColumnSet:
+      computeFieldDependencies((columnSet as GroupColumnSet)["field"], resultArray)
       break
     default:
       throw new Error("ColumnSet with unknown type: " + columnSet.constructor)
diff --git a/js/typescript-library/src/generate-json-query.ts b/js/typescript-library/src/generate-json-query.ts
index 8dd5455..f9b66d6 100644
--- a/js/typescript-library/src/generate-json-query.ts
+++ b/js/typescript-library/src/generate-json-query.ts
@@ -1,5 +1,5 @@
 import * as fs from "fs"
-import {BucketColumnSet} from "./columnsets"
+import {GroupColumnSet} from "./columnsets"
 import {all, ConditionType, criterion, criterion_, eq, gt, havingCriterion, lt} from "./conditions"
 import {TableField, tableField, tableFields} from "./field"
 import {avg, ExpressionMeasure, sum} from "./measure"
@@ -16,7 +16,7 @@ export function generateFromQuery() {
   }))
   const cte1 = new VirtualTable("myCte1", ["id", "min", "max", "other"], [[0, 0, 1, "x"], [1, 2, 3, "y"]])
   const cte2 = new VirtualTable("myCte2", ["id", "min", "max", "other"], [[0, 4, 12, "a"], [1, 12, 25, "b"]])
-  const bucketColumnSet = new BucketColumnSet(tableField("group"), tableField("scenario"), values)
+  const groupColumnSet = new GroupColumnSet(tableField("group"), tableField("scenario"), values)
   const measure = sum("sum", new TableField("f1"))
   const measureExpr = new ExpressionMeasure("sum_expr", "sum(f1)")
   const fields = tableFields(["a", "b"])
@@ -41,7 +41,7 @@ export function generateFromQuery() {
             criterion(new TableField("f3"), eq(123))
           ]))
           .select(fields,
-                  [bucketColumnSet],
+                  [groupColumnSet],
                   [measure, avg("sum", new TableField("f1")), measureExpr])
           .rollup(fields)
           .having(all([
diff --git a/js/typescript-library/src/generate-json-queryDto.ts b/js/typescript-library/src/generate-json-queryDto.ts
index 65da678..5b1b8d9 100644
--- a/js/typescript-library/src/generate-json-queryDto.ts
+++ b/js/typescript-library/src/generate-json-queryDto.ts
@@ -3,7 +3,7 @@ import {
   AggregatedMeasure,
   avgIf,
   BinaryOperationMeasure, BinaryOperator,
-  comparisonMeasureWithBucket,
+  comparisonMeasureWithinSameGroup,
   comparisonMeasureWithParent,
   comparisonMeasureWithPeriod,
   ComparisonMethod,
@@ -31,7 +31,7 @@ import {
 } from "./conditions"
 import * as fs from "fs"
 import {OrderKeyword} from "./order"
-import {BucketColumnSet, Month} from "./columnsets"
+import {GroupColumnSet, Month} from "./columnsets"
 import {AliasedField, ConstantField, countRows, TableField, tableField} from "./field"
 
 export function generateFromQueryDto() {
@@ -65,7 +65,7 @@ export function generateFromQueryDto() {
   const one = new ConstantField(1)
   q.withMeasure(avgIf("whatever", f1.divide(one.plus(rate)), criterion_(f1.plus(f2).as("f1+f2"), one, ConditionType.GT)))
 
-  q.withMeasure(comparisonMeasureWithBucket("comp bucket", ComparisonMethod.ABSOLUTE_DIFFERENCE, price, new Map([
+  q.withMeasure(comparisonMeasureWithinSameGroup("comp group", ComparisonMethod.ABSOLUTE_DIFFERENCE, price, new Map([
     [tableField("group"), "g"],
     [tableField("scenario"), "s-1"]
   ])))
@@ -96,7 +96,7 @@ export function generateFromQueryDto() {
     "a": ["a1", "a2"],
     "b": ["b1", "b2"]
   }))
-  q.withBucketColumnSet(new BucketColumnSet(tableField("group"), tableField("scenario"), values))
+  q.withGroupColumnSet(new GroupColumnSet(tableField("group"), tableField("scenario"), values))
 
   // SubQuery - Note this is not valid because a table has been set above, but we are just testing
   // the json here.
diff --git a/js/typescript-library/src/index.ts b/js/typescript-library/src/index.ts
index 6429392..b6cffda 100644
--- a/js/typescript-library/src/index.ts
+++ b/js/typescript-library/src/index.ts
@@ -15,7 +15,7 @@ export {
   sumIf, minIf, maxIf, avgIf, countIf, countDistinctIf,
   plus, minus, multiply, divide,
   integer, decimal,
-  comparisonMeasureWithPeriod, comparisonMeasureWithBucket, comparisonMeasureWithParent,
+  comparisonMeasureWithPeriod, comparisonMeasureWithinSameGroup, comparisonMeasureWithParent,
   totalCount,
   ComparisonMethod,
 } from './measure'
@@ -28,7 +28,7 @@ export {
 } from './conditions'
 
 export {
-  ColumnSet, BucketColumnSet,
+  ColumnSet, GroupColumnSet,
   Period, Month, Year, Quarter, Semester,
 } from './columnsets'
 
diff --git a/js/typescript-library/src/measure.ts b/js/typescript-library/src/measure.ts
index 2c6e47c..a47b964 100644
--- a/js/typescript-library/src/measure.ts
+++ b/js/typescript-library/src/measure.ts
@@ -251,11 +251,11 @@ export function comparisonMeasureWithPeriod(alias: string,
   return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition, undefined, period)
 }
 
-export function comparisonMeasureWithBucket(alias: string,
-                                            comparisonMethod: ComparisonMethod,
-                                            measure: Measure,
-                                            referencePosition: Map<Field, string>): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition, ColumnSetKey.BUCKET)
+export function comparisonMeasureWithinSameGroup(alias: string,
+                                                 comparisonMethod: ComparisonMethod,
+                                                 measure: Measure,
+                                                 referencePosition: Map<Field, string>): Measure {
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition, ColumnSetKey.GROUP)
 }
 
 export function comparisonMeasureWithParent(alias: string,
diff --git a/js/typescript-library/src/query.ts b/js/typescript-library/src/query.ts
index 926191d..96f1aa9 100644
--- a/js/typescript-library/src/query.ts
+++ b/js/typescript-library/src/query.ts
@@ -1,4 +1,4 @@
-import {BucketColumnSet, ColumnSet, ColumnSetKey} from "./columnsets"
+import {GroupColumnSet, ColumnSet, ColumnSetKey} from "./columnsets"
 import {Field} from "./field"
 import {Measure} from "./measure"
 import {ExplicitOrderDto, Order, OrderKeyword, SimpleOrder} from "./order"
@@ -93,8 +93,8 @@ export class Query {
     return this
   }
 
-  withBucketColumnSet(columSet: BucketColumnSet): Query {
-    this.columnSets.set(ColumnSetKey.BUCKET, columSet)
+  withGroupColumnSet(columSet: GroupColumnSet): Query {
+    this.columnSets.set(ColumnSetKey.GROUP, columSet)
     return this
   }
 


Test patch:
diff --git a/bigquery/src/test/java/io/squashql/query/TestBigQueryBucketComparison.java b/bigquery/src/test/java/io/squashql/query/TestBigQueryGroupComparison.java
similarity index 95%
rename from bigquery/src/test/java/io/squashql/query/TestBigQueryBucketComparison.java
rename to bigquery/src/test/java/io/squashql/query/TestBigQueryGroupComparison.java
index 1e78f11..f986389 100644
--- a/bigquery/src/test/java/io/squashql/query/TestBigQueryBucketComparison.java
+++ b/bigquery/src/test/java/io/squashql/query/TestBigQueryGroupComparison.java
@@ -15,7 +15,7 @@ import static io.squashql.query.BigQueryTestUtil.PROJECT_ID;
 /**
  * Do not edit this class, it has been generated automatically by {@link io.squashql.template.BigQueryClassTemplateGenerator}.
  */
-public class TestBigQueryBucketComparison extends ATestBucketComparison {
+public class TestBigQueryGroupComparison extends ATestGroupComparison {
 
   @AfterAll
   void tearDown() {
diff --git a/clickhouse/src/test/java/io/squashql/query/TestClickHouseBucketComparison.java b/clickhouse/src/test/java/io/squashql/query/TestClickHouseGroupComparison.java
similarity index 95%
rename from clickhouse/src/test/java/io/squashql/query/TestClickHouseBucketComparison.java
rename to clickhouse/src/test/java/io/squashql/query/TestClickHouseGroupComparison.java
index 0fff778..e8096c4 100644
--- a/clickhouse/src/test/java/io/squashql/query/TestClickHouseBucketComparison.java
+++ b/clickhouse/src/test/java/io/squashql/query/TestClickHouseGroupComparison.java
@@ -13,7 +13,7 @@ import org.junit.jupiter.api.BeforeAll;
 /**
  * Do not edit this class, it has been generated automatically by {@link ClickHouseClassTemplateGenerator}.
  */
-public class TestClickHouseBucketComparison extends ATestBucketComparison {
+public class TestClickHouseGroupComparison extends ATestGroupComparison {
 
   public org.testcontainers.containers.GenericContainer container = ClickHouseTestUtil.createClickHouseContainer();
 
diff --git a/core/src/test/java/io/squashql/jackson/TestQueryS13n.java b/core/src/test/java/io/squashql/jackson/TestQueryS13n.java
index 1b02a85..ec91b3e 100644
--- a/core/src/test/java/io/squashql/jackson/TestQueryS13n.java
+++ b/core/src/test/java/io/squashql/jackson/TestQueryS13n.java
@@ -76,12 +76,12 @@ public class TestQueryS13n {
   }
 
   @Test
-  void testRoundTripBucketComparisonQuery() {
+  void testRoundTripGroupComparisonQuery() {
     String groupOfScenario = "Group of scenario";
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto(groupOfScenario, tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
-            .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
-            .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto(groupOfScenario, tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
+            .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
+            .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
 
     AggregatedMeasure price = new AggregatedMeasure("p", "price", "sum");
     ComparisonMeasureReferencePosition priceComp = new ComparisonMeasureReferencePosition(
@@ -92,11 +92,11 @@ public class TestQueryS13n {
                     tableField(SCENARIO_FIELD_NAME), "first",
                     tableField(groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     var query = new QueryDto()
             .table("products")
-            .withColumnSet(ColumnSetKey.BUCKET, bucketCS)
+            .withColumnSet(ColumnSetKey.GROUP, groupCS)
             .withMeasure(priceComp)
             .withMeasure(price);
 
diff --git a/core/src/test/java/io/squashql/query/ATestDocBucketComparison.java b/core/src/test/java/io/squashql/query/ATestDocGroupComparison.java
similarity index 79%
rename from core/src/test/java/io/squashql/query/ATestDocBucketComparison.java
rename to core/src/test/java/io/squashql/query/ATestDocGroupComparison.java
index 193aeb8..541405a 100644
--- a/core/src/test/java/io/squashql/query/ATestDocBucketComparison.java
+++ b/core/src/test/java/io/squashql/query/ATestDocGroupComparison.java
@@ -1,21 +1,22 @@
 package io.squashql.query;
 
-import static io.squashql.query.TableField.tableField;
-import static io.squashql.transaction.DataLoader.MAIN_SCENARIO_NAME;
-import static io.squashql.transaction.DataLoader.SCENARIO_FIELD_NAME;
-
 import io.squashql.TestClass;
 import io.squashql.query.builder.Query;
-import io.squashql.query.dto.BucketColumnSetDto;
+import io.squashql.query.dto.GroupColumnSetDto;
 import io.squashql.query.dto.QueryDto;
 import io.squashql.table.Table;
 import io.squashql.type.TableTypedField;
-import java.util.List;
-import java.util.Map;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
 
+import java.util.List;
+import java.util.Map;
+
+import static io.squashql.query.TableField.tableField;
+import static io.squashql.transaction.DataLoader.MAIN_SCENARIO_NAME;
+import static io.squashql.transaction.DataLoader.SCENARIO_FIELD_NAME;
+
 /**
  * This test class is used to verify and print tables for the documentation. Nothing is asserted in those tests this is
  * why it is @{@link Disabled}.
@@ -23,7 +24,7 @@ import org.junit.jupiter.api.TestInstance;
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 @TestClass(ignore = {TestClass.Type.SPARK, TestClass.Type.BIGQUERY, TestClass.Type.SNOWFLAKE, TestClass.Type.CLICKHOUSE})
 @Disabled
-public abstract class ATestDocBucketComparison extends ABaseTestQuery {
+public abstract class ATestDocGroupComparison extends ABaseTestQuery {
 
   @Override
   protected Map<String, List<TableTypedField>> getFieldsByStore() {
@@ -45,21 +46,21 @@ public abstract class ATestDocBucketComparison extends ABaseTestQuery {
   void test() {
     Measure revenue = new ExpressionMeasure("revenue", "sum(saleprice * loavessold)");
     final Field scenario = tableField(SCENARIO_FIELD_NAME);
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", scenario)
-            .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
-            .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
-            .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "s3"))
-            .withNewBucket("group4", List.of(MAIN_SCENARIO_NAME, "s1", "s2", "s3"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", scenario)
+            .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
+            .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
+            .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "s3"))
+            .withNewGroup("group4", List.of(MAIN_SCENARIO_NAME, "s1", "s2", "s3"));
     ComparisonMeasureReferencePosition revenueComparison = new ComparisonMeasureReferencePosition(
             "revenueComparison",
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             revenue,
             Map.of(scenario, "s-1", tableField("group"), "g"),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     QueryDto queryDto = Query.from("store")
 //            .select(List.of(SCENARIO_FIELD_NAME, "saleprice", "loavessold", "pointofsale"),List.of(CountMeasure.INSTANCE, revenue))
-            .select(List.of(), List.of(bucketCS), List.of(CountMeasure.INSTANCE, revenue, revenueComparison))
+            .select(List.of(), List.of(groupCS), List.of(CountMeasure.INSTANCE, revenue, revenueComparison))
             .build();
     Table result = this.executor.executeQuery(queryDto);
     result.show();
diff --git a/core/src/test/java/io/squashql/query/ATestBucketComparison.java b/core/src/test/java/io/squashql/query/ATestGroupComparison.java
similarity index 82%
rename from core/src/test/java/io/squashql/query/ATestBucketComparison.java
rename to core/src/test/java/io/squashql/query/ATestGroupComparison.java
index 8fd4aa4..e6a4fb2 100644
--- a/core/src/test/java/io/squashql/query/ATestBucketComparison.java
+++ b/core/src/test/java/io/squashql/query/ATestGroupComparison.java
@@ -3,7 +3,7 @@ package io.squashql.query;
 import io.squashql.TestClass;
 import io.squashql.query.builder.Query;
 import io.squashql.query.database.SqlUtils;
-import io.squashql.query.dto.BucketColumnSetDto;
+import io.squashql.query.dto.GroupColumnSetDto;
 import io.squashql.query.dto.QueryDto;
 import io.squashql.table.Table;
 import io.squashql.type.TableTypedField;
@@ -25,16 +25,16 @@ import static io.squashql.transaction.DataLoader.SCENARIO_FIELD_NAME;
 
 @TestClass
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
-public abstract class ATestBucketComparison extends ABaseTestQuery {
+public abstract class ATestGroupComparison extends ABaseTestQuery {
 
   protected String storeName = "store" + getClass().getSimpleName().toLowerCase();
 
   protected String groupOfScenario = "Group of scenario";
 
-  protected BucketColumnSetDto bucketCS = new BucketColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
-          .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
-          .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
-          .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
+  protected GroupColumnSetDto groupCS = new GroupColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
+          .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
+          .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
+          .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
 
   @Override
   protected Map<String, List<TableTypedField>> getFieldsByStore() {
@@ -70,10 +70,10 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
   @ValueSource(booleans = {true, false})
   void testAbsoluteDifferenceWithFirst(boolean fullName) {
     Field scenario = fullName ? new TableField(this.storeName, SCENARIO_FIELD_NAME) : new TableField(SCENARIO_FIELD_NAME);
-    BucketColumnSetDto bucket = new BucketColumnSetDto(this.groupOfScenario, scenario)
-            .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
-            .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
-            .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
+    GroupColumnSetDto group = new GroupColumnSetDto(this.groupOfScenario, scenario)
+            .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "s1"))
+            .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "s2"))
+            .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "s1", "s2"));
 
     AggregatedMeasure price = new AggregatedMeasure("p", "price", "sum");
     ComparisonMeasureReferencePosition priceComp = new ComparisonMeasureReferencePosition(
@@ -84,7 +84,7 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
                     scenario, AComparisonExecutor.REF_POS_FIRST,
                     tableField(this.groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
     AggregatedMeasure quantity = new AggregatedMeasure("q", "quantity", "sum");
     ComparisonMeasureReferencePosition quantityComp = new ComparisonMeasureReferencePosition(
             "quantityDiff",
@@ -94,11 +94,11 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
                     scenario, AComparisonExecutor.REF_POS_FIRST,
                     tableField(this.groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     var query = Query
             .from(this.storeName)
-            .select_(List.of(bucket), List.of(priceComp, price, quantityComp, quantity))
+            .select_(List.of(group), List.of(priceComp, price, quantityComp, quantity))
             .build();
 
     Table dataset = this.executor.executeQuery(query);
@@ -119,7 +119,7 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
     query = Query
             .from(this.storeName)
             .where(scenario, eq("s1"))
-            .select_(List.of(bucket), List.of(priceComp))
+            .select_(List.of(group), List.of(priceComp))
             .build();
 
     dataset = this.executor.executeQuery(query);
@@ -139,18 +139,18 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
                     tableField(SCENARIO_FIELD_NAME), "s-1",
                     tableField(this.groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
     AggregatedMeasure quantity = new AggregatedMeasure("q", "quantity", "sum");
     ComparisonMeasureReferencePosition quantityComp = new ComparisonMeasureReferencePosition(
             "quantityDiff",
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             quantity,
             Map.of(tableField(SCENARIO_FIELD_NAME), "s-1", tableField(this.groupOfScenario), "g"),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     var query = new QueryDto()
             .table(this.storeName)
-            .withColumnSet(ColumnSetKey.BUCKET, this.bucketCS)
+            .withColumnSet(ColumnSetKey.GROUP, this.groupCS)
             .withMeasure(priceComp)
             .withMeasure(price)
             .withMeasure(quantityComp)
@@ -182,7 +182,7 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
                     tableField(SCENARIO_FIELD_NAME), AComparisonExecutor.REF_POS_FIRST,
                     tableField(this.groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
     AggregatedMeasure quantity = new AggregatedMeasure("q", "quantity", "sum");
     ComparisonMeasureReferencePosition quantityComp = new ComparisonMeasureReferencePosition(
             "quantityDiff",
@@ -192,11 +192,11 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
                     tableField(SCENARIO_FIELD_NAME), AComparisonExecutor.REF_POS_FIRST,
                     tableField(this.groupOfScenario), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     var query = new QueryDto()
             .table(this.storeName)
-            .withColumnSet(ColumnSetKey.BUCKET, this.bucketCS)
+            .withColumnSet(ColumnSetKey.GROUP, this.groupCS)
             .withMeasure(priceComp)
             .withMeasure(price)
             .withMeasure(quantityComp)
@@ -220,14 +220,14 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
   @Test
   void testOrderIsPreserved() {
     // The following order should be respected even if columns are ordered by default.
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("B", List.of("s1", MAIN_SCENARIO_NAME))
-            .withNewBucket("A", List.of("s2", MAIN_SCENARIO_NAME, "s1"))
-            .withNewBucket("C", List.of(MAIN_SCENARIO_NAME, "s2", "s1"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("B", List.of("s1", MAIN_SCENARIO_NAME))
+            .withNewGroup("A", List.of("s2", MAIN_SCENARIO_NAME, "s1"))
+            .withNewGroup("C", List.of(MAIN_SCENARIO_NAME, "s2", "s1"));
 
     var query = Query
             .from(this.storeName)
-            .select_(List.of(bucketCS), List.of(CountMeasure.INSTANCE))
+            .select_(List.of(groupCS), List.of(CountMeasure.INSTANCE))
             .build();
 
     Table dataset = this.executor.executeQuery(query);
@@ -247,15 +247,15 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
   @Test
   void testOrderIsPreservedAndNaturallyOrderOnOtherColumns() {
     // The following order should be respected even if columns are ordered by default.
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("B", List.of("s1", MAIN_SCENARIO_NAME))
-            .withNewBucket("A", List.of("s2", MAIN_SCENARIO_NAME));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("B", List.of("s1", MAIN_SCENARIO_NAME))
+            .withNewGroup("A", List.of("s2", MAIN_SCENARIO_NAME));
 
-    // Add category in the query. The table should be ordered first according the implicit order of the buckets and then
+    // Add category in the query. The table should be ordered first according the implicit order of the groups and then
     // by category.
     var query = Query
             .from(this.storeName)
-            .select(tableFields(List.of("category")), List.of(bucketCS), List.of(CountMeasure.INSTANCE))
+            .select(tableFields(List.of("category")), List.of(groupCS), List.of(CountMeasure.INSTANCE))
             .build();
 
     Table dataset = this.executor.executeQuery(query);
@@ -278,14 +278,14 @@ public abstract class ATestBucketComparison extends ABaseTestQuery {
   @Test
   void testTotal() {
     // The following order should be respected even if columns are ordered by default.
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("B", List.of("s1", MAIN_SCENARIO_NAME))
-            .withNewBucket("A", List.of("s2", MAIN_SCENARIO_NAME, "s1"))
-            .withNewBucket("C", List.of(MAIN_SCENARIO_NAME, "s2", "s1"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto(this.groupOfScenario, tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("B", List.of("s1", MAIN_SCENARIO_NAME))
+            .withNewGroup("A", List.of("s2", MAIN_SCENARIO_NAME, "s1"))
+            .withNewGroup("C", List.of(MAIN_SCENARIO_NAME, "s2", "s1"));
 
     var query = Query
             .from(this.storeName)
-            .select_(List.of(bucketCS), List.of(CountMeasure.INSTANCE))
+            .select_(List.of(groupCS), List.of(CountMeasure.INSTANCE))
             .rollup(tableFields(List.of(SCENARIO_FIELD_NAME))) // should not affect the comparison engine
             .build();
 
diff --git a/core/src/test/java/io/squashql/query/ATestPivotTable.java b/core/src/test/java/io/squashql/query/ATestPivotTable.java
index 1029479..3847dd2 100644
--- a/core/src/test/java/io/squashql/query/ATestPivotTable.java
+++ b/core/src/test/java/io/squashql/query/ATestPivotTable.java
@@ -237,22 +237,22 @@ public abstract class ATestPivotTable extends ABaseTestQuery {
   void testGroupingOneColumnEachAxis() {
     Field group = tableField("group");
     Field country = tableField("country");
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", country)
-            .withNewBucket("european", List.of("uk", "france"))
-            .withNewBucket("anglophone", List.of("usa", "uk"))
-            .withNewBucket("all", List.of("usa", "uk", "france"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", country)
+            .withNewGroup("european", List.of("uk", "france"))
+            .withNewGroup("anglophone", List.of("usa", "uk"))
+            .withNewGroup("all", List.of("usa", "uk", "france"));
     Measure amount = Functions.sum("amount", "amount");
     ComparisonMeasureReferencePosition amountComp = new ComparisonMeasureReferencePosition(
             "amountComp",
             ABSOLUTE_DIFFERENCE,
             amount,
-            Map.of(bucketCS.field, "c-1", tableField("group"), "g"),
-            ColumnSetKey.BUCKET);
+            Map.of(groupCS.field, "c-1", tableField("group"), "g"),
+            ColumnSetKey.GROUP);
 
     List<Measure> measures = List.of(amountComp);
     QueryDto query = Query
             .from(this.storeSpending)
-            .select(List.of(), List.of(bucketCS), measures)
+            .select(List.of(), List.of(groupCS), measures)
             .build();
     PivotTable result = this.executor.executePivotQuery(new PivotTableQueryDto(query, Collections.singletonList(country),
             Collections.singletonList(group), false));
@@ -279,22 +279,22 @@ public abstract class ATestPivotTable extends ABaseTestQuery {
   void testGroupingMultipleColumns(TestInfo testInfo) {
     final Field group = tableField("group");
     final Field country = tableField("country");
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", country)
-            .withNewBucket("european", List.of("uk", "france"))
-            .withNewBucket("anglophone", List.of("usa", "uk"))
-            .withNewBucket("all", List.of("usa", "uk", "france"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", country)
+            .withNewGroup("european", List.of("uk", "france"))
+            .withNewGroup("anglophone", List.of("usa", "uk"))
+            .withNewGroup("all", List.of("usa", "uk", "france"));
     Measure amount = Functions.sum("amount", "amount");
     ComparisonMeasureReferencePosition amountComp = new ComparisonMeasureReferencePosition(
             "amountComp",
             ABSOLUTE_DIFFERENCE,
             amount,
             Map.of(country, "c-1", group, "g"),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     List<Measure> measures = List.of(amountComp);
     QueryDto query = Query
             .from(this.storeSpending)
-            .select(tableFields(List.of("spending category")), List.of(bucketCS), measures)
+            .select(tableFields(List.of("spending category")), List.of(groupCS), measures)
             .build();
     verifyResults(testInfo, query, List.of("group", "country"), List.of("spending category"));
   }
@@ -425,14 +425,14 @@ public abstract class ATestPivotTable extends ABaseTestQuery {
     Measure amount = Functions.sum("amount", "amount");
     Measure pop = Functions.sum("population", "population");
 
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", tableField("spending category"))
-            .withNewBucket("group1", List.of("extra"))
-            .withNewBucket("group2", List.of("extra", "minimum expenditure"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", tableField("spending category"))
+            .withNewGroup("group1", List.of("extra"))
+            .withNewGroup("group2", List.of("extra", "minimum expenditure"));
 
     List<Measure> measuresSpending = List.of(amount);
     QueryDto query1 = Query
             .from(this.storeSpending)
-            .select(tableFields(List.of("country")), List.of(bucketCS), measuresSpending)
+            .select(tableFields(List.of("country")), List.of(groupCS), measuresSpending)
             .build();
     /*
     +---------+---------------------+-------------+--------+--------+--------+
diff --git a/core/src/test/java/io/squashql/query/ATestQueryExecutor.java b/core/src/test/java/io/squashql/query/ATestQueryExecutor.java
index 8f8db92..076f756 100644
--- a/core/src/test/java/io/squashql/query/ATestQueryExecutor.java
+++ b/core/src/test/java/io/squashql/query/ATestQueryExecutor.java
@@ -768,9 +768,9 @@ public abstract class ATestQueryExecutor extends ABaseTestQuery {
 
   @Test
   void testMergeWithColumnSetsPreserveOrder() {
-    BucketColumnSetDto group1 = new BucketColumnSetDto("group1", tableField("category"))
-            .withNewBucket("Food & Drink", List.of("food", "drink"))
-            .withNewBucket("Other", List.of("cloth"));
+    GroupColumnSetDto group1 = new GroupColumnSetDto("group1", tableField("category"))
+            .withNewGroup("Food & Drink", List.of("food", "drink"))
+            .withNewGroup("Other", List.of("cloth"));
     /*
       +--------------+----------+----------+-------+
       |       group1 | category | category | p_sum |
@@ -785,9 +785,9 @@ public abstract class ATestQueryExecutor extends ABaseTestQuery {
             .select_(List.of(group1), List.of(sum("p_sum", "price")))
             .build();
 
-    BucketColumnSetDto group2 = new BucketColumnSetDto("group2", tableField("subcategory"))
-            .withNewBucket("Categorized", List.of("biscuit"))
-            .withNewBucket("Not categorized", Arrays.asList(null, "other"));
+    GroupColumnSetDto group2 = new GroupColumnSetDto("group2", tableField("subcategory"))
+            .withNewGroup("Categorized", List.of("biscuit"))
+            .withNewGroup("Not categorized", Arrays.asList(null, "other"));
     /*
       +-----------------+-------------+-------+
       |          group2 | subcategory | p_avg |
diff --git a/core/src/test/java/io/squashql/query/TestMeasures.java b/core/src/test/java/io/squashql/query/TestMeasures.java
index e82b343..51d86ad 100644
--- a/core/src/test/java/io/squashql/query/TestMeasures.java
+++ b/core/src/test/java/io/squashql/query/TestMeasures.java
@@ -64,7 +64,7 @@ public class TestMeasures {
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             kpi,
             referencePosition,
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     ComparisonMeasureReferencePosition parentComparisonMeasure = new ComparisonMeasureReferencePosition("parent", ComparisonMethod.DIVIDE, amount, tableFields(List.of("city", "country", "continent")));
 
diff --git a/core/src/test/java/io/squashql/query/builder/TestQuery.java b/core/src/test/java/io/squashql/query/builder/TestQuery.java
index 3c581a0..d899679 100644
--- a/core/src/test/java/io/squashql/query/builder/TestQuery.java
+++ b/core/src/test/java/io/squashql/query/builder/TestQuery.java
@@ -19,7 +19,7 @@ public class TestQuery {
 
   @Test
   void testSimple() {
-    BucketColumnSetDto columnSet = new BucketColumnSetDto();
+    GroupColumnSetDto columnSet = new GroupColumnSetDto();
     Measure sum = sum("sum", "f2");
 
     QueryDto build = Query
@@ -31,7 +31,7 @@ public class TestQuery {
             .table("saas")
             .withColumn(tableField("col1"))
             .withColumn(tableField("col2"))
-            .withColumnSet(ColumnSetKey.BUCKET, columnSet)
+            .withColumnSet(ColumnSetKey.GROUP, columnSet)
             .withMeasure(sum);
 
     Assertions.assertThat(build).isEqualTo(q);
@@ -68,7 +68,7 @@ public class TestQuery {
             .table("saas")
             .withColumn(tableField("col1"))
             .withColumn(tableField("col2"))
-            .withColumnSet(ColumnSetKey.BUCKET, columnSet)
+            .withColumnSet(ColumnSetKey.GROUP, columnSet)
             .withMeasure(sum)
             .withLimit(100);
 
diff --git a/core/src/test/java/io/squashql/util/TestDatabaseQueryCreation.java b/core/src/test/java/io/squashql/util/TestDatabaseQueryCreation.java
index aaa7eea..a0e33f4 100644
--- a/core/src/test/java/io/squashql/util/TestDatabaseQueryCreation.java
+++ b/core/src/test/java/io/squashql/util/TestDatabaseQueryCreation.java
@@ -1,7 +1,7 @@
 package io.squashql.util;
 
 import io.squashql.query.*;
-import io.squashql.query.dto.BucketColumnSetDto;
+import io.squashql.query.dto.GroupColumnSetDto;
 import io.squashql.query.dto.QueryDto;
 import io.squashql.query.parameter.Parameter;
 import org.assertj.core.api.Assertions;
@@ -35,7 +35,7 @@ public class TestDatabaseQueryCreation {
   @Test
   void testColumnSetInSubQuery() {
     QueryDto subQuery = new QueryDto().table("table")
-            .withColumnSet(ColumnSetKey.BUCKET, new BucketColumnSetDto("a", tableField("b")));
+            .withColumnSet(ColumnSetKey.GROUP, new GroupColumnSetDto("a", tableField("b")));
     QueryDto queryDto = new QueryDto().table(subQuery);
 
     Assertions.assertThatThrownBy(() -> new QueryResolver(queryDto, Collections.emptyMap()))
@@ -57,7 +57,7 @@ public class TestDatabaseQueryCreation {
   @Test
   void testUnsupportedMeasureInSubQuery() {
     QueryDto subQuery = new QueryDto().table("table")
-            .withMeasure(new ComparisonMeasureReferencePosition("alias", ComparisonMethod.DIVIDE, new AggregatedMeasure("p", "price", "sum"), Collections.emptyMap(), ColumnSetKey.BUCKET));
+            .withMeasure(new ComparisonMeasureReferencePosition("alias", ComparisonMethod.DIVIDE, new AggregatedMeasure("p", "price", "sum"), Collections.emptyMap(), ColumnSetKey.GROUP));
     QueryDto queryDto = new QueryDto().table(subQuery);
 
     Assertions.assertThatThrownBy(() -> new QueryResolver(queryDto, Collections.emptyMap()))
diff --git a/duckdb/src/test/java/io/squashql/TestPivotTable.java b/duckdb/src/test/java/io/squashql/TestPivotTable.java
index a15ece1..1aeb4f8 100644
--- a/duckdb/src/test/java/io/squashql/TestPivotTable.java
+++ b/duckdb/src/test/java/io/squashql/TestPivotTable.java
@@ -355,31 +355,31 @@ public class TestPivotTable {
   }
 
   @Test
-  void testBucketingComparisonWithAliases() {
+  void testGroupComparisonWithAliases() {
     setup(getFieldsByStore(), this::loadData);
 
     Field countryAliased = this.country.as("countryAliased"); // ALIAS this column. this is what it is tested here
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", countryAliased)
-            .withNewBucket("european", List.of("uk", "france"))
-            .withNewBucket("anglophone", List.of("usa", "uk"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", countryAliased)
+            .withNewGroup("european", List.of("uk", "france"))
+            .withNewGroup("anglophone", List.of("usa", "uk"));
     Measure amount = Functions.sum("amount", "amount");
     ComparisonMeasureReferencePosition amountComp = new ComparisonMeasureReferencePosition(
             "amountComp",
             ABSOLUTE_DIFFERENCE,
             amount,
-            Map.of(bucketCS.field, "c-1", bucketCS.newField, "g"),
-            ColumnSetKey.BUCKET);
+            Map.of(groupCS.field, "c-1", groupCS.newField, "g"),
+            ColumnSetKey.GROUP);
 
     List<Measure> measures = List.of(amountComp, amount);
 
     QueryDto query = Query
             .from(this.storeSpending)
             .where(Functions.criterion(this.spendingCategory, Functions.eq("extra"))) // to get a small result
-            .select(List.of(this.spendingCategory), List.of(bucketCS), measures)
+            .select(List.of(this.spendingCategory), List.of(groupCS), measures)
             .build();
     this.executor.executeQuery(query)
             .show();
-    List<Field> rows = List.of(bucketCS.newField, countryAliased);
+    List<Field> rows = List.of(groupCS.newField, countryAliased);
     List<Field> columns = List.of(this.spendingCategory);
     PivotTable pivotTable = this.executor.executePivotQuery(new PivotTableQueryDto(query, rows, columns, false));
     Assertions.assertThat(pivotTable.table.headers().stream().map(Header::name))
diff --git a/duckdb/src/test/java/io/squashql/query/TestDuckDBDocBucketComparison.java b/duckdb/src/test/java/io/squashql/query/TestDuckDBDocGroupComparison.java
similarity index 92%
rename from duckdb/src/test/java/io/squashql/query/TestDuckDBDocBucketComparison.java
rename to duckdb/src/test/java/io/squashql/query/TestDuckDBDocGroupComparison.java
index 71c6c68..7b17dc4 100644
--- a/duckdb/src/test/java/io/squashql/query/TestDuckDBDocBucketComparison.java
+++ b/duckdb/src/test/java/io/squashql/query/TestDuckDBDocGroupComparison.java
@@ -10,7 +10,7 @@ import io.squashql.transaction.DuckDBDataLoader;
 /**
  * Do not edit this class, it has been generated automatically by {@link io.squashql.template.DuckDBClassTemplateGenerator}.
  */
-public class TestDuckDBDocBucketComparison extends ATestDocBucketComparison {
+public class TestDuckDBDocGroupComparison extends ATestDocGroupComparison {
 
   @Override
   protected QueryEngine createQueryEngine(Datastore datastore) {
diff --git a/duckdb/src/test/java/io/squashql/query/TestDuckDBBucketComparison.java b/duckdb/src/test/java/io/squashql/query/TestDuckDBGroupComparison.java
similarity index 93%
rename from duckdb/src/test/java/io/squashql/query/TestDuckDBBucketComparison.java
rename to duckdb/src/test/java/io/squashql/query/TestDuckDBGroupComparison.java
index c08b624..1ff0c08 100644
--- a/duckdb/src/test/java/io/squashql/query/TestDuckDBBucketComparison.java
+++ b/duckdb/src/test/java/io/squashql/query/TestDuckDBGroupComparison.java
@@ -10,7 +10,7 @@ import io.squashql.transaction.DuckDBDataLoader;
 /**
  * Do not edit this class, it has been generated automatically by {@link io.squashql.template.DuckDBClassTemplateGenerator}.
  */
-public class TestDuckDBBucketComparison extends ATestBucketComparison {
+public class TestDuckDBGroupComparison extends ATestGroupComparison {
 
   @Override
   protected QueryEngine createQueryEngine(Datastore datastore) {
diff --git a/js/typescript-library/src/__tests__/dependencies/computeColumnSetDependencies.test.ts b/js/typescript-library/src/__tests__/dependencies/computeColumnSetDependencies.test.ts
index ae8241b..51e9e50 100644
--- a/js/typescript-library/src/__tests__/dependencies/computeColumnSetDependencies.test.ts
+++ b/js/typescript-library/src/__tests__/dependencies/computeColumnSetDependencies.test.ts
@@ -1,6 +1,6 @@
 import * as dependencies from "../../dependencies"
 import {TableField} from "../../field"
-import {BucketColumnSet, ColumnSet} from "../../columnsets"
+import {GroupColumnSet, ColumnSet} from "../../columnsets"
 
 afterEach(() => {
   jest.restoreAllMocks()
@@ -8,25 +8,25 @@ afterEach(() => {
 
 describe('computeColumnSetDependencies', () => {
 
-  it('should compute dependencies for BucketColumnSet', () => {
+  it('should compute dependencies for GroupColumnSet', () => {
     const createdField = new TableField('mockTable.createdField')
     const mockField = new TableField('mockTable.mockField')
-    const columnSet = new BucketColumnSet(createdField, mockField, new Map())
+    const columnSet = new GroupColumnSet(createdField, mockField, new Map())
     const result = dependencies.computeColumnSetDependencies(columnSet)
 
     expect(result).toEqual(expect.arrayContaining([mockField]))
   })
 
   it('should throw an error for unknown ColumnSet type', () => {
-    class UnknownBucketColumnSet implements ColumnSet {
+    class UnknownGroupColumnSet implements ColumnSet {
       readonly class: string
       readonly key: string
     }
 
-    const unknownBucketColumnSet = new UnknownBucketColumnSet()
+    const unknownGroupColumnSet = new UnknownGroupColumnSet()
 
-    expect(() => dependencies.computeColumnSetDependencies(unknownBucketColumnSet)).toThrow(
-            "ColumnSet with unknown type: class UnknownBucketColumnSet"
+    expect(() => dependencies.computeColumnSetDependencies(unknownGroupColumnSet)).toThrow(
+            "ColumnSet with unknown type: class UnknownGroupColumnSet"
     )
   })
 
diff --git a/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts b/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
index b1a5609..9e16671 100644
--- a/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
+++ b/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
@@ -64,7 +64,7 @@ describe('computeMeasureDependencies', () => {
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             mockMeasure1,
             referencePosition,
-            ColumnSetKey.BUCKET,
+            ColumnSetKey.GROUP,
             mockPeriod,
             ancestors
     )
diff --git a/server/src/test/java/io/squashql/client/HttpClientQuerierTest.java b/server/src/test/java/io/squashql/client/HttpClientQuerierTest.java
index d6e57cc..c4027f1 100644
--- a/server/src/test/java/io/squashql/client/HttpClientQuerierTest.java
+++ b/server/src/test/java/io/squashql/client/HttpClientQuerierTest.java
@@ -101,10 +101,10 @@ public class HttpClientQuerierTest {
 
   @Test
   void testRunGroupingScenarioQuery() {
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "MN up"))
-            .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "MN & MDD up"))
-            .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "MN up", "MN & MDD up"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "MN up"))
+            .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "MN & MDD up"))
+            .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "MN up", "MN & MDD up"));
 
     Measure aggregatedMeasure = Functions.sum("capdv", "capdv");
     ComparisonMeasureReferencePosition capdvDiff = new ComparisonMeasureReferencePosition(
@@ -115,10 +115,10 @@ public class HttpClientQuerierTest {
                     tableField(SCENARIO_FIELD_NAME), "first",
                     tableField("group"), "g"
             ),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
     var query = Query
             .from("our_prices")
-            .select_(List.of(bucketCS), List.of(capdvDiff, aggregatedMeasure))
+            .select_(List.of(groupCS), List.of(capdvDiff, aggregatedMeasure))
             .build();
 
     QueryResultDto response = this.querier.run(query);
diff --git a/server/src/test/java/io/squashql/js/TestJavascriptLibrary.java b/server/src/test/java/io/squashql/js/TestJavascriptLibrary.java
index eea31d8..f4658e4 100644
--- a/server/src/test/java/io/squashql/js/TestJavascriptLibrary.java
+++ b/server/src/test/java/io/squashql/js/TestJavascriptLibrary.java
@@ -56,11 +56,11 @@ public class TestJavascriptLibrary {
     var one = new ConstantField(1);
     q.withMeasure(avgIf("whatever", divide(f1, plus(one, rate)), criterion(plus(f1, f2).as("f1+f2"), one, ConditionType.GT)));
 
-    q.withMeasure(new ComparisonMeasureReferencePosition("comp bucket",
+    q.withMeasure(new ComparisonMeasureReferencePosition("comp group",
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             price,
             Map.of(tableField("scenario"), "s-1", tableField("group"), "g"),
-            ColumnSetKey.BUCKET));
+            ColumnSetKey.GROUP));
 
     Period.Month month = new Period.Month(tableField("Month"), tableField("Year"));
     q.withMeasure(new ComparisonMeasureReferencePosition("growth",
@@ -86,10 +86,10 @@ public class TestJavascriptLibrary {
     q.orderBy(a, OrderKeywordDto.ASC);
     q.orderBy(b, List.of("1", "l", "p"));
 
-    BucketColumnSetDto columnSet = new BucketColumnSetDto("group", tableField("scenario"))
-            .withNewBucket("a", List.of("a1", "a2"))
-            .withNewBucket("b", List.of("b1", "b2"));
-    q.withColumnSet(ColumnSetKey.BUCKET, columnSet);
+    GroupColumnSetDto columnSet = new GroupColumnSetDto("group", tableField("scenario"))
+            .withNewGroup("a", List.of("a1", "a2"))
+            .withNewGroup("b", List.of("b1", "b2"));
+    q.withColumnSet(ColumnSetKey.GROUP, columnSet);
 
     QueryDto subQuery = new QueryDto()
             .table(table)
@@ -123,9 +123,9 @@ public class TestJavascriptLibrary {
     var cte1 = new VirtualTableDto("myCte1", List.of("id", "min", "max", "other"), List.of(List.of(0, 0, 1, "x"), List.of(1, 2, 3, "y")));
     var cte2 = new VirtualTableDto("myCte2", List.of("id", "min", "max", "other"), List.of(List.of(0, 4, 12, "a"), List.of(1, 12, 25, "b")));
 
-    BucketColumnSetDto bucketColumnSet = new BucketColumnSetDto("group", tableField("scenario"))
-            .withNewBucket("a", List.of("a1", "a2"))
-            .withNewBucket("b", List.of("b1", "b2"));
+    GroupColumnSetDto groupColumnSet = new GroupColumnSetDto("group", tableField("scenario"))
+            .withNewGroup("a", List.of("a1", "a2"))
+            .withNewGroup("b", List.of("b1", "b2"));
 
     Measure measure = sum("sum", "f1");
     Measure measureExpr = new ExpressionMeasure("sum_expr", "sum(f1)");
@@ -140,7 +140,7 @@ public class TestJavascriptLibrary {
             .where(tableField("f2"), gt(659))
             .where(tableField("f3"), eq(123))
             .select(tableFields(List.of("a", "b")),
-                    List.of(bucketColumnSet),
+                    List.of(groupColumnSet),
                     List.of(measure, avg("sum", "f1"), measureExpr))
             .rollup(tableField("a"), tableField("b"))
             .having(all(criterion((BasicMeasure) measure, gt(0)), criterion((BasicMeasure) measureExpr, lt(10))))
diff --git a/server/src/test/java/io/squashql/spring/web/rest/QueryControllerTest.java b/server/src/test/java/io/squashql/spring/web/rest/QueryControllerTest.java
index 2b6163a..dbc148e 100644
--- a/server/src/test/java/io/squashql/spring/web/rest/QueryControllerTest.java
+++ b/server/src/test/java/io/squashql/spring/web/rest/QueryControllerTest.java
@@ -137,10 +137,10 @@ public class QueryControllerTest {
 
   @Test
   void testScenarioGroupingQuery() throws Exception {
-    BucketColumnSetDto bucketCS = new BucketColumnSetDto("group", tableField(SCENARIO_FIELD_NAME))
-            .withNewBucket("group1", List.of(MAIN_SCENARIO_NAME, "MN up"))
-            .withNewBucket("group2", List.of(MAIN_SCENARIO_NAME, "MN & MDD up"))
-            .withNewBucket("group3", List.of(MAIN_SCENARIO_NAME, "MN up", "MN & MDD up"));
+    GroupColumnSetDto groupCS = new GroupColumnSetDto("group", tableField(SCENARIO_FIELD_NAME))
+            .withNewGroup("group1", List.of(MAIN_SCENARIO_NAME, "MN up"))
+            .withNewGroup("group2", List.of(MAIN_SCENARIO_NAME, "MN & MDD up"))
+            .withNewGroup("group3", List.of(MAIN_SCENARIO_NAME, "MN up", "MN & MDD up"));
 
     Measure aggregatedMeasure = Functions.sum("capdv", "capdv");
     Measure indicePrix = new ExpressionMeasure(
@@ -151,13 +151,13 @@ public class QueryControllerTest {
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             aggregatedMeasure,
             Map.of(tableField(SCENARIO_FIELD_NAME), "s-1", tableField("group"), "g"),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
     ComparisonMeasureReferencePosition indicePrixDiff = new ComparisonMeasureReferencePosition(
             "indicePrixDiff",
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
             indicePrix,
             Map.of(tableField(SCENARIO_FIELD_NAME), "s-1", tableField("group"), "g"),
-            ColumnSetKey.BUCKET);
+            ColumnSetKey.GROUP);
 
     var query = Query
             .from("our_prices")
@@ -165,7 +165,7 @@ public class QueryControllerTest {
             .on(criterion("our_prices" + ".pdv", "our_stores_their_stores" + ".our_store", ConditionType.EQ))
             .join("their_prices", JoinType.INNER)
             .on(criterion("their_prices" + ".competitor_concurrent_pdv", "our_stores_their_stores" + ".their_store", ConditionType.EQ))
-            .select_(List.of(bucketCS), List.of(aggregatedMeasureDiff, indicePrixDiff))
+            .select_(List.of(groupCS), List.of(aggregatedMeasureDiff, indicePrixDiff))
             .build();
 
     this.mvc.perform(MockMvcRequestBuilders.post(QueryController.MAPPING_QUERY)
diff --git a/snowflake/src/test/java/io/squashql/query/TestSnowflakeBucketComparison.java b/snowflake/src/test/java/io/squashql/query/TestSnowflakeGroupComparison.java
similarity index 95%
rename from snowflake/src/test/java/io/squashql/query/TestSnowflakeBucketComparison.java
rename to snowflake/src/test/java/io/squashql/query/TestSnowflakeGroupComparison.java
index 5c14c88..cc8f879 100644
--- a/snowflake/src/test/java/io/squashql/query/TestSnowflakeBucketComparison.java
+++ b/snowflake/src/test/java/io/squashql/query/TestSnowflakeGroupComparison.java
@@ -11,7 +11,7 @@ import org.junit.jupiter.api.AfterAll;
 /**
  * Do not edit this class, it has been generated automatically by {@link io.squashql.template.SnowflakeClassTemplateGenerator}.
  */
-public class TestSnowflakeBucketComparison extends ATestBucketComparison {
+public class TestSnowflakeGroupComparison extends ATestGroupComparison {
 
   @AfterAll
   void tearDown() {
diff --git a/spark/src/test/java/io/squashql/query/TestSparkBucketComparison.java b/spark/src/test/java/io/squashql/query/TestSparkGroupComparison.java
similarity index 94%
rename from spark/src/test/java/io/squashql/query/TestSparkBucketComparison.java
rename to spark/src/test/java/io/squashql/query/TestSparkGroupComparison.java
index 36f2cc9..2263211 100644
--- a/spark/src/test/java/io/squashql/query/TestSparkBucketComparison.java
+++ b/spark/src/test/java/io/squashql/query/TestSparkGroupComparison.java
@@ -11,7 +11,7 @@ import org.junit.jupiter.api.AfterAll;
 /**
  * Do not edit this class, it has been generated automatically by {@link io.squashql.template.SparkClassTemplateGenerator}.
  */
-public class TestSparkBucketComparison extends ATestBucketComparison {
+public class TestSparkGroupComparison extends ATestGroupComparison {
 
   @AfterAll
   void tearDown() {