[ASTERIXDB-2956][IDX] Adding RQG for array indexes + fixes
- user model changes: no
- storage format changes: no
- interface changes: no
Adding RQGs for array indexes and the fixes detailed below:
- Handle conjuncts with nested ANDs (for SOME AND EVERY).
- Disable merge-select local rewrite when a join is encountered.
- Analyze for array indexes for each ASSIGN op (as opposed to the last
ASSIGN).
- Disable INLJ with cross products in probe (ASTERIXDB-2966 bug).
- Enable general theta join INLJ acceleration with array indexes.
- Fix type builder bug for getting array type (at initial ingestion).
- Small fixes to get composite-atomic index initial ingestion working
(now evaluators and record descriptors between operators are correct).
Change-Id: I25a0f34010bca6296e75c6d6bc04eb515376941f
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/13263
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
index 37109ab..25e8813 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
@@ -837,8 +837,7 @@
IOptimizationContext context, List<Index> datasetIndexes, int optFuncExprIndex,
AccessMethodAnalysisContext analysisCtx) throws AlgebricksException {
boolean doesArrayIndexQualify = context.getPhysicalOptimizationConfig().isArrayIndexEnabled()
- && datasetIndexes.stream().anyMatch(i -> i.getIndexType() == IndexType.ARRAY)
- && assignOrUnnestIndex == subTree.getAssignsAndUnnests().size() - 1;
+ && datasetIndexes.stream().anyMatch(i -> i.getIndexType() == IndexType.ARRAY);
List<LogicalVariable> varList = assignOp.getVariables();
MutableInt fieldSource = new MutableInt(0);
for (int varIndex = 0; varIndex < varList.size(); varIndex++) {
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
index 55f0827..b733b52 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
@@ -19,7 +19,9 @@
package org.apache.asterix.optimizer.rules.am;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
import org.apache.asterix.common.config.DatasetConfig.IndexType;
@@ -38,6 +40,7 @@
import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.UnnestOperator;
@@ -98,6 +101,29 @@
return false;
}
+ // TODO (GLENN): There is a bug with cross-products originating from the probe. Disable this case for now.
+ Deque<ILogicalOperator> opStack = new ArrayDeque<>();
+ List<ILogicalOperator> visited = new ArrayList<>();
+ opStack.add(probeSubTree.getRoot());
+ while (!opStack.isEmpty()) {
+ ILogicalOperator workingOp = opStack.pop();
+ if (!visited.contains(workingOp)) {
+ if (workingOp.getOperatorTag() == LogicalOperatorTag.INNERJOIN
+ || workingOp.getOperatorTag() == LogicalOperatorTag.LEFTOUTERJOIN) {
+ AbstractBinaryJoinOperator joinOperator = (AbstractBinaryJoinOperator) workingOp;
+ if (joinOperator.getCondition().getValue().equals(ConstantExpression.TRUE)) {
+ return false;
+ }
+ }
+ visited.add(workingOp);
+ }
+ for (Mutable<ILogicalOperator> opRef : workingOp.getInputs()) {
+ if (!visited.contains(opRef.getValue())) {
+ opStack.push(opRef.getValue());
+ }
+ }
+ }
+
LogicalVariable newNullPlaceHolderVar = null;
if (isLeftOuterJoin) {
// Gets a new null place holder variable that is the first field variable of the primary key from the
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java
index a800111..bc6d21c 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceJoinAccessMethodRule.java
@@ -26,7 +26,6 @@
import org.apache.asterix.metadata.entities.Dataset;
import org.apache.asterix.metadata.entities.Index;
-import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.optimizer.rules.am.array.IIntroduceAccessMethodRuleLocalRewrite;
import org.apache.asterix.optimizer.rules.am.array.JoinFromSubplanRewrite;
import org.apache.commons.lang3.mutable.Mutable;
@@ -105,7 +104,9 @@
registerAccessMethod(BTreeAccessMethod.INSTANCE, accessMethods);
registerAccessMethod(RTreeAccessMethod.INSTANCE, accessMethods);
registerAccessMethod(InvertedIndexAccessMethod.INSTANCE, accessMethods);
- JoinFromSubplanRewrite.addOptimizableFunction(BuiltinFunctions.EQ);
+ for (Pair<FunctionIdentifier, Boolean> optFunc : BTreeAccessMethod.INSTANCE.getOptimizableFunctions()) {
+ JoinFromSubplanRewrite.addOptimizableFunction(optFunc.first);
+ }
}
/**
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/AbstractOperatorFromSubplanRewrite.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/AbstractOperatorFromSubplanRewrite.java
index 89800d8..0f7f354 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/AbstractOperatorFromSubplanRewrite.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/AbstractOperatorFromSubplanRewrite.java
@@ -102,7 +102,7 @@
protected LogicalVariable getConditioningVariable(ILogicalExpression condition) {
List<Mutable<ILogicalExpression>> selectConjuncts = new ArrayList<>();
- if (condition.splitIntoConjuncts(selectConjuncts)) {
+ if (splitIntoConjuncts(condition, selectConjuncts)) {
for (Mutable<ILogicalExpression> conjunct : selectConjuncts) {
if (conjunct.getValue().getExpressionTag().equals(LogicalExpressionTag.VARIABLE)) {
return ((VariableReferenceExpression) conjunct.getValue()).getVariableReference();
@@ -132,7 +132,7 @@
// Ensure that this SELECT represents a predicate for an existential query, and is a query we can optimize.
ILogicalExpression normalizedSelectCondition =
normalizeCondition(workingSubplanRootAsAggregate, optimizableSelect.getCondition().getValue());
- normalizedSelectCondition = keepOptimizableFunctions(normalizedSelectCondition);
+ normalizedSelectCondition = keepOptimizableFunctions(normalizedSelectCondition).cloneExpression();
// Create a copy of this SELECT, and set this to our rewrite root.
SelectOperator rewriteRootSelect = new SelectOperator(new MutableObject<>(normalizedSelectCondition),
@@ -226,9 +226,7 @@
// Sanity check: we should always be working with an UNNEST at this stage.
if (bottommostNewUnnest == null) {
- throw new CompilationException(ErrorCode.COMPILATION_ERROR,
- workingSubplanRootAsAggregate.getSourceLocation(),
- "UNNEST expected in nested plan branch, but not found.");
+ return null;
}
// If we are working with strict universal quantification, then we must also check whether we have a
@@ -255,7 +253,7 @@
combinedCondition.setSourceLocation(selectOp.getSourceLocation());
List<Mutable<ILogicalExpression>> conjuncts = new ArrayList<>();
- if (selectOp.getCondition().getValue().splitIntoConjuncts(conjuncts)) {
+ if (splitIntoConjuncts(selectOp.getCondition().getValue(), conjuncts)) {
combinedCondition.getArguments().addAll(conjuncts);
conjuncts.clear();
} else {
@@ -266,7 +264,7 @@
case LEFTOUTERJOIN:
case INNERJOIN:
AbstractBinaryJoinOperator joinOp = (AbstractBinaryJoinOperator) auxOp;
- if (joinOp.getCondition().getValue().splitIntoConjuncts(conjuncts)) {
+ if (splitIntoConjuncts(joinOp.getCondition().getValue(), conjuncts)) {
combinedCondition.getArguments().addAll(conjuncts);
} else {
combinedCondition.getArguments().add(joinOp.getCondition());
@@ -275,7 +273,7 @@
case SELECT:
SelectOperator selectOp2 = (SelectOperator) auxOp;
- if (selectOp2.getCondition().getValue().splitIntoConjuncts(conjuncts)) {
+ if (splitIntoConjuncts(selectOp2.getCondition().getValue(), conjuncts)) {
combinedCondition.getArguments().addAll(conjuncts);
} else {
combinedCondition.getArguments().add(selectOp2.getCondition());
@@ -343,7 +341,7 @@
if (cond.getExpressionTag().equals(LogicalExpressionTag.FUNCTION_CALL)) {
AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) cond;
List<Mutable<ILogicalExpression>> conjuncts = new ArrayList<>();
- if (func.splitIntoConjuncts(conjuncts)) {
+ if (splitIntoConjuncts(func, conjuncts)) {
List<Mutable<ILogicalExpression>> optimizableConjuncts = new ArrayList<>();
for (Mutable<ILogicalExpression> conjunct : conjuncts) {
if (conjunct.getValue().getExpressionTag().equals(LogicalExpressionTag.FUNCTION_CALL)
@@ -415,7 +413,7 @@
ILogicalExpression selectCondExpr =
normalizeCondition(null, ((SelectOperator) subplanInput).getCondition().getValue());
List<Mutable<ILogicalExpression>> conjunctsFromSelect = new ArrayList<>();
- if (selectCondExpr.splitIntoConjuncts(conjunctsFromSelect)) {
+ if (splitIntoConjuncts(selectCondExpr, conjunctsFromSelect)) {
// We have a collection of conjuncts. Analyze each conjunct w/ a function.
for (Mutable<ILogicalExpression> mutableConjunct : conjunctsFromSelect) {
ILogicalExpression workingConjunct = mutableConjunct.getValue();
@@ -500,4 +498,20 @@
return ifMissingOrNullFunction.getArguments().get(0).getValue().cloneExpression();
}
}
+
+ private boolean splitIntoConjuncts(ILogicalExpression expression, List<Mutable<ILogicalExpression>> conjuncts) {
+ List<Mutable<ILogicalExpression>> exprConjuncts = new ArrayList<>();
+ if (expression.splitIntoConjuncts(exprConjuncts)) {
+ for (Mutable<ILogicalExpression> conjunct : exprConjuncts) {
+ List<Mutable<ILogicalExpression>> innerExprConjuncts = new ArrayList<>();
+ if (splitIntoConjuncts(conjunct.getValue(), innerExprConjuncts)) {
+ conjuncts.addAll(innerExprConjuncts);
+ } else {
+ conjuncts.add(conjunct);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/JoinFromSubplanRewrite.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/JoinFromSubplanRewrite.java
index c6fb5fd..aa80462 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/JoinFromSubplanRewrite.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/JoinFromSubplanRewrite.java
@@ -181,8 +181,9 @@
// Traverse our subplan and generate a SELECT branch if applicable.
SubplanOperator subplanOperator =
(SubplanOperator) joinContext.selectAfterSubplan.getInputs().get(0).getValue();
+ List<Mutable<ILogicalOperator>> originalOpInputs = originalOperator.getInputs();
Pair<SelectOperator, UnnestOperator> traversalOutput =
- traverseSubplanBranch(subplanOperator, originalOperator.getInputs().get(1).getValue(), true);
+ traverseSubplanBranch(subplanOperator, originalOpInputs.get(1).getValue(), true);
if (traversalOutput == null) {
return null;
}
@@ -190,12 +191,11 @@
// We have successfully generated a SELECT branch. Create the new JOIN operator.
ScalarFunctionCallExpression newCond = coalesceConditions(traversalOutput.first, joinContext.originalJoinRoot);
joinContext.newJoinRoot = new InnerJoinOperator(new MutableObject<>(newCond));
- joinContext.newJoinRoot.getInputs().add(0, originalOperator.getInputs().get(0));
+ joinContext.newJoinRoot.getInputs().add(0, new MutableObject<>(originalOpInputs.get(0).getValue()));
// Connect the join branches together.
traversalOutput.second.getInputs().clear();
- traversalOutput.second.getInputs().add(originalOperator.getInputs().get(1));
- context.computeAndSetTypeEnvironmentForOperator(traversalOutput.second);
+ traversalOutput.second.getInputs().add(new MutableObject<>(originalOpInputs.get(1).getValue()));
joinContext.newJoinRoot.getInputs().add(1, traversalOutput.first.getInputs().get(0));
context.computeAndSetTypeEnvironmentForOperator(joinContext.newJoinRoot);
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/MergedSelectRewrite.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/MergedSelectRewrite.java
index c9705ab..5aefdbf 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/MergedSelectRewrite.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/array/MergedSelectRewrite.java
@@ -64,7 +64,10 @@
// Explore all operators below this SELECT until the first data source operator.
selectRootStack.push(originalOperator);
- collectSelectConjuncts(originalOperator.getInputs().get(0));
+ if (!collectSelectConjuncts(originalOperator.getInputs().get(0))) {
+ // We encountered a JOIN operator. Exit early.
+ return null;
+ }
if (thisSelectConjuncts.size() == selectConjuncts.size()) {
// No other SELECTs were found. Return null to indicate there were no SELECTs to merge.
@@ -98,7 +101,7 @@
return selectRootStack.pop();
}
- private void collectSelectConjuncts(Mutable<ILogicalOperator> workingOp) {
+ private boolean collectSelectConjuncts(Mutable<ILogicalOperator> workingOp) {
switch (workingOp.getValue().getOperatorTag()) {
case DATASOURCESCAN:
case EMPTYTUPLESOURCE:
@@ -110,7 +113,7 @@
case INNERJOIN:
case LEFTOUTERJOIN:
// We are not interested in exploring joins in this class.
- break;
+ return false;
case SELECT:
SelectOperator selectOperator = (SelectOperator) workingOp.getValue();
@@ -123,9 +126,12 @@
default:
// Explore the rest of our plan in our DFS fashion.
for (Mutable<ILogicalOperator> input : workingOp.getValue().getInputs()) {
- collectSelectConjuncts(input);
+ if (!collectSelectConjuncts(input)) {
+ return false;
+ }
}
}
+ return true;
}
private void removeSelectsFromPlan(ILogicalOperator parentOp, Mutable<ILogicalOperator> workingOp) {
diff --git a/asterixdb/asterix-app/data/array-index.adm b/asterixdb/asterix-app/data/array-index.adm
new file mode 100644
index 0000000..fbe2221
--- /dev/null
+++ b/asterixdb/asterix-app/data/array-index.adm
@@ -0,0 +1,500 @@
+{"grouping_1000":1, "grouping_500":1, "grouping_250":1, "grouping_100":1, "integer_rand_2000":null, "integer_seq_2000":1, "integer_rand_2":0, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":2, "grouping_500":2, "grouping_250":2, "grouping_100":2, "integer_rand_2000":null, "integer_seq_2000":2, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":3, "grouping_500":3, "grouping_250":3, "grouping_100":3, "integer_rand_2000":78, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":18, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":null}
+{"grouping_1000":4, "grouping_500":4, "grouping_250":4, "grouping_100":4, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_20":null, "string_rand_26_a":0, "string_rand_26_b":null, "string_rand_26_c":0}
+{"grouping_1000":5, "grouping_500":5, "grouping_250":5, "grouping_100":5, "integer_rand_2000":null, "integer_seq_2000":5, "integer_rand_2":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":null}
+{"grouping_1000":6, "grouping_500":6, "grouping_250":6, "grouping_100":6, "integer_seq_2000":null, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":0}
+{"grouping_1000":7, "grouping_500":7, "grouping_250":7, "grouping_100":7, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":null, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":8, "grouping_500":8, "grouping_250":8, "grouping_100":8, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":9, "grouping_500":9, "grouping_250":9, "grouping_100":9, "integer_rand_2000":null, "integer_seq_2000":9, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":0}
+{"grouping_1000":10, "grouping_500":10, "grouping_250":10, "grouping_100":10, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_c":0}
+{"grouping_1000":11, "grouping_500":11, "grouping_250":11, "grouping_100":11, "integer_rand_2000":null, "integer_seq_2000":11, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_b":0, "string_rand_26_c":null}
+{"grouping_1000":12, "grouping_500":12, "grouping_250":12, "grouping_100":12, "integer_rand_2000":312, "integer_seq_2000":12, "integer_rand_2":null, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":13, "grouping_500":13, "grouping_250":13, "grouping_100":13, "integer_rand_2000":338, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":14, "grouping_500":14, "grouping_250":14, "grouping_100":14, "integer_rand_2000":364, "integer_seq_2000":14, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":4, "string_rand_26_a":0, "string_rand_26_b":null, "string_rand_26_c":0}
+{"grouping_1000":15, "grouping_500":15, "grouping_250":15, "grouping_100":15, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":null, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":16, "grouping_500":16, "grouping_250":16, "grouping_100":16, "integer_rand_2000":416, "integer_seq_2000":16, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_20":16, "string_rand_26_c":null}
+{"grouping_1000":17, "grouping_500":17, "grouping_250":17, "grouping_100":17, "integer_rand_2000":442, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":0, "string_rand_26_b":0, "string_rand_26_c":0}
+{"grouping_1000":18, "grouping_500":18, "grouping_250":18, "grouping_100":18, "integer_rand_2000":468, "integer_rand_2":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":0, "string_rand_26_b":null, "string_rand_26_c":0}
+{"grouping_1000":19, "grouping_500":19, "grouping_250":19, "grouping_100":19, "integer_rand_2000":494, "integer_seq_2000":19, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":0, "string_rand_26_c":0}
+{"grouping_1000":20, "grouping_500":20, "grouping_250":20, "grouping_100":20, "integer_rand_2000":403, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":21, "grouping_500":21, "grouping_250":21, "grouping_100":21, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":null}
+{"grouping_1000":22, "grouping_500":22, "grouping_250":22, "grouping_100":22, "integer_rand_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_a":null, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":23, "grouping_500":23, "grouping_250":23, "grouping_100":23, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":24, "grouping_500":24, "grouping_250":24, "grouping_100":24, "integer_rand_2000":80, "integer_seq_2000":24, "integer_rand_2":null, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":25, "grouping_500":25, "grouping_250":25, "grouping_100":25, "integer_rand_2000":485, "integer_seq_2000":25, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":5, "string_rand_26_a":null, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":26, "grouping_500":26, "grouping_250":26, "grouping_100":26, "integer_rand_2000":423, "integer_seq_2000":26, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":null}
+{"grouping_1000":27, "grouping_500":27, "grouping_250":27, "grouping_100":27, "integer_rand_2000":null, "integer_seq_2000":27, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":10, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":28, "grouping_500":28, "grouping_250":28, "grouping_100":28, "integer_rand_2000":null, "integer_seq_2000":28, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":29, "grouping_500":29, "grouping_250":29, "grouping_100":29, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":17, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":30, "grouping_500":30, "grouping_250":30, "grouping_100":30, "integer_rand_2000":null, "integer_seq_2000":30, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_20":null, "string_rand_26_b":22}
+{"grouping_1000":31, "grouping_500":31, "grouping_250":31, "grouping_100":31, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":11, "string_rand_26_b":11, "string_rand_26_c":null}
+{"grouping_1000":32, "grouping_500":32, "grouping_250":32, "grouping_100":32, "integer_seq_2000":32, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":33, "grouping_500":33, "grouping_250":33, "grouping_100":33, "integer_rand_2000":110, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":null, "string_rand_26_c":6}
+{"grouping_1000":34, "grouping_500":34, "grouping_250":34, "grouping_100":34, "integer_rand_2000":null, "integer_seq_2000":34, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":22, "string_rand_26_c":22}
+{"grouping_1000":35, "grouping_500":35, "grouping_250":35, "grouping_100":35, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":36, "grouping_500":36, "grouping_250":36, "grouping_100":36, "integer_rand_2000":null, "integer_seq_2000":36, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":16, "string_rand_26_c":null}
+{"grouping_1000":37, "grouping_500":37, "grouping_250":37, "grouping_100":37, "integer_rand_2000":299, "integer_seq_2000":37, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":null}
+{"grouping_1000":38, "grouping_500":38, "grouping_250":38, "grouping_100":38, "integer_rand_2000":null, "integer_seq_2000":38, "integer_rand_2":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":39, "grouping_500":39, "grouping_250":39, "grouping_100":39, "integer_rand_2000":5, "integer_seq_2000":39, "integer_rand_2":1, "integer_rand_4":1, "string_rand_26_a":5, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":40, "grouping_500":40, "grouping_250":40, "grouping_100":40, "integer_rand_2000":31, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_20":11, "string_rand_26_a":null, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":41, "grouping_500":41, "grouping_250":41, "grouping_100":41, "integer_rand_2000":57, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":null, "string_rand_26_b":5, "string_rand_26_c":5}
+{"grouping_1000":42, "grouping_500":42, "grouping_250":42, "grouping_100":42, "integer_rand_2000":83, "integer_seq_2000":42, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":5, "string_rand_26_c":5}
+{"grouping_1000":43, "grouping_500":43, "grouping_250":43, "grouping_100":43, "integer_rand_2000":109, "integer_seq_2000":43, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":9, "string_rand_26_a":5, "string_rand_26_c":5}
+{"grouping_1000":44, "grouping_500":44, "grouping_250":44, "grouping_100":44, "integer_rand_2000":135, "integer_seq_2000":44, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_20":null, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":5}
+{"grouping_1000":45, "grouping_500":45, "grouping_250":45, "grouping_100":45, "integer_rand_2000":null, "integer_seq_2000":45, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":46, "grouping_500":46, "grouping_250":46, "grouping_100":46, "integer_rand_2000":187, "integer_seq_2000":46, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":47, "grouping_500":47, "grouping_250":47, "grouping_100":47, "integer_rand_2000":213, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":5, "string_rand_26_b":null}
+{"grouping_1000":48, "grouping_500":48, "grouping_250":48, "grouping_100":48, "integer_rand_2000":239, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":49, "grouping_500":49, "grouping_250":49, "grouping_100":49, "integer_rand_2000":null, "integer_seq_2000":49, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":5, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":50, "grouping_500":50, "grouping_250":50, "grouping_100":50, "integer_rand_2000":null, "integer_seq_2000":50, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":1, "string_rand_26_a":null, "string_rand_26_b":5, "string_rand_26_c":5}
+{"grouping_1000":51, "grouping_500":51, "grouping_250":51, "grouping_100":51, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":5, "string_rand_26_b":null, "string_rand_26_c":5}
+{"grouping_1000":52, "grouping_500":52, "grouping_250":52, "grouping_100":52, "integer_seq_2000":52, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":53, "grouping_500":53, "grouping_250":53, "grouping_100":53, "integer_seq_2000":53, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":5, "string_rand_26_b":null, "string_rand_26_c":5}
+{"grouping_1000":54, "grouping_500":54, "grouping_250":54, "grouping_100":54, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":5, "string_rand_26_b":null, "string_rand_26_c":5}
+{"grouping_1000":55, "grouping_500":55, "grouping_250":55, "grouping_100":55, "integer_rand_2000":null, "integer_seq_2000":55, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":1, "string_rand_26_b":null, "string_rand_26_c":5}
+{"grouping_1000":56, "grouping_500":56, "grouping_250":56, "grouping_100":56, "integer_rand_2000":447, "integer_seq_2000":56, "integer_rand_4":3, "integer_rand_20":7, "string_rand_26_a":5, "string_rand_26_b":null, "string_rand_26_c":5}
+{"grouping_1000":57, "grouping_500":57, "grouping_250":57, "grouping_100":57, "integer_rand_2000":473, "integer_seq_2000":57, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":5, "string_rand_26_b":5, "string_rand_26_c":null}
+{"grouping_1000":58, "grouping_500":58, "grouping_250":58, "grouping_100":58, "integer_rand_2000":499, "integer_seq_2000":58, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":null, "string_rand_26_c":5}
+{"grouping_1000":59, "grouping_500":59, "grouping_250":59, "grouping_100":59, "integer_rand_2000":95, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_20":15, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":60, "grouping_500":60, "grouping_250":60, "grouping_100":60, "integer_rand_2000":200, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_b":18, "string_rand_26_c":null}
+{"grouping_1000":61, "grouping_500":61, "grouping_250":61, "grouping_100":61, "integer_rand_2000":245, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":5, "string_rand_26_a":11, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":62, "grouping_500":62, "grouping_250":62, "grouping_100":62, "integer_rand_2000":339, "integer_seq_2000":62, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":1}
+{"grouping_1000":63, "grouping_500":63, "grouping_250":63, "grouping_100":63, "integer_rand_2000":null, "integer_seq_2000":63, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":64, "grouping_500":64, "grouping_250":64, "grouping_100":64, "integer_rand_2000":439, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":65, "grouping_500":65, "grouping_250":65, "grouping_100":65, "integer_rand_2000":252, "integer_seq_2000":65, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":2, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":66, "grouping_500":66, "grouping_250":66, "grouping_100":66, "integer_rand_2000":220, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":67, "grouping_500":67, "grouping_250":67, "grouping_100":67, "integer_rand_2000":89, "integer_seq_2000":67, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":68, "grouping_500":68, "grouping_250":68, "grouping_100":68, "integer_rand_2000":null, "integer_seq_2000":68, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":69, "grouping_500":69, "grouping_250":69, "grouping_100":69, "integer_rand_2000":230, "integer_seq_2000":69, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":70, "grouping_500":70, "grouping_250":70, "grouping_100":70, "integer_rand_2000":349, "integer_seq_2000":70, "integer_rand_4":1, "integer_rand_10":9, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":71, "grouping_500":71, "grouping_250":71, "grouping_100":71, "integer_seq_2000":71, "integer_rand_4":3, "integer_rand_20":19, "string_rand_26_a":null, "string_rand_26_b":11, "string_rand_26_c":null}
+{"grouping_1000":72, "grouping_500":72, "grouping_250":72, "grouping_100":72, "integer_rand_2000":240, "integer_seq_2000":72, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_b":6, "string_rand_26_c":6}
+{"grouping_1000":73, "grouping_500":73, "grouping_250":73, "grouping_100":73, "integer_rand_2000":12, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":12, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":74, "grouping_500":74, "grouping_250":74, "grouping_100":74, "integer_rand_2000":23, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":75, "grouping_500":75, "grouping_250":75, "grouping_100":75, "integer_rand_2000":null, "integer_seq_2000":75, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":76, "grouping_500":76, "grouping_250":76, "grouping_100":76, "integer_rand_2000":396, "integer_seq_2000":76, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":77, "grouping_500":77, "grouping_250":77, "grouping_100":77, "integer_seq_2000":77, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":23}
+{"grouping_1000":78, "grouping_500":78, "grouping_250":78, "grouping_100":78, "integer_rand_2000":null, "integer_seq_2000":78, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":79, "grouping_500":79, "grouping_250":79, "grouping_100":79, "integer_rand_2000":36, "integer_seq_2000":79, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":10, "string_rand_26_c":10}
+{"grouping_1000":80, "grouping_500":80, "grouping_250":80, "grouping_100":80, "integer_rand_2000":62, "integer_seq_2000":80, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":81, "grouping_500":81, "grouping_250":81, "grouping_100":81, "integer_rand_2000":null, "integer_seq_2000":81, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":null}
+{"grouping_1000":82, "grouping_500":82, "grouping_250":82, "grouping_100":82, "integer_rand_2000":114, "integer_seq_2000":82, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":10, "string_rand_26_b":null, "string_rand_26_c":10}
+{"grouping_1000":83, "grouping_500":83, "grouping_250":83, "grouping_100":83, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":10}
+{"grouping_1000":84, "grouping_500":84, "grouping_250":84, "grouping_100":84, "integer_rand_2000":null, "integer_seq_2000":84, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":85, "grouping_500":85, "grouping_250":85, "grouping_100":85, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":null, "string_rand_26_b":10}
+{"grouping_1000":86, "grouping_500":86, "grouping_250":86, "grouping_100":86, "integer_rand_2000":218, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":87, "grouping_500":87, "grouping_250":87, "grouping_100":87, "integer_rand_2000":null, "integer_seq_2000":87, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":88, "grouping_500":88, "grouping_250":88, "grouping_100":88, "integer_rand_2000":270, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":10, "string_rand_26_a":null, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":89, "grouping_500":89, "grouping_250":89, "grouping_100":89, "integer_rand_2000":296, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":10}
+{"grouping_1000":90, "grouping_500":90, "grouping_250":90, "grouping_100":90, "integer_rand_2000":null, "integer_seq_2000":90, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "string_rand_26_a":10, "string_rand_26_b":10}
+{"grouping_1000":91, "grouping_500":91, "grouping_250":91, "grouping_100":91, "integer_rand_2000":348, "integer_seq_2000":91, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":10, "string_rand_26_b":null, "string_rand_26_c":10}
+{"grouping_1000":92, "grouping_500":92, "grouping_250":92, "grouping_100":92, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":14, "string_rand_26_a":null, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":93, "grouping_500":93, "grouping_250":93, "grouping_100":93, "integer_seq_2000":93, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_20":0, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":94, "grouping_500":94, "grouping_250":94, "grouping_100":94, "integer_rand_2000":426, "integer_seq_2000":94, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_b":10}
+{"grouping_1000":95, "grouping_500":95, "grouping_250":95, "grouping_100":95, "integer_rand_2000":452, "integer_seq_2000":95, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":96, "grouping_500":96, "grouping_250":96, "grouping_100":96, "integer_rand_2000":478, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":10, "string_rand_26_b":10, "string_rand_26_c":10}
+{"grouping_1000":97, "grouping_500":97, "grouping_250":97, "grouping_100":97, "integer_rand_2000":null, "integer_seq_2000":97, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":7}
+{"grouping_1000":98, "grouping_500":98, "grouping_250":98, "grouping_100":98, "integer_rand_2000":85, "integer_seq_2000":98, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_20":5, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":7}
+{"grouping_1000":99, "grouping_500":99, "grouping_250":99, "grouping_100":99, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_10":null, "integer_rand_20":10, "string_rand_26_b":18, "string_rand_26_c":null}
+{"grouping_1000":100, "grouping_500":100, "grouping_250":100, "grouping_100":0, "integer_rand_2000":303, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":101, "grouping_500":101, "grouping_250":101, "grouping_100":1, "integer_rand_2000":345, "integer_seq_2000":null, "integer_rand_4":1, "integer_rand_20":5, "string_rand_26_a":null, "string_rand_26_b":7, "string_rand_26_c":null}
+{"grouping_1000":102, "grouping_500":102, "grouping_250":102, "grouping_100":2, "integer_rand_2000":340, "integer_seq_2000":102, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":2, "string_rand_26_b":null, "string_rand_26_c":2}
+{"grouping_1000":103, "grouping_500":103, "grouping_250":103, "grouping_100":3, "integer_rand_2000":7, "integer_seq_2000":103, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_b":7}
+{"grouping_1000":104, "grouping_500":104, "grouping_250":104, "grouping_100":4, "integer_rand_2000":335, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":105, "grouping_500":105, "grouping_250":105, "grouping_100":5, "integer_rand_2000":350, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":null, "string_rand_26_b":12}
+{"grouping_1000":106, "grouping_500":106, "grouping_250":106, "grouping_100":6, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":17, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":107, "grouping_500":107, "grouping_250":107, "grouping_100":7, "integer_rand_2000":292, "integer_seq_2000":107, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":12, "string_rand_26_a":6, "string_rand_26_b":null, "string_rand_26_c":6}
+{"grouping_1000":108, "grouping_500":108, "grouping_250":108, "grouping_100":8, "integer_rand_2000":360, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":22, "string_rand_26_c":22}
+{"grouping_1000":109, "grouping_500":109, "grouping_250":109, "grouping_100":9, "integer_seq_2000":109, "integer_rand_2":null, "integer_rand_20":7, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":null}
+{"grouping_1000":110, "grouping_500":110, "grouping_250":110, "grouping_100":10, "integer_rand_2000":116, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":12, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":111, "grouping_500":111, "grouping_250":111, "grouping_100":11, "integer_seq_2000":111, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":6, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":112, "grouping_500":112, "grouping_250":112, "grouping_100":12, "integer_rand_2000":37, "integer_seq_2000":112, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":11, "string_rand_26_b":11, "string_rand_26_c":null}
+{"grouping_1000":113, "grouping_500":113, "grouping_250":113, "grouping_100":13, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":12, "string_rand_26_c":12}
+{"grouping_1000":114, "grouping_500":114, "grouping_250":114, "grouping_100":14, "integer_rand_2000":null, "integer_seq_2000":114, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":16, "string_rand_26_c":16}
+{"grouping_1000":115, "grouping_500":115, "grouping_250":115, "grouping_100":15, "integer_rand_2000":47, "integer_seq_2000":115, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":21, "string_rand_26_b":21, "string_rand_26_c":null}
+{"grouping_1000":116, "grouping_500":116, "grouping_250":116, "grouping_100":16, "integer_rand_2000":392, "integer_seq_2000":116, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":117, "grouping_500":117, "grouping_250":117, "grouping_100":17, "integer_rand_2000":15, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":15, "string_rand_26_b":15, "string_rand_26_c":15}
+{"grouping_1000":118, "grouping_500":118, "grouping_250":118, "grouping_100":18, "integer_rand_2000":41, "integer_seq_2000":118, "integer_rand_2":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":15, "string_rand_26_b":15}
+{"grouping_1000":119, "grouping_500":119, "grouping_250":119, "grouping_100":19, "integer_rand_2000":67, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":7, "string_rand_26_a":15, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":120, "grouping_500":120, "grouping_250":120, "grouping_100":20, "integer_rand_2000":93, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":15, "string_rand_26_b":15, "string_rand_26_c":15}
+{"grouping_1000":121, "grouping_500":121, "grouping_250":121, "grouping_100":21, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_a":15, "string_rand_26_b":15, "string_rand_26_c":15}
+{"grouping_1000":122, "grouping_500":122, "grouping_250":122, "grouping_100":22, "integer_rand_2000":145, "integer_seq_2000":122, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":5, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":15}
+{"grouping_1000":123, "grouping_500":123, "grouping_250":123, "grouping_100":23, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_20":11, "string_rand_26_a":null, "string_rand_26_b":15}
+{"grouping_1000":124, "grouping_500":124, "grouping_250":124, "grouping_100":24, "integer_rand_2000":197, "integer_seq_2000":124, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":125, "grouping_500":125, "grouping_250":125, "grouping_100":25, "integer_rand_2000":223, "integer_seq_2000":125, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "string_rand_26_a":15, "string_rand_26_b":15, "string_rand_26_c":15}
+{"grouping_1000":126, "grouping_500":126, "grouping_250":126, "grouping_100":26, "integer_rand_2000":null, "integer_seq_2000":126, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":15, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":127, "grouping_500":127, "grouping_250":127, "grouping_100":27, "integer_rand_2000":275, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_b":null, "string_rand_26_c":15}
+{"grouping_1000":128, "grouping_500":128, "grouping_250":128, "grouping_100":28, "integer_rand_2000":301, "integer_seq_2000":128, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":15, "string_rand_26_b":null}
+{"grouping_1000":129, "grouping_500":129, "grouping_250":129, "grouping_100":29, "integer_rand_2000":327, "integer_seq_2000":129, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":7, "string_rand_26_a":15, "string_rand_26_b":null, "string_rand_26_c":15}
+{"grouping_1000":130, "grouping_500":130, "grouping_250":130, "grouping_100":30, "integer_rand_2000":353, "integer_seq_2000":130, "integer_rand_2":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_b":15, "string_rand_26_c":null}
+{"grouping_1000":131, "grouping_500":131, "grouping_250":131, "grouping_100":31, "integer_rand_2000":379, "integer_seq_2000":131, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_20":null, "string_rand_26_a":15, "string_rand_26_b":15, "string_rand_26_c":null}
+{"grouping_1000":132, "grouping_500":132, "grouping_250":132, "grouping_100":32, "integer_rand_2000":405, "integer_seq_2000":132, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":133, "grouping_500":133, "grouping_250":133, "grouping_100":33, "integer_rand_2000":431, "integer_seq_2000":133, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":11, "string_rand_26_a":15, "string_rand_26_b":null, "string_rand_26_c":15}
+{"grouping_1000":134, "grouping_500":134, "grouping_250":134, "grouping_100":34, "integer_rand_2000":null, "integer_seq_2000":134, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":17, "string_rand_26_a":15, "string_rand_26_c":15}
+{"grouping_1000":135, "grouping_500":135, "grouping_250":135, "grouping_100":35, "integer_rand_2000":483, "integer_seq_2000":135, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":15, "string_rand_26_b":null, "string_rand_26_c":15}
+{"grouping_1000":136, "grouping_500":136, "grouping_250":136, "grouping_100":36, "integer_rand_2000":117, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":13}
+{"grouping_1000":137, "grouping_500":137, "grouping_250":137, "grouping_100":37, "integer_rand_2000":438, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_20":18, "string_rand_26_a":null, "string_rand_26_b":22}
+{"grouping_1000":138, "grouping_500":138, "grouping_250":138, "grouping_100":38, "integer_rand_2000":460, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":139, "grouping_500":139, "grouping_250":139, "grouping_100":39, "integer_seq_2000":139, "integer_rand_2":null, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":140, "grouping_500":140, "grouping_250":140, "grouping_100":40, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":2, "string_rand_26_c":null}
+{"grouping_1000":141, "grouping_500":141, "grouping_250":141, "grouping_100":41, "integer_rand_2000":null, "integer_seq_2000":141, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":null}
+{"grouping_1000":142, "grouping_500":142, "grouping_250":142, "grouping_100":42, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":7, "string_rand_26_c":7}
+{"grouping_1000":143, "grouping_500":143, "grouping_250":143, "grouping_100":43, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":2, "string_rand_26_c":null}
+{"grouping_1000":144, "grouping_500":144, "grouping_250":144, "grouping_100":44, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":12, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":145, "grouping_500":145, "grouping_250":145, "grouping_100":45, "integer_rand_2000":147, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":146, "grouping_500":146, "grouping_250":146, "grouping_100":46, "integer_rand_2000":null, "integer_seq_2000":146, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":147, "grouping_500":147, "grouping_250":147, "grouping_100":47, "integer_rand_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":null, "string_rand_26_b":22, "string_rand_26_c":null}
+{"grouping_1000":148, "grouping_500":148, "grouping_250":148, "grouping_100":48, "integer_rand_2000":157, "integer_seq_2000":148, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_b":1}
+{"grouping_1000":149, "grouping_500":149, "grouping_250":149, "grouping_100":49, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_10":null, "integer_rand_20":9, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":150, "grouping_500":150, "grouping_250":150, "grouping_100":50, "integer_rand_2000":null, "integer_seq_2000":150, "integer_rand_2":0, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":null}
+{"grouping_1000":151, "grouping_500":151, "grouping_250":151, "grouping_100":51, "integer_rand_2000":167, "integer_seq_2000":151, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":11, "string_rand_26_b":null}
+{"grouping_1000":152, "grouping_500":152, "grouping_250":152, "grouping_100":52, "integer_rand_2000":412, "integer_seq_2000":152, "integer_rand_2":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":153, "grouping_500":153, "grouping_250":153, "grouping_100":53, "integer_rand_2000":null, "integer_seq_2000":153, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":154, "grouping_500":154, "grouping_250":154, "grouping_100":54, "integer_rand_2000":null, "integer_seq_2000":154, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":null, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":155, "grouping_500":155, "grouping_250":155, "grouping_100":55, "integer_rand_2000":489, "integer_seq_2000":155, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "string_rand_26_a":21, "string_rand_26_b":null, "string_rand_26_c":21}
+{"grouping_1000":156, "grouping_500":156, "grouping_250":156, "grouping_100":56, "integer_rand_2000":20, "integer_rand_2":0, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":157, "grouping_500":157, "grouping_250":157, "grouping_100":57, "integer_rand_2000":null, "integer_seq_2000":157, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":158, "grouping_500":158, "grouping_250":158, "grouping_100":58, "integer_rand_2000":72, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":159, "grouping_500":159, "grouping_250":159, "grouping_100":59, "integer_rand_2000":98, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":null, "string_rand_26_b":20}
+{"grouping_1000":160, "grouping_500":160, "grouping_250":160, "grouping_100":60, "integer_rand_2000":null, "integer_seq_2000":160, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_20":4, "string_rand_26_a":20, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":161, "grouping_500":161, "grouping_250":161, "grouping_100":61, "integer_rand_2000":150, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":162, "grouping_500":162, "grouping_250":162, "grouping_100":62, "integer_rand_2000":176, "integer_seq_2000":162, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":20, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":163, "grouping_500":163, "grouping_250":163, "grouping_100":63, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":2, "string_rand_26_a":20, "string_rand_26_b":20, "string_rand_26_c":null}
+{"grouping_1000":164, "grouping_500":164, "grouping_250":164, "grouping_100":64, "integer_rand_2000":228, "integer_seq_2000":164, "integer_rand_2":0, "integer_rand_10":null, "integer_rand_20":8, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":165, "grouping_500":165, "grouping_250":165, "grouping_100":65, "integer_rand_2000":254, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":14, "string_rand_26_a":20, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":166, "grouping_500":166, "grouping_250":166, "grouping_100":66, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":167, "grouping_500":167, "grouping_250":167, "grouping_100":67, "integer_rand_2000":306, "integer_seq_2000":167, "integer_rand_2":null, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_a":20, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":168, "grouping_500":168, "grouping_250":168, "grouping_100":68, "integer_rand_2000":332, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":20, "string_rand_26_b":null, "string_rand_26_c":20}
+{"grouping_1000":169, "grouping_500":169, "grouping_250":169, "grouping_100":69, "integer_seq_2000":169, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":20, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":170, "grouping_500":170, "grouping_250":170, "grouping_100":70, "integer_rand_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":171, "grouping_500":171, "grouping_250":171, "grouping_100":71, "integer_rand_2000":410, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":20, "string_rand_26_c":20}
+{"grouping_1000":172, "grouping_500":172, "grouping_250":172, "grouping_100":72, "integer_rand_2000":436, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":173, "grouping_500":173, "grouping_250":173, "grouping_100":73, "integer_rand_2000":462, "integer_seq_2000":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":2, "string_rand_26_a":20, "string_rand_26_b":20, "string_rand_26_c":20}
+{"grouping_1000":174, "grouping_500":174, "grouping_250":174, "grouping_100":74, "integer_rand_2000":null, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":20, "string_rand_26_b":20, "string_rand_26_c":null}
+{"grouping_1000":175, "grouping_500":175, "grouping_250":175, "grouping_100":75, "integer_rand_2000":null, "integer_seq_2000":175, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":176, "grouping_500":176, "grouping_250":176, "grouping_100":76, "integer_rand_2000":386, "integer_seq_2000":176, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":22, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":177, "grouping_500":177, "grouping_250":177, "grouping_100":77, "integer_seq_2000":177, "integer_rand_2":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":178, "grouping_500":178, "grouping_250":178, "grouping_100":78, "integer_rand_2000":257, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":23}
+{"grouping_1000":179, "grouping_500":179, "grouping_250":179, "grouping_100":79, "integer_rand_2000":42, "integer_seq_2000":179, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":null}
+{"grouping_1000":180, "grouping_500":180, "grouping_250":180, "grouping_100":80, "integer_rand_2000":465, "integer_seq_2000":180, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":181, "grouping_500":181, "grouping_250":181, "grouping_100":81, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":7, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":7}
+{"grouping_1000":182, "grouping_500":182, "grouping_250":182, "grouping_100":82, "integer_rand_2000":302, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":183, "grouping_500":183, "grouping_250":183, "grouping_100":83, "integer_rand_2000":432, "integer_seq_2000":183, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":null}
+{"grouping_1000":184, "grouping_500":184, "grouping_250":184, "grouping_100":84, "integer_rand_2000":null, "integer_seq_2000":184, "integer_rand_2":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":17, "string_rand_26_c":null}
+{"grouping_1000":185, "grouping_500":185, "grouping_250":185, "grouping_100":85, "integer_rand_2000":486, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":18, "string_rand_26_c":null}
+{"grouping_1000":186, "grouping_500":186, "grouping_250":186, "grouping_100":86, "integer_rand_2000":null, "integer_seq_2000":186, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":187, "grouping_500":187, "grouping_250":187, "grouping_100":87, "integer_seq_2000":187, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_20":null, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":188, "grouping_500":188, "grouping_250":188, "grouping_100":88, "integer_rand_2000":183, "integer_seq_2000":188, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":1, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":189, "grouping_500":189, "grouping_250":189, "grouping_100":89, "integer_rand_2000":null, "integer_seq_2000":189, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":190, "grouping_500":190, "grouping_250":190, "grouping_100":90, "integer_rand_2000":297, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":17, "string_rand_26_a":11, "string_rand_26_b":11, "string_rand_26_c":11}
+{"grouping_1000":191, "grouping_500":191, "grouping_250":191, "grouping_100":91, "integer_rand_2000":73, "integer_seq_2000":191, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":21, "string_rand_26_c":21}
+{"grouping_1000":192, "grouping_500":192, "grouping_250":192, "grouping_100":92, "integer_rand_2000":496, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":null, "string_rand_26_c":2}
+{"grouping_1000":193, "grouping_500":193, "grouping_250":193, "grouping_100":93, "integer_rand_2000":307, "integer_seq_2000":193, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":7, "string_rand_26_a":21, "string_rand_26_c":null}
+{"grouping_1000":194, "grouping_500":194, "grouping_250":194, "grouping_100":94, "integer_seq_2000":194, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":195, "grouping_500":195, "grouping_250":195, "grouping_100":95, "integer_rand_2000":25, "integer_seq_2000":195, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":196, "grouping_500":196, "grouping_250":196, "grouping_100":96, "integer_seq_2000":196, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "string_rand_26_a":null, "string_rand_26_b":25}
+{"grouping_1000":197, "grouping_500":197, "grouping_250":197, "grouping_100":97, "integer_rand_2000":77, "integer_seq_2000":197, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":198, "grouping_500":198, "grouping_250":198, "grouping_100":98, "integer_rand_2000":null, "integer_seq_2000":198, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":3, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":199, "grouping_500":199, "grouping_250":199, "grouping_100":99, "integer_rand_2000":129, "integer_seq_2000":null, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":200, "grouping_500":200, "grouping_250":200, "grouping_100":0, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":201, "grouping_500":201, "grouping_250":201, "grouping_100":1, "integer_rand_2000":null, "integer_seq_2000":201, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":202, "grouping_500":202, "grouping_250":202, "grouping_100":2, "integer_rand_2000":null, "integer_seq_2000":202, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":203, "grouping_500":203, "grouping_250":203, "grouping_100":3, "integer_rand_2000":233, "integer_seq_2000":203, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":null}
+{"grouping_1000":204, "grouping_500":204, "grouping_250":204, "grouping_100":4, "integer_rand_2000":null, "integer_seq_2000":204, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":205, "grouping_500":205, "grouping_250":205, "grouping_100":5, "integer_rand_2000":285, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":5, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":206, "grouping_500":206, "grouping_250":206, "grouping_100":6, "integer_rand_2000":311, "integer_seq_2000":null, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":207, "grouping_500":207, "grouping_250":207, "grouping_100":7, "integer_rand_2000":null, "integer_seq_2000":207, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":null, "string_rand_26_b":25, "string_rand_26_c":null}
+{"grouping_1000":208, "grouping_500":208, "grouping_250":208, "grouping_100":8, "integer_rand_2000":363, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":25, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":209, "grouping_500":209, "grouping_250":209, "grouping_100":9, "integer_rand_2000":389, "integer_seq_2000":209, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":210, "grouping_500":210, "grouping_250":210, "grouping_100":10, "integer_seq_2000":210, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":211, "grouping_500":211, "grouping_250":211, "grouping_100":11, "integer_rand_2000":441, "integer_seq_2000":211, "integer_rand_2":null, "integer_rand_4":1, "string_rand_26_a":25, "string_rand_26_b":25}
+{"grouping_1000":212, "grouping_500":212, "grouping_250":212, "grouping_100":12, "integer_rand_2000":null, "integer_seq_2000":212, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":213, "grouping_500":213, "grouping_250":213, "grouping_100":13, "integer_rand_2000":null, "integer_seq_2000":213, "integer_rand_2":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":25, "string_rand_26_b":25, "string_rand_26_c":25}
+{"grouping_1000":214, "grouping_500":214, "grouping_250":214, "grouping_100":14, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":13, "string_rand_26_b":null, "string_rand_26_c":13}
+{"grouping_1000":215, "grouping_500":215, "grouping_250":215, "grouping_100":15, "integer_rand_2000":44, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":216, "grouping_500":216, "grouping_250":216, "grouping_100":16, "integer_seq_2000":216, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":217, "grouping_500":217, "grouping_250":217, "grouping_100":17, "integer_rand_2000":null, "integer_seq_2000":217, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":23}
+{"grouping_1000":218, "grouping_500":218, "grouping_250":218, "grouping_100":18, "integer_rand_2000":54, "integer_seq_2000":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":219, "grouping_500":219, "grouping_250":219, "grouping_100":19, "integer_rand_2000":79, "integer_seq_2000":219, "integer_rand_2":1, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_a":1, "string_rand_26_b":null, "string_rand_26_c":1}
+{"grouping_1000":220, "grouping_500":220, "grouping_250":220, "grouping_100":20, "integer_rand_2000":null, "integer_seq_2000":220, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":7, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":221, "grouping_500":221, "grouping_250":221, "grouping_100":21, "integer_rand_2000":64, "integer_seq_2000":221, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":12, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":222, "grouping_500":222, "grouping_250":222, "grouping_100":22, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":17}
+{"grouping_1000":223, "grouping_500":223, "grouping_250":223, "grouping_100":23, "integer_rand_2000":407, "integer_seq_2000":223, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":224, "grouping_500":224, "grouping_250":224, "grouping_100":24, "integer_rand_2000":74, "integer_rand_2":0, "integer_rand_10":null, "string_rand_26_a":22, "string_rand_26_b":22, "string_rand_26_c":22}
+{"grouping_1000":225, "grouping_500":225, "grouping_250":225, "grouping_100":25, "integer_rand_2000":329, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":null, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":226, "grouping_500":226, "grouping_250":226, "grouping_100":26, "integer_rand_2000":417, "integer_seq_2000":226, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":227, "grouping_500":227, "grouping_250":227, "grouping_100":27, "integer_rand_2000":null, "integer_seq_2000":227, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":null, "string_rand_26_b":6, "string_rand_26_c":null}
+{"grouping_1000":228, "grouping_500":228, "grouping_250":228, "grouping_100":28, "integer_rand_2000":179, "integer_seq_2000":228, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":229, "grouping_500":229, "grouping_250":229, "grouping_100":29, "integer_rand_2000":427, "integer_seq_2000":229, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":11, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":230, "grouping_500":230, "grouping_250":230, "grouping_100":30, "integer_rand_2000":null, "integer_seq_2000":230, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":16}
+{"grouping_1000":231, "grouping_500":231, "grouping_250":231, "grouping_100":31, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":232, "grouping_500":232, "grouping_250":232, "grouping_100":32, "integer_rand_2000":437, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":null, "string_rand_26_a":21, "string_rand_26_c":21}
+{"grouping_1000":233, "grouping_500":233, "grouping_250":233, "grouping_100":33, "integer_rand_2000":null, "integer_seq_2000":233, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":234, "grouping_500":234, "grouping_250":234, "grouping_100":34, "integer_rand_2000":30, "integer_seq_2000":234, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":4, "string_rand_26_b":null}
+{"grouping_1000":235, "grouping_500":235, "grouping_250":235, "grouping_100":35, "integer_rand_2000":56, "integer_seq_2000":null, "integer_rand_4":0, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":4}
+{"grouping_1000":236, "grouping_500":236, "grouping_250":236, "grouping_100":36, "integer_rand_2000":82, "integer_seq_2000":236, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":null}
+{"grouping_1000":237, "grouping_500":237, "grouping_250":237, "grouping_100":37, "integer_rand_2000":null, "integer_rand_2":0, "integer_rand_20":8, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":238, "grouping_500":238, "grouping_250":238, "grouping_100":38, "integer_rand_2000":null, "integer_seq_2000":238, "integer_rand_2":0, "integer_rand_4":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":239, "grouping_500":239, "grouping_250":239, "grouping_100":39, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":0, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":240, "grouping_500":240, "grouping_250":240, "grouping_100":40, "integer_rand_2000":186, "integer_seq_2000":240, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":241, "grouping_500":241, "grouping_250":241, "grouping_100":41, "integer_seq_2000":241, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":4, "string_rand_26_b":null}
+{"grouping_1000":242, "grouping_500":242, "grouping_250":242, "grouping_100":42, "integer_rand_2000":238, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":243, "grouping_500":243, "grouping_250":243, "grouping_100":43, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":null, "string_rand_26_c":4}
+{"grouping_1000":244, "grouping_500":244, "grouping_250":244, "grouping_100":44, "integer_rand_2000":null, "integer_seq_2000":244, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":245, "grouping_500":245, "grouping_250":245, "grouping_100":45, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":246, "grouping_500":246, "grouping_250":246, "grouping_100":46, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":4, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":247, "grouping_500":247, "grouping_250":247, "grouping_100":47, "integer_rand_2000":null, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":4}
+{"grouping_1000":248, "grouping_500":248, "grouping_250":248, "grouping_100":48, "integer_rand_2000":394, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":14, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":249, "grouping_500":249, "grouping_250":249, "grouping_100":49, "integer_rand_2000":420, "integer_seq_2000":249, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":250, "grouping_500":250, "grouping_250":0, "grouping_100":50, "integer_rand_2000":null, "integer_seq_2000":250, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":4, "string_rand_26_c":4}
+{"grouping_1000":251, "grouping_500":251, "grouping_250":1, "grouping_100":51, "integer_rand_2000":472, "integer_seq_2000":251, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":4, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":252, "grouping_500":252, "grouping_250":2, "grouping_100":52, "integer_rand_2000":498, "integer_seq_2000":252, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":4}
+{"grouping_1000":253, "grouping_500":253, "grouping_250":3, "grouping_100":53, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":5, "string_rand_26_a":null, "string_rand_26_b":13, "string_rand_26_c":null}
+{"grouping_1000":254, "grouping_500":254, "grouping_250":4, "grouping_100":54, "integer_rand_2000":174, "integer_seq_2000":254, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":18, "string_rand_26_b":18}
+{"grouping_1000":255, "grouping_500":255, "grouping_250":5, "grouping_100":55, "integer_rand_2000":null, "integer_seq_2000":255, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":256, "grouping_500":256, "grouping_250":6, "grouping_100":56, "integer_rand_2000":325, "integer_seq_2000":256, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":257, "grouping_500":257, "grouping_250":7, "grouping_100":57, "integer_rand_2000":184, "integer_seq_2000":257, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":2, "string_rand_26_b":null, "string_rand_26_c":2}
+{"grouping_1000":258, "grouping_500":258, "grouping_250":8, "grouping_100":58, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":6, "string_rand_26_c":null}
+{"grouping_1000":259, "grouping_500":259, "grouping_250":9, "grouping_100":59, "integer_rand_2000":75, "integer_seq_2000":null, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":260, "grouping_500":260, "grouping_250":10, "grouping_100":60, "integer_rand_2000":194, "integer_seq_2000":260, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_c":12}
+{"grouping_1000":261, "grouping_500":261, "grouping_250":11, "grouping_100":61, "integer_rand_2000":422, "integer_seq_2000":261, "integer_rand_2":null, "integer_rand_10":2, "string_rand_26_a":null, "string_rand_26_b":6, "string_rand_26_c":6}
+{"grouping_1000":262, "grouping_500":262, "grouping_250":12, "grouping_100":62, "integer_rand_2000":null, "integer_seq_2000":262, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":22, "string_rand_26_c":22}
+{"grouping_1000":263, "grouping_500":263, "grouping_250":13, "grouping_100":63, "integer_rand_2000":204, "integer_seq_2000":263, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":4, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":264, "grouping_500":264, "grouping_250":14, "grouping_100":64, "integer_rand_2000":null, "integer_seq_2000":264, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":265, "grouping_500":265, "grouping_250":15, "grouping_100":65, "integer_rand_2000":96, "integer_seq_2000":265, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":18, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":266, "grouping_500":266, "grouping_250":16, "grouping_100":66, "integer_rand_2000":214, "integer_seq_2000":266, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":6, "string_rand_26_c":null}
+{"grouping_1000":267, "grouping_500":267, "grouping_250":17, "grouping_100":67, "integer_rand_2000":276, "integer_seq_2000":267, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":268, "grouping_500":268, "grouping_250":18, "grouping_100":68, "integer_rand_2000":356, "integer_seq_2000":268, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_a":18, "string_rand_26_b":null, "string_rand_26_c":18}
+{"grouping_1000":269, "grouping_500":269, "grouping_250":19, "grouping_100":69, "integer_rand_2000":224, "integer_seq_2000":269, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":270, "grouping_500":270, "grouping_250":20, "grouping_100":70, "integer_rand_2000":193, "integer_seq_2000":270, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":271, "grouping_500":271, "grouping_250":21, "grouping_100":71, "integer_rand_2000":246, "integer_seq_2000":271, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":272, "grouping_500":272, "grouping_250":22, "grouping_100":72, "integer_rand_2000":9, "integer_seq_2000":272, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_b":9}
+{"grouping_1000":273, "grouping_500":273, "grouping_250":23, "grouping_100":73, "integer_rand_2000":35, "integer_seq_2000":273, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":9, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":274, "grouping_500":274, "grouping_250":24, "grouping_100":74, "integer_rand_2000":61, "integer_seq_2000":274, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":275, "grouping_500":275, "grouping_250":25, "grouping_100":75, "integer_seq_2000":275, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":7, "string_rand_26_a":9, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":276, "grouping_500":276, "grouping_250":26, "grouping_100":76, "integer_rand_2000":null, "integer_seq_2000":276, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":9, "string_rand_26_b":null, "string_rand_26_c":9}
+{"grouping_1000":277, "grouping_500":277, "grouping_250":27, "grouping_100":77, "integer_rand_2000":139, "integer_seq_2000":277, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_20":19, "string_rand_26_a":9, "string_rand_26_b":9}
+{"grouping_1000":278, "grouping_500":278, "grouping_250":28, "grouping_100":78, "integer_rand_2000":165, "integer_seq_2000":278, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "string_rand_26_a":9, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":279, "grouping_500":279, "grouping_250":29, "grouping_100":79, "integer_rand_2000":191, "integer_seq_2000":279, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_b":null}
+{"grouping_1000":280, "grouping_500":280, "grouping_250":30, "grouping_100":80, "integer_rand_2000":217, "integer_seq_2000":280, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":null, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":281, "grouping_500":281, "grouping_250":31, "grouping_100":81, "integer_rand_2000":243, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "string_rand_26_a":9, "string_rand_26_c":9}
+{"grouping_1000":282, "grouping_500":282, "grouping_250":32, "grouping_100":82, "integer_rand_2000":269, "integer_seq_2000":282, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":null, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":283, "grouping_500":283, "grouping_250":33, "grouping_100":83, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_20":null, "string_rand_26_a":9, "string_rand_26_b":9}
+{"grouping_1000":284, "grouping_500":284, "grouping_250":34, "grouping_100":84, "integer_rand_2000":null, "integer_seq_2000":284, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":9, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":285, "grouping_500":285, "grouping_250":35, "grouping_100":85, "integer_rand_2000":347, "integer_seq_2000":285, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":9, "string_rand_26_b":null}
+{"grouping_1000":286, "grouping_500":286, "grouping_250":36, "grouping_100":86, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":9, "string_rand_26_c":null}
+{"grouping_1000":287, "grouping_500":287, "grouping_250":37, "grouping_100":87, "integer_rand_2000":null, "integer_seq_2000":287, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":9, "string_rand_26_b":9, "string_rand_26_c":9}
+{"grouping_1000":288, "grouping_500":288, "grouping_250":38, "grouping_100":88, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":9, "string_rand_26_b":null, "string_rand_26_c":9}
+{"grouping_1000":289, "grouping_500":289, "grouping_250":39, "grouping_100":89, "integer_rand_2000":451, "integer_seq_2000":289, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":290, "grouping_500":290, "grouping_250":40, "grouping_100":90, "integer_rand_2000":477, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":9, "string_rand_26_b":9, "string_rand_26_c":null}
+{"grouping_1000":291, "grouping_500":291, "grouping_250":41, "grouping_100":91, "integer_rand_2000":13, "integer_seq_2000":291, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":null, "string_rand_26_c":13}
+{"grouping_1000":292, "grouping_500":292, "grouping_250":42, "grouping_100":92, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":293, "grouping_500":293, "grouping_250":43, "grouping_100":93, "integer_rand_2000":304, "integer_seq_2000":293, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":294, "grouping_500":294, "grouping_250":44, "grouping_100":94, "integer_seq_2000":294, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":21, "string_rand_26_b":null, "string_rand_26_c":21}
+{"grouping_1000":295, "grouping_500":295, "grouping_250":45, "grouping_100":95, "integer_rand_2000":475, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":null, "string_rand_26_b":7, "string_rand_26_c":7}
+{"grouping_1000":296, "grouping_500":296, "grouping_250":46, "grouping_100":96, "integer_rand_2000":314, "integer_seq_2000":296, "integer_rand_2":0, "integer_rand_10":null, "integer_rand_20":14, "string_rand_26_a":2, "string_rand_26_b":null, "string_rand_26_c":2}
+{"grouping_1000":297, "grouping_500":297, "grouping_250":47, "grouping_100":97, "integer_rand_2000":null, "integer_seq_2000":297, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":null}
+{"grouping_1000":298, "grouping_500":298, "grouping_250":48, "grouping_100":98, "integer_rand_2000":172, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":299, "grouping_500":299, "grouping_250":49, "grouping_100":99, "integer_rand_2000":324, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":12}
+{"grouping_1000":300, "grouping_500":300, "grouping_250":50, "grouping_100":0, "integer_seq_2000":300, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":21, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":301, "grouping_500":301, "grouping_250":51, "grouping_100":1, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":7, "string_rand_26_b":null, "string_rand_26_c":7}
+{"grouping_1000":302, "grouping_500":302, "grouping_250":52, "grouping_100":2, "integer_rand_2000":334, "integer_seq_2000":302, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":22, "string_rand_26_b":22, "string_rand_26_c":22}
+{"grouping_1000":303, "grouping_500":303, "grouping_250":53, "grouping_100":3, "integer_rand_2000":1, "integer_seq_2000":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":1, "string_rand_26_b":null, "string_rand_26_c":1}
+{"grouping_1000":304, "grouping_500":304, "grouping_250":54, "grouping_100":4, "integer_rand_2000":449, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":7, "string_rand_26_b":null, "string_rand_26_c":7}
+{"grouping_1000":305, "grouping_500":305, "grouping_250":55, "grouping_100":5, "integer_rand_2000":null, "integer_seq_2000":305, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":6}
+{"grouping_1000":306, "grouping_500":306, "grouping_250":56, "grouping_100":6, "integer_rand_2000":null, "integer_seq_2000":306, "integer_rand_2":1, "integer_rand_4":null, "string_rand_26_a":11, "string_rand_26_b":11, "string_rand_26_c":11}
+{"grouping_1000":307, "grouping_500":307, "grouping_250":57, "grouping_100":7, "integer_rand_2000":272, "integer_seq_2000":307, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":12}
+{"grouping_1000":308, "grouping_500":308, "grouping_250":58, "grouping_100":8, "integer_rand_2000":354, "integer_seq_2000":null, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":309, "grouping_500":309, "grouping_250":59, "grouping_100":9, "integer_rand_2000":null, "integer_seq_2000":309, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":310, "grouping_500":310, "grouping_250":60, "grouping_100":10, "integer_rand_2000":203, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null}
+{"grouping_1000":311, "grouping_500":311, "grouping_250":61, "grouping_100":11, "integer_rand_2000":14, "integer_seq_2000":311, "integer_rand_2":0, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":14, "string_rand_26_b":null, "string_rand_26_c":14}
+{"grouping_1000":312, "grouping_500":312, "grouping_250":62, "grouping_100":12, "integer_rand_2000":40, "integer_seq_2000":null, "integer_rand_4":0, "integer_rand_10":0, "string_rand_26_a":null, "string_rand_26_b":14, "string_rand_26_c":null}
+{"grouping_1000":313, "grouping_500":313, "grouping_250":63, "grouping_100":13, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":314, "grouping_500":314, "grouping_250":64, "grouping_100":14, "integer_rand_2000":92, "integer_seq_2000":314, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":null, "string_rand_26_b":14, "string_rand_26_c":null}
+{"grouping_1000":315, "grouping_500":315, "grouping_250":65, "grouping_100":15, "integer_rand_2000":null, "integer_seq_2000":315, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":316, "grouping_500":316, "grouping_250":66, "grouping_100":16, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":14, "string_rand_26_b":null, "string_rand_26_c":14}
+{"grouping_1000":317, "grouping_500":317, "grouping_250":67, "grouping_100":17, "integer_rand_2000":170, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":10, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":318, "grouping_500":318, "grouping_250":68, "grouping_100":18, "integer_rand_2000":null, "integer_seq_2000":318, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":319, "grouping_500":319, "grouping_250":69, "grouping_100":19, "integer_rand_2000":null, "integer_seq_2000":319, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":null}
+{"grouping_1000":320, "grouping_500":320, "grouping_250":70, "grouping_100":20, "integer_rand_2000":248, "integer_seq_2000":320, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":null, "string_rand_26_c":14}
+{"grouping_1000":321, "grouping_500":321, "grouping_250":71, "grouping_100":21, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":322, "grouping_500":322, "grouping_250":72, "grouping_100":22, "integer_rand_2000":300, "integer_seq_2000":322, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_a":14, "string_rand_26_c":14}
+{"grouping_1000":323, "grouping_500":323, "grouping_250":73, "grouping_100":23, "integer_rand_2000":326, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":6, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":324, "grouping_500":324, "grouping_250":74, "grouping_100":24, "integer_rand_2000":352, "integer_seq_2000":324, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":12, "string_rand_26_a":14, "string_rand_26_b":null, "string_rand_26_c":14}
+{"grouping_1000":325, "grouping_500":325, "grouping_250":75, "grouping_100":25, "integer_rand_2000":null, "integer_seq_2000":325, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":18, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":326, "grouping_500":326, "grouping_250":76, "grouping_100":26, "integer_rand_2000":404, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":327, "grouping_500":327, "grouping_250":77, "grouping_100":27, "integer_rand_2000":430, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":14}
+{"grouping_1000":328, "grouping_500":328, "grouping_250":78, "grouping_100":28, "integer_rand_2000":456, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":329, "grouping_500":329, "grouping_250":79, "grouping_100":29, "integer_rand_2000":482, "integer_seq_2000":329, "integer_rand_4":2, "integer_rand_20":null, "string_rand_26_a":14, "string_rand_26_b":14, "string_rand_26_c":14}
+{"grouping_1000":330, "grouping_500":330, "grouping_250":80, "grouping_100":30, "integer_rand_2000":null, "integer_seq_2000":330, "integer_rand_2":1, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":13, "string_rand_26_b":13}
+{"grouping_1000":331, "grouping_500":331, "grouping_250":81, "grouping_100":31, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":18, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":332, "grouping_500":332, "grouping_250":82, "grouping_100":32, "integer_rand_2000":null, "integer_seq_2000":332, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":18, "string_rand_26_c":18}
+{"grouping_1000":333, "grouping_500":333, "grouping_250":83, "grouping_100":33, "integer_rand_2000":101, "integer_seq_2000":333, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":334, "grouping_500":334, "grouping_250":84, "grouping_100":34, "integer_rand_2000":22, "integer_rand_2":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":22, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":335, "grouping_500":335, "grouping_250":85, "grouping_100":35, "integer_rand_2000":444, "integer_seq_2000":335, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":null, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":336, "grouping_500":336, "grouping_250":86, "grouping_100":36, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":7, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":337, "grouping_500":337, "grouping_250":87, "grouping_100":37, "integer_rand_2000":282, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":338, "grouping_500":338, "grouping_250":88, "grouping_100":38, "integer_rand_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":339, "grouping_500":339, "grouping_250":89, "grouping_100":39, "integer_rand_2000":null, "integer_seq_2000":339, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":null}
+{"grouping_1000":340, "grouping_500":340, "grouping_250":90, "grouping_100":40, "integer_rand_2000":null, "integer_seq_2000":340, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_a":21, "string_rand_26_b":21, "string_rand_26_c":21}
+{"grouping_1000":341, "grouping_500":341, "grouping_250":91, "grouping_100":41, "integer_rand_2000":null, "integer_seq_2000":341, "integer_rand_2":null, "integer_rand_10":null, "string_rand_26_a":22, "string_rand_26_b":22, "string_rand_26_c":null}
+{"grouping_1000":342, "grouping_500":342, "grouping_250":92, "grouping_100":42, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":343, "grouping_500":343, "grouping_250":93, "grouping_100":43, "integer_rand_2000":319, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":7}
+{"grouping_1000":344, "grouping_500":344, "grouping_250":94, "grouping_100":44, "integer_rand_2000":474, "integer_seq_2000":344, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":6, "string_rand_26_c":6}
+{"grouping_1000":345, "grouping_500":345, "grouping_250":95, "grouping_100":45, "integer_rand_2000":null, "integer_seq_2000":345, "integer_rand_2":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":11, "string_rand_26_b":11}
+{"grouping_1000":346, "grouping_500":346, "grouping_250":96, "grouping_100":46, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":1}
+{"grouping_1000":347, "grouping_500":347, "grouping_250":97, "grouping_100":47, "integer_rand_2000":484, "integer_seq_2000":347, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":16, "string_rand_26_b":null}
+{"grouping_1000":348, "grouping_500":348, "grouping_250":98, "grouping_100":48, "integer_rand_2000":151, "integer_seq_2000":348, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":11, "string_rand_26_c":21}
+{"grouping_1000":349, "grouping_500":349, "grouping_250":99, "grouping_100":49, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":1, "string_rand_26_c":1}
+{"grouping_1000":350, "grouping_500":350, "grouping_250":100, "grouping_100":50, "integer_seq_2000":350, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":19, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":351, "grouping_500":351, "grouping_250":101, "grouping_100":51, "integer_rand_2000":null, "integer_seq_2000":351, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "string_rand_26_a":19, "string_rand_26_c":19}
+{"grouping_1000":352, "grouping_500":352, "grouping_250":102, "grouping_100":52, "integer_rand_2000":null, "integer_seq_2000":352, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":19, "string_rand_26_b":19}
+{"grouping_1000":353, "grouping_500":353, "grouping_250":103, "grouping_100":53, "integer_seq_2000":353, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":17, "string_rand_26_a":19, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":354, "grouping_500":354, "grouping_250":104, "grouping_100":54, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":null}
+{"grouping_1000":355, "grouping_500":355, "grouping_250":105, "grouping_100":55, "integer_rand_2000":null, "integer_seq_2000":355, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":9, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":356, "grouping_500":356, "grouping_250":106, "grouping_100":56, "integer_rand_2000":null, "integer_seq_2000":356, "integer_rand_4":3, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":357, "grouping_500":357, "grouping_250":107, "grouping_100":57, "integer_rand_2000":201, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":19}
+{"grouping_1000":358, "grouping_500":358, "grouping_250":108, "grouping_100":58, "integer_rand_2000":227, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":359, "grouping_500":359, "grouping_250":109, "grouping_100":59, "integer_rand_2000":253, "integer_seq_2000":359, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":null}
+{"grouping_1000":360, "grouping_500":360, "grouping_250":110, "grouping_100":60, "integer_rand_2000":null, "integer_seq_2000":360, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":361, "grouping_500":361, "grouping_250":111, "grouping_100":61, "integer_rand_2000":305, "integer_seq_2000":361, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":362, "grouping_500":362, "grouping_250":112, "grouping_100":62, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":19, "string_rand_26_b":19, "string_rand_26_c":null}
+{"grouping_1000":363, "grouping_500":363, "grouping_250":113, "grouping_100":63, "integer_seq_2000":363, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":17, "string_rand_26_a":19, "string_rand_26_b":null, "string_rand_26_c":19}
+{"grouping_1000":364, "grouping_500":364, "grouping_250":114, "grouping_100":64, "integer_seq_2000":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":19, "string_rand_26_c":19}
+{"grouping_1000":365, "grouping_500":365, "grouping_250":115, "grouping_100":65, "integer_rand_2000":null, "integer_seq_2000":365, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":9, "string_rand_26_a":19, "string_rand_26_b":null, "string_rand_26_c":19}
+{"grouping_1000":366, "grouping_500":366, "grouping_250":116, "grouping_100":66, "integer_rand_2000":435, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":19, "string_rand_26_b":null, "string_rand_26_c":19}
+{"grouping_1000":367, "grouping_500":367, "grouping_250":117, "grouping_100":67, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":368, "grouping_500":368, "grouping_250":118, "grouping_100":68, "integer_rand_2000":487, "integer_seq_2000":368, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_c":19}
+{"grouping_1000":369, "grouping_500":369, "grouping_250":119, "grouping_100":69, "integer_rand_2000":221, "integer_seq_2000":369, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":13, "string_rand_26_c":null}
+{"grouping_1000":370, "grouping_500":370, "grouping_250":120, "grouping_100":70, "integer_rand_2000":115, "integer_seq_2000":370, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":11, "string_rand_26_b":11}
+{"grouping_1000":371, "grouping_500":371, "grouping_250":121, "grouping_100":71, "integer_rand_2000":null, "integer_seq_2000":371, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":6, "string_rand_26_c":6}
+{"grouping_1000":372, "grouping_500":372, "grouping_250":122, "grouping_100":72, "integer_rand_2000":null, "integer_seq_2000":372, "integer_rand_2":1, "integer_rand_10":1, "string_rand_26_a":23, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":373, "grouping_500":373, "grouping_250":123, "grouping_100":73, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":11, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":374, "grouping_500":374, "grouping_250":124, "grouping_100":74, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":18, "string_rand_26_b":null}
+{"grouping_1000":375, "grouping_500":375, "grouping_250":125, "grouping_100":75, "integer_rand_2000":241, "integer_seq_2000":375, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":7, "string_rand_26_b":null, "string_rand_26_c":7}
+{"grouping_1000":376, "grouping_500":376, "grouping_250":126, "grouping_100":76, "integer_seq_2000":376, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":6, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":377, "grouping_500":377, "grouping_250":127, "grouping_100":77, "integer_rand_2000":49, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":9, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":378, "grouping_500":378, "grouping_250":128, "grouping_100":78, "integer_rand_2000":null, "integer_seq_2000":378, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":379, "grouping_500":379, "grouping_250":129, "grouping_100":79, "integer_rand_2000":63, "integer_seq_2000":379, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":11, "string_rand_26_c":null}
+{"grouping_1000":380, "grouping_500":380, "grouping_250":130, "grouping_100":80, "integer_rand_2000":309, "integer_seq_2000":380, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":381, "grouping_500":381, "grouping_250":131, "grouping_100":81, "integer_rand_2000":261, "integer_seq_2000":381, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_20":null, "string_rand_26_a":1, "string_rand_26_c":1}
+{"grouping_1000":382, "grouping_500":382, "grouping_250":132, "grouping_100":82, "integer_rand_2000":146, "integer_seq_2000":382, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":16, "string_rand_26_b":16}
+{"grouping_1000":383, "grouping_500":383, "grouping_250":133, "grouping_100":83, "integer_rand_2000":null, "integer_seq_2000":383, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":7, "string_rand_26_c":null}
+{"grouping_1000":384, "grouping_500":384, "grouping_250":134, "grouping_100":84, "integer_rand_2000":271, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":null, "string_rand_26_c":11}
+{"grouping_1000":385, "grouping_500":385, "grouping_250":135, "grouping_100":85, "integer_rand_2000":null, "integer_seq_2000":385, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":16}
+{"grouping_1000":386, "grouping_500":386, "grouping_250":136, "grouping_100":86, "integer_rand_2000":365, "integer_seq_2000":386, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_a":1, "string_rand_26_b":null, "string_rand_26_c":1}
+{"grouping_1000":387, "grouping_500":387, "grouping_250":137, "grouping_100":87, "integer_rand_2000":281, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":21, "string_rand_26_b":21, "string_rand_26_c":null}
+{"grouping_1000":388, "grouping_500":388, "grouping_250":138, "grouping_100":88, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":3, "integer_rand_20":3, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":null}
+{"grouping_1000":389, "grouping_500":389, "grouping_250":139, "grouping_100":89, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":390, "grouping_500":390, "grouping_250":140, "grouping_100":90, "integer_rand_2000":50, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":24, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":391, "grouping_500":391, "grouping_250":141, "grouping_100":91, "integer_rand_2000":76, "integer_rand_2":0, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_a":24, "string_rand_26_c":24}
+{"grouping_1000":392, "grouping_500":392, "grouping_250":142, "grouping_100":92, "integer_rand_2000":102, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":24, "string_rand_26_c":null}
+{"grouping_1000":393, "grouping_500":393, "grouping_250":143, "grouping_100":93, "integer_rand_2000":128, "integer_seq_2000":393, "integer_rand_2":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":24, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":394, "grouping_500":394, "grouping_250":144, "grouping_100":94, "integer_rand_2000":154, "integer_seq_2000":394, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":395, "grouping_500":395, "grouping_250":145, "grouping_100":95, "integer_rand_2000":180, "integer_seq_2000":null, "integer_rand_10":0, "integer_rand_20":null, "string_rand_26_b":24, "string_rand_26_c":null}
+{"grouping_1000":396, "grouping_500":396, "grouping_250":146, "grouping_100":96, "integer_rand_2000":206, "integer_seq_2000":396, "integer_rand_2":0, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":24, "string_rand_26_b":24, "string_rand_26_c":null}
+{"grouping_1000":397, "grouping_500":397, "grouping_250":147, "grouping_100":97, "integer_rand_2000":null, "integer_seq_2000":397, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":2, "string_rand_26_a":24, "string_rand_26_c":24}
+{"grouping_1000":398, "grouping_500":398, "grouping_250":148, "grouping_100":98, "integer_rand_2000":null, "integer_seq_2000":398, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":24, "string_rand_26_c":null}
+{"grouping_1000":399, "grouping_500":399, "grouping_250":149, "grouping_100":99, "integer_seq_2000":399, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_20":null, "string_rand_26_a":24, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":400, "grouping_500":400, "grouping_250":150, "grouping_100":0, "integer_rand_2000":null, "integer_seq_2000":400, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":24, "string_rand_26_c":24}
+{"grouping_1000":401, "grouping_500":401, "grouping_250":151, "grouping_100":1, "integer_rand_2000":336, "integer_seq_2000":401, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":24}
+{"grouping_1000":402, "grouping_500":402, "grouping_250":152, "grouping_100":2, "integer_rand_2000":362, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":2, "string_rand_26_a":null, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":403, "grouping_500":403, "grouping_250":153, "grouping_100":3, "integer_seq_2000":403, "integer_rand_2":null, "integer_rand_10":null, "integer_rand_20":8, "string_rand_26_a":24}
+{"grouping_1000":404, "grouping_500":404, "grouping_250":154, "grouping_100":4, "integer_rand_2000":null, "integer_seq_2000":404, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":24, "string_rand_26_b":24}
+{"grouping_1000":405, "grouping_500":405, "grouping_250":155, "grouping_100":5, "integer_rand_2000":440, "integer_seq_2000":405, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":0, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":24}
+{"grouping_1000":406, "grouping_500":406, "grouping_250":156, "grouping_100":6, "integer_rand_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":407, "grouping_500":407, "grouping_250":157, "grouping_100":7, "integer_rand_2000":null, "integer_rand_2":0, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":24, "string_rand_26_b":24, "string_rand_26_c":24}
+{"grouping_1000":408, "grouping_500":408, "grouping_250":158, "grouping_100":8, "integer_rand_2000":351, "integer_seq_2000":408, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":409, "grouping_500":409, "grouping_250":159, "grouping_100":9, "integer_seq_2000":409, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "string_rand_26_a":null, "string_rand_26_b":18, "string_rand_26_c":null}
+{"grouping_1000":410, "grouping_500":410, "grouping_250":160, "grouping_100":10, "integer_rand_2000":105, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":5, "integer_rand_20":5, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":null}
+{"grouping_1000":411, "grouping_500":411, "grouping_250":161, "grouping_100":11, "integer_rand_2000":361, "integer_seq_2000":411, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":1, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":23}
+{"grouping_1000":412, "grouping_500":412, "grouping_250":162, "grouping_100":12, "integer_seq_2000":412, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_b":null, "string_rand_26_c":2}
+{"grouping_1000":413, "grouping_500":413, "grouping_250":163, "grouping_100":13, "integer_rand_2000":142, "integer_seq_2000":413, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":12}
+{"grouping_1000":414, "grouping_500":414, "grouping_250":164, "grouping_100":14, "integer_rand_2000":371, "integer_seq_2000":414, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_20":null, "string_rand_26_a":7, "string_rand_26_b":7, "string_rand_26_c":null}
+{"grouping_1000":415, "grouping_500":415, "grouping_250":165, "grouping_100":15, "integer_rand_2000":38, "integer_seq_2000":415, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":12, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":416, "grouping_500":416, "grouping_250":166, "grouping_100":16, "integer_rand_2000":402, "integer_seq_2000":416, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":417, "grouping_500":417, "grouping_250":167, "grouping_100":17, "integer_rand_2000":381, "integer_seq_2000":417, "integer_rand_2":1, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":17, "string_rand_26_c":null}
+{"grouping_1000":418, "grouping_500":418, "grouping_250":168, "grouping_100":18, "integer_rand_2000":48, "integer_seq_2000":418, "integer_rand_2":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":22, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":419, "grouping_500":419, "grouping_250":169, "grouping_100":19, "integer_rand_2000":null, "integer_seq_2000":419, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":19, "string_rand_26_a":7, "string_rand_26_c":null}
+{"grouping_1000":420, "grouping_500":420, "grouping_250":170, "grouping_100":20, "integer_rand_2000":391, "integer_seq_2000":420, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":421, "grouping_500":421, "grouping_250":171, "grouping_100":21, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":null, "string_rand_26_c":6}
+{"grouping_1000":422, "grouping_500":422, "grouping_250":172, "grouping_100":22, "integer_rand_2000":null, "integer_seq_2000":422, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":8, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":423, "grouping_500":423, "grouping_250":173, "grouping_100":23, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":11}
+{"grouping_1000":424, "grouping_500":424, "grouping_250":174, "grouping_100":24, "integer_rand_2000":null, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":8, "string_rand_26_a":16}
+{"grouping_1000":425, "grouping_500":425, "grouping_250":175, "grouping_100":25, "integer_rand_2000":173, "integer_seq_2000":425, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":13, "string_rand_26_a":17, "string_rand_26_b":17, "string_rand_26_c":17}
+{"grouping_1000":426, "grouping_500":426, "grouping_250":176, "grouping_100":26, "integer_rand_2000":411, "integer_seq_2000":426, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":11, "string_rand_26_b":21, "string_rand_26_c":null}
+{"grouping_1000":427, "grouping_500":427, "grouping_250":177, "grouping_100":27, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":3, "string_rand_26_a":3, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":428, "grouping_500":428, "grouping_250":178, "grouping_100":28, "integer_rand_2000":29, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":3}
+{"grouping_1000":429, "grouping_500":429, "grouping_250":179, "grouping_100":29, "integer_rand_2000":55, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":3, "string_rand_26_b":3, "string_rand_26_c":3}
+{"grouping_1000":430, "grouping_500":430, "grouping_250":180, "grouping_100":30, "integer_rand_2000":81, "integer_seq_2000":430, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":1, "string_rand_26_a":3, "string_rand_26_c":3}
+{"grouping_1000":431, "grouping_500":431, "grouping_250":181, "grouping_100":31, "integer_rand_2000":null, "integer_seq_2000":431, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":3, "string_rand_26_b":3, "string_rand_26_c":3}
+{"grouping_1000":432, "grouping_500":432, "grouping_250":182, "grouping_100":32, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":null, "string_rand_26_b":3}
+{"grouping_1000":433, "grouping_500":433, "grouping_250":183, "grouping_100":33, "integer_rand_2000":159, "integer_seq_2000":null, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":3, "string_rand_26_b":null}
+{"grouping_1000":434, "grouping_500":434, "grouping_250":184, "grouping_100":34, "integer_rand_2000":185, "integer_seq_2000":434, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":null, "integer_rand_20":5, "string_rand_26_a":3, "string_rand_26_b":null, "string_rand_26_c":3}
+{"grouping_1000":435, "grouping_500":435, "grouping_250":185, "grouping_100":35, "integer_rand_2000":211, "integer_seq_2000":435, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":3}
+{"grouping_1000":436, "grouping_500":436, "grouping_250":186, "grouping_100":36, "integer_rand_2000":237, "integer_seq_2000":436, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_20":17, "string_rand_26_a":3, "string_rand_26_b":3, "string_rand_26_c":3}
+{"grouping_1000":437, "grouping_500":437, "grouping_250":187, "grouping_100":37, "integer_rand_2000":263, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":3, "string_rand_26_b":3, "string_rand_26_c":null}
+{"grouping_1000":438, "grouping_500":438, "grouping_250":188, "grouping_100":38, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":null, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":439, "grouping_500":439, "grouping_250":189, "grouping_100":39, "integer_rand_2000":null, "integer_seq_2000":439, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":null, "string_rand_26_b":3, "string_rand_26_c":3}
+{"grouping_1000":440, "grouping_500":440, "grouping_250":190, "grouping_100":40, "integer_rand_2000":null, "integer_seq_2000":440, "integer_rand_2":1, "integer_rand_10":null, "string_rand_26_a":3, "string_rand_26_b":null, "string_rand_26_c":3}
+{"grouping_1000":441, "grouping_500":441, "grouping_250":191, "grouping_100":41, "integer_rand_2000":367, "integer_rand_2":null, "integer_rand_10":7, "integer_rand_20":7, "string_rand_26_a":null, "string_rand_26_b":3, "string_rand_26_c":3}
+{"grouping_1000":442, "grouping_500":442, "grouping_250":192, "grouping_100":42, "integer_rand_2000":null, "integer_seq_2000":442, "integer_rand_2":null, "integer_rand_10":3, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":3, "string_rand_26_c":null}
+{"grouping_1000":443, "grouping_500":443, "grouping_250":193, "grouping_100":43, "integer_rand_2000":419, "integer_seq_2000":443, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_a":3, "string_rand_26_b":null}
+{"grouping_1000":444, "grouping_500":444, "grouping_250":194, "grouping_100":44, "integer_seq_2000":444, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_20":5, "string_rand_26_a":3, "string_rand_26_b":null}
+{"grouping_1000":445, "grouping_500":445, "grouping_250":195, "grouping_100":45, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":3, "string_rand_26_b":3, "string_rand_26_c":null}
+{"grouping_1000":446, "grouping_500":446, "grouping_250":196, "grouping_100":46, "integer_rand_2000":null, "integer_seq_2000":446, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":7, "string_rand_26_a":null, "string_rand_26_c":3}
+{"grouping_1000":447, "grouping_500":447, "grouping_250":197, "grouping_100":47, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_20":1, "string_rand_26_a":null, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":448, "grouping_500":448, "grouping_250":198, "grouping_100":48, "integer_rand_2000":null, "integer_seq_2000":448, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":449, "grouping_500":449, "grouping_250":199, "grouping_100":49, "integer_rand_2000":null, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":5, "integer_rand_20":null, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":null}
+{"grouping_1000":450, "grouping_500":450, "grouping_250":200, "grouping_100":50, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_10":1, "integer_rand_20":null, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":23}
+{"grouping_1000":451, "grouping_500":451, "grouping_250":201, "grouping_100":51, "integer_rand_2000":null, "integer_rand_2":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_b":null}
+{"grouping_1000":452, "grouping_500":452, "grouping_250":202, "grouping_100":52, "integer_rand_2000":495, "integer_seq_2000":452, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":1, "string_rand_26_b":1, "string_rand_26_c":1}
+{"grouping_1000":453, "grouping_500":453, "grouping_250":203, "grouping_100":53, "integer_rand_2000":33, "integer_seq_2000":453, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":null, "string_rand_26_b":7, "string_rand_26_c":null}
+{"grouping_1000":454, "grouping_500":454, "grouping_250":204, "grouping_100":54, "integer_rand_2000":168, "integer_seq_2000":454, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":12, "string_rand_26_b":null, "string_rand_26_c":12}
+{"grouping_1000":455, "grouping_500":455, "grouping_250":205, "grouping_100":55, "integer_rand_2000":459, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":9, "integer_rand_20":null, "string_rand_26_a":17, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":456, "grouping_500":456, "grouping_250":206, "grouping_100":56, "integer_rand_2000":169, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":457, "grouping_500":457, "grouping_250":207, "grouping_100":57, "integer_rand_2000":178, "integer_seq_2000":457, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":22, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":458, "grouping_500":458, "grouping_250":208, "grouping_100":58, "integer_rand_2000":6, "integer_seq_2000":458, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "string_rand_26_a":null, "string_rand_26_b":6, "string_rand_26_c":null}
+{"grouping_1000":459, "grouping_500":459, "grouping_250":209, "grouping_100":59, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":null, "integer_rand_4":1, "integer_rand_10":9, "integer_rand_20":9, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":460, "grouping_500":460, "grouping_250":210, "grouping_100":60, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_4":0, "integer_rand_20":8, "string_rand_26_b":null, "string_rand_26_c":6}
+{"grouping_1000":461, "grouping_500":461, "grouping_250":211, "grouping_100":61, "integer_rand_2000":266, "integer_seq_2000":461, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":6, "string_rand_26_b":6, "string_rand_26_c":null}
+{"grouping_1000":462, "grouping_500":462, "grouping_250":212, "grouping_100":62, "integer_rand_2000":32, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_20":12, "string_rand_26_a":6, "string_rand_26_b":6, "string_rand_26_c":6}
+{"grouping_1000":463, "grouping_500":463, "grouping_250":213, "grouping_100":63, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":16}
+{"grouping_1000":464, "grouping_500":464, "grouping_250":214, "grouping_100":64, "integer_rand_2000":408, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":null, "string_rand_26_a":18, "string_rand_26_c":18}
+{"grouping_1000":465, "grouping_500":465, "grouping_250":215, "grouping_100":65, "integer_rand_2000":458, "integer_seq_2000":465, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":null}
+{"grouping_1000":466, "grouping_500":466, "grouping_250":216, "grouping_100":66, "integer_rand_2000":8, "integer_seq_2000":466, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":467, "grouping_500":467, "grouping_250":217, "grouping_100":67, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":4, "integer_rand_20":null, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":468, "grouping_500":468, "grouping_250":218, "grouping_100":68, "integer_seq_2000":468, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":469, "grouping_500":469, "grouping_250":219, "grouping_100":69, "integer_rand_2000":86, "integer_seq_2000":469, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":6, "integer_rand_20":6, "string_rand_26_a":null, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":470, "grouping_500":470, "grouping_250":220, "grouping_100":70, "integer_rand_2000":112, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_a":8, "string_rand_26_b":8}
+{"grouping_1000":471, "grouping_500":471, "grouping_250":221, "grouping_100":71, "integer_rand_2000":138, "integer_seq_2000":471, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":18, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":472, "grouping_500":472, "grouping_250":222, "grouping_100":72, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_20":null, "string_rand_26_a":8, "string_rand_26_b":null, "string_rand_26_c":8}
+{"grouping_1000":473, "grouping_500":473, "grouping_250":223, "grouping_100":73, "integer_seq_2000":473, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":10, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":474, "grouping_500":474, "grouping_250":224, "grouping_100":74, "integer_rand_2000":216, "integer_seq_2000":474, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":null, "string_rand_26_c":null}
+{"grouping_1000":475, "grouping_500":475, "grouping_250":225, "grouping_100":75, "integer_rand_2000":242, "integer_seq_2000":475, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_10":2, "integer_rand_20":null, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":476, "grouping_500":476, "grouping_250":226, "grouping_100":76, "integer_rand_2000":268, "integer_seq_2000":476, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":null, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":477, "grouping_500":477, "grouping_250":227, "grouping_100":77, "integer_rand_4":2, "integer_rand_10":4, "integer_rand_20":14, "string_rand_26_a":8, "string_rand_26_b":null, "string_rand_26_c":8}
+{"grouping_1000":478, "grouping_500":478, "grouping_250":228, "grouping_100":78, "integer_rand_2000":null, "integer_seq_2000":478, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":0, "string_rand_26_a":null, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":479, "grouping_500":479, "grouping_250":229, "grouping_100":79, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_10":6, "integer_rand_20":null, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":480, "grouping_500":480, "grouping_250":230, "grouping_100":80, "integer_rand_2000":null, "integer_seq_2000":480, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":2, "integer_rand_20":12, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":481, "grouping_500":481, "grouping_250":231, "grouping_100":81, "integer_rand_2000":398, "integer_seq_2000":481, "integer_rand_2":null, "integer_rand_4":null, "integer_rand_20":18, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":482, "grouping_500":482, "grouping_250":232, "grouping_100":82, "integer_rand_2000":424, "integer_seq_2000":482, "integer_rand_2":null, "integer_rand_4":0, "integer_rand_10":4, "integer_rand_20":4, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":483, "grouping_500":483, "grouping_250":233, "grouping_100":83, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":0, "integer_rand_20":null, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":null}
+{"grouping_1000":484, "grouping_500":484, "grouping_250":234, "grouping_100":84, "integer_rand_2000":476, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":16, "string_rand_26_a":8, "string_rand_26_b":8, "string_rand_26_c":8}
+{"grouping_1000":485, "grouping_500":485, "grouping_250":235, "grouping_100":85, "integer_rand_2000":328, "integer_rand_4":0, "integer_rand_10":8, "integer_rand_20":8, "string_rand_26_a":16, "string_rand_26_b":16, "string_rand_26_c":16}
+{"grouping_1000":486, "grouping_500":486, "grouping_250":236, "grouping_100":86, "integer_rand_2000":355, "integer_seq_2000":486, "integer_rand_2":1, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":15, "string_rand_26_a":17, "string_rand_26_b":null, "string_rand_26_c":17}
+{"grouping_1000":487, "grouping_500":487, "grouping_250":237, "grouping_100":87, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":18, "string_rand_26_b":null, "string_rand_26_c":18}
+{"grouping_1000":488, "grouping_500":488, "grouping_250":238, "grouping_100":88, "integer_rand_2000":null, "integer_seq_2000":null, "integer_rand_2":1, "integer_rand_4":1, "integer_rand_10":3, "integer_rand_20":13, "string_rand_26_a":23, "string_rand_26_b":23, "string_rand_26_c":null}
+{"grouping_1000":489, "grouping_500":489, "grouping_250":239, "grouping_100":89, "integer_rand_2000":2, "integer_seq_2000":489, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":null, "integer_rand_20":2, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":490, "grouping_500":490, "grouping_250":240, "grouping_100":90, "integer_rand_2000":null, "integer_seq_2000":490, "integer_rand_2":0, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":2, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":491, "grouping_500":491, "grouping_250":241, "grouping_100":91, "integer_rand_2000":136, "integer_rand_2":0, "integer_rand_10":6, "integer_rand_20":16, "string_rand_26_a":6, "string_rand_26_b":null, "string_rand_26_c":null}
+{"grouping_1000":492, "grouping_500":492, "grouping_250":242, "grouping_100":92, "integer_rand_2000":262, "integer_seq_2000":492, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":2, "integer_rand_20":2, "string_rand_26_a":null, "string_rand_26_b":2, "string_rand_26_c":2}
+{"grouping_1000":493, "grouping_500":493, "grouping_250":243, "grouping_100":93, "integer_rand_2000":298, "integer_seq_2000":493, "integer_rand_2":0, "integer_rand_4":2, "integer_rand_10":8, "integer_rand_20":18, "string_rand_26_a":null, "string_rand_26_b":12, "string_rand_26_c":12}
+{"grouping_1000":494, "grouping_500":494, "grouping_250":244, "grouping_100":94, "integer_rand_2000":99, "integer_seq_2000":494, "integer_rand_4":null, "string_rand_26_a":21, "string_rand_26_b":21, "string_rand_26_c":null}
+{"grouping_1000":495, "grouping_500":495, "grouping_250":245, "grouping_100":95, "integer_rand_2000":455, "integer_seq_2000":495, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":5, "integer_rand_20":15, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
+{"grouping_1000":496, "grouping_500":496, "grouping_250":246, "grouping_100":96, "integer_rand_2000":null, "integer_seq_2000":496, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_b":null, "string_rand_26_c":22}
+{"grouping_1000":497, "grouping_500":497, "grouping_250":247, "grouping_100":97, "integer_seq_2000":497, "integer_rand_2":1, "integer_rand_4":null, "integer_rand_10":null, "integer_rand_20":19, "string_rand_26_a":null, "string_rand_26_b":21, "string_rand_26_c":null}
+{"grouping_1000":498, "grouping_500":498, "grouping_250":248, "grouping_100":98, "integer_rand_2000":152, "integer_seq_2000":498, "integer_rand_2":0, "integer_rand_4":0, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":null, "string_rand_26_b":22, "string_rand_26_c":22}
+{"grouping_1000":499, "grouping_500":499, "grouping_250":249, "grouping_100":99, "integer_rand_2000":null, "integer_seq_2000":499, "integer_rand_2":null, "integer_rand_4":2, "integer_rand_10":8, "string_rand_26_a":6, "string_rand_26_b":null}
+{"grouping_1000":500, "grouping_500":0, "grouping_250":0, "grouping_100":0, "integer_rand_2000":39, "integer_seq_2000":500, "integer_rand_2":null, "integer_rand_4":3, "integer_rand_10":null, "integer_rand_20":null, "string_rand_26_a":13, "string_rand_26_b":13, "string_rand_26_c":13}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayDataset.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayDataset.java
new file mode 100644
index 0000000..d943953
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayDataset.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import static org.apache.asterix.test.array.ArrayElement.TableField;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.ArrayNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.IntNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.ObjectNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.TextNode;
+
+public class ArrayDataset {
+ public static final String[] ADDITIONAL_GROUPS = new String[] { "extra_grouping_5_a", "extra_grouping_5_b" };
+ public static final String[] ADDITIONAL_FIELDS = new String[] { "extra_integer_1_a", "extra_integer_1_b" };
+ public static final String[] VALUES_FOR_ADDITIONAL_GROUPS = new String[] { "1", "2", "3", "4", "5" };
+ public static final String[] VALUES_FOR_ADDITIONAL_FIELDS = new String[] { "1", "2" };
+
+ public static final String[] CONTAINER_OBJECT_NAMES = new String[] { "container_object_1", "container_object_2" };
+ public static final String[] CONTAINED_OBJECT_NAMES = new String[] { "contained_object_1", "contained_object_2" };
+
+ private String fromBaseQuery;
+
+ @Override
+ public String toString() {
+ return fromBaseQuery;
+ }
+
+ public static class Builder {
+ private final JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(false);
+ private final List<ArrayElement> builderElements = new ArrayList<>();
+
+ public void addElement(ArrayElement element) {
+ builderElements.add(element);
+ }
+
+ public ArrayDataset build() {
+ ArrayElement e = builderElements.stream().filter(m -> !m.unnestList.isEmpty()).findFirst().orElseThrow();
+ List<TableField> f = builderElements.stream().filter(m -> m.unnestList.isEmpty())
+ .map(m -> m.projectList.get(0)).collect(Collectors.toUnmodifiableList());
+ int arrayNestingLevel = e.unnestList.size();
+
+ // First, build the innermost array component (i.e. the SELECT clause of the DDL, or lack thereof).
+ StringBuilder sb = new StringBuilder();
+ sb.append("WITH group1 AS (\n");
+ sb.append("\tFROM ").append(BaseWisconsinTable.TABLE_NAME).append(" D\n\t");
+ appendGroupByClause(sb, e.unnestList.size());
+ sb.append("\tGROUP AS G1\n");
+ appendSelectClauseWithGroupTerm(sb, "G1", arrayNestingLevel, e.unnestList.get(arrayNestingLevel - 1),
+ buildStartingSelectValue(e));
+ sb.append(")\n");
+
+ // If we have any nested arrays, additional groups.
+ for (int i = 1; i < e.unnestList.size(); i++) {
+ String joinFieldName = BaseWisconsinTable.GROUPING_FIELDS[arrayNestingLevel - 1].fieldName;
+ sb.append(", group").append(i + 1).append(" AS (\n");
+ sb.append("\tFROM ").append(BaseWisconsinTable.TABLE_NAME).append(" D\n\t");
+ sb.append("JOIN group").append(i).append(" G").append(i).append("\n\tON ");
+ sb.append("D.").append(joinFieldName);
+ sb.append(" = G").append(i).append('.').append(joinFieldName).append("\n\t");
+ appendGroupByClause(sb, arrayNestingLevel - 1);
+ sb.append("\tGROUP AS G").append(i + 1).append('\n');
+ appendSelectClauseWithGroupTerm(sb, "G" + (i + 1), arrayNestingLevel - 1,
+ e.unnestList.get(arrayNestingLevel - 2), String.format("%s_inner.G%d", "G" + (i + 1), i));
+ sb.append(")\n");
+ arrayNestingLevel--;
+ }
+
+ // Add the final SELECT clause.
+ String joinFieldName = BaseWisconsinTable.GROUPING_FIELDS[arrayNestingLevel - 1].fieldName;
+ sb.append("FROM ").append(BaseWisconsinTable.TABLE_NAME).append(" D\n");
+ sb.append("JOIN group").append(e.unnestList.size()).append(" G").append(e.unnestList.size());
+ sb.append("\nON D.").append(joinFieldName).append(" = G");
+ sb.append(e.unnestList.size()).append('.').append(joinFieldName).append("\n");
+ appendSelectClauseWithoutGroupTerm(sb, "G" + e.unnestList.size(), arrayNestingLevel - 1,
+ e.unnestList.get(0), f);
+
+ // Return the new array dataset.
+ ArrayDataset arrayDataset = new ArrayDataset();
+ arrayDataset.fromBaseQuery = sb.toString();
+ return arrayDataset;
+ }
+
+ private void appendGroupByClause(StringBuilder sb, int numGroupFields) {
+ sb.append("GROUP BY D.").append(BaseWisconsinTable.GROUPING_FIELDS[0].fieldName).append(" ");
+ for (int i = 1; i < numGroupFields; i++) {
+ sb.append(", D.").append(BaseWisconsinTable.GROUPING_FIELDS[i].fieldName).append(' ');
+ }
+ sb.append('\n');
+ }
+
+ private void appendSelectClauseWithGroupTerm(StringBuilder sb, String groupAlias, int numGroupFields,
+ TableField groupField, String groupValue) {
+ ObjectNode selectClauseNode = new ObjectNode(jsonNodeFactory);
+
+ // Append the GROUP BY fields.
+ for (int i = 0; i < numGroupFields; i++) {
+ selectClauseNode.put(BaseWisconsinTable.GROUPING_FIELDS[i].fieldName,
+ String.format("$D.%s$", BaseWisconsinTable.GROUPING_FIELDS[i].fieldName));
+ }
+
+ // Append two extra groups alongside the group-to-be-added.
+ List<JsonNode> additionalGroupValues = Stream.of(VALUES_FOR_ADDITIONAL_GROUPS)
+ .map(v -> new IntNode(Integer.parseInt(v))).collect(Collectors.toList());
+ for (String additionalGroup : ADDITIONAL_GROUPS) {
+ selectClauseNode.set(additionalGroup, new ArrayNode(jsonNodeFactory, additionalGroupValues));
+ }
+
+ // Create the group field.
+ String q = String.format("$( FROM %s %<s_inner SELECT VALUE %s )$", groupAlias, groupValue);
+ appendNestedFieldsToObjectNode(groupField, selectClauseNode, new TextNode(q));
+
+ // Serialize our object into a SELECT clause.
+ sb.append("\tSELECT VALUE ").append(buildJSONForQuery(selectClauseNode));
+ }
+
+ private void appendSelectClauseWithoutGroupTerm(StringBuilder sb, String groupAlias, int numGroupFields,
+ TableField groupField, List<TableField> auxiliaryFields) {
+ ObjectNode selectClauseNode = new ObjectNode(jsonNodeFactory);
+
+ // Append the GROUP BY fields.
+ for (int i = 0; i < numGroupFields; i++) {
+ selectClauseNode.put(BaseWisconsinTable.GROUPING_FIELDS[i].fieldName,
+ String.format("$D.%s$", BaseWisconsinTable.GROUPING_FIELDS[i].fieldName));
+ }
+
+ // Append two extra groups alongside the group-to-be-added.
+ List<JsonNode> additionalGroupValues = Stream.of(VALUES_FOR_ADDITIONAL_GROUPS)
+ .map(v -> new IntNode(Integer.parseInt(v))).collect(Collectors.toList());
+ for (String additionalGroup : ADDITIONAL_GROUPS) {
+ selectClauseNode.set(additionalGroup, new ArrayNode(jsonNodeFactory, additionalGroupValues));
+ }
+
+ // Add / create our auxiliary objects.
+ for (TableField field : auxiliaryFields) {
+ String v = buildTableFieldValue("D." + field.getSourceField().fieldName, field);
+ appendNestedFieldsToObjectNode(field, selectClauseNode, new TextNode(String.format("$%s$", v)));
+ }
+
+ // Finally, add our group field. This array should already be formed.
+ String q = String.format("$%s.%s$", groupAlias, groupField.getFullFieldName());
+ appendNestedFieldsToObjectNode(groupField, selectClauseNode, new TextNode(q));
+
+ // Serialize our object into a SELECT clause.
+ sb.append("SELECT VALUE ").append(buildJSONForQuery(selectClauseNode));
+ }
+
+ private String buildStartingSelectValue(ArrayElement element) {
+ StringBuilder sb = new StringBuilder();
+ if (element.projectList.isEmpty()) {
+ TableField workingField = element.unnestList.get(element.unnestList.size() - 1);
+ String fieldName = "G1_inner.D." + workingField.getSourceField().fieldName;
+ sb.append(buildTableFieldValue(fieldName, workingField));
+
+ } else {
+ ObjectNode selectValueNode = new ObjectNode(jsonNodeFactory);
+
+ // Append extra fields within the object item. These values will always be fixed.
+ for (int i = 0; i < ADDITIONAL_FIELDS.length; i++) {
+ int additionalFieldValue = Integer.parseInt(VALUES_FOR_ADDITIONAL_FIELDS[i]);
+ selectValueNode.set(ADDITIONAL_FIELDS[i], new IntNode(additionalFieldValue));
+ }
+
+ // Append the items within our object itself.
+ for (TableField workingField : element.projectList) {
+ String fieldName = "G1_inner.D." + workingField.getSourceField().fieldName;
+ String v = buildTableFieldValue(fieldName, workingField);
+ appendNestedFieldsToObjectNode(workingField, selectValueNode,
+ new TextNode(String.format("$%s$", v)));
+ }
+
+ // Serialize our value node.
+ sb.append(buildJSONForQuery(selectValueNode));
+ }
+
+ return sb.toString();
+ }
+
+ private void appendNestedFieldsToObjectNode(TableField field, ObjectNode objectNode, TextNode endpointValue) {
+ ObjectNode workingObject = objectNode;
+ for (int i = 0; i < field.getFieldName().size(); i++) {
+ String fieldPart = field.getFieldName().get(i);
+ if (i < field.getFieldName().size() - 1) {
+ if (workingObject.get(fieldPart) == null) {
+ ObjectNode objectInsideWorkingObject = new ObjectNode(jsonNodeFactory);
+ workingObject.set(fieldPart, objectInsideWorkingObject);
+ workingObject = objectInsideWorkingObject;
+
+ } else {
+ workingObject = (ObjectNode) workingObject.get(fieldPart);
+ }
+
+ } else {
+ workingObject.set(fieldPart, endpointValue);
+ }
+ }
+ }
+
+ private String buildTableFieldValue(String fieldName, TableField field) {
+ switch (field.getFieldType()) {
+ case BIGINT:
+ return fieldName;
+ case DOUBLE:
+ return String.format("(%s + 0.5)", fieldName.replace("double", "integer"));
+ case STRING:
+ return String.format("CODEPOINT_TO_STRING([100 + %s])", fieldName);
+ }
+ throw new UnsupportedOperationException("Unsupported type for field: " + field.getFieldType().toString());
+ }
+
+ private String buildJSONForQuery(ObjectNode node) {
+ return node.toString().replace("\"$", "").replace("$\"", "").replace("\\\"", "\"");
+ }
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayElement.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayElement.java
new file mode 100644
index 0000000..6e41ead
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayElement.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ArrayElement {
+ final List<TableField> unnestList = new ArrayList<>();
+ final List<TableField> projectList = new ArrayList<>();
+ final int elementPosition;
+ final Kind kind;
+
+ public ArrayElement(Kind kind, int elementPosition) {
+ this.elementPosition = elementPosition;
+ this.kind = kind;
+ }
+
+ public
+
+ static class TableField {
+ private final List<String> fieldName;
+ private final BaseWisconsinTable.Field sourceField;
+
+ TableField(List<String> name, BaseWisconsinTable.Field field) {
+ fieldName = name;
+ sourceField = field;
+ }
+
+ List<String> getFieldName() {
+ return fieldName;
+ }
+
+ String getFullFieldName() {
+ return String.join(".", fieldName);
+ }
+
+ String getLastFieldName() {
+ return fieldName.get(fieldName.size() - 1);
+ }
+
+ BaseWisconsinTable.Field getSourceField() {
+ return sourceField;
+ }
+
+ public BaseWisconsinTable.Field.Type getFieldType() {
+ return (sourceField == null) ? null : sourceField.fieldType;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s [%s]", getFullFieldName(), (sourceField == null) ? "NONE" : sourceField.fieldName);
+ }
+ }
+
+ enum Kind {
+ ATOMIC,
+ UNNEST_VALUE,
+ UNNEST_OBJECT
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayIndex.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayIndex.java
new file mode 100644
index 0000000..1d7d973
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayIndex.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ArrayIndex {
+ private final List<ArrayElement> elements;
+ private final List<List<String>> arrayPath;
+ private String ddlStatement;
+ private String indexName;
+ private String datasetName;
+
+ @Override
+ public String toString() {
+ return ddlStatement;
+ }
+
+ public List<ArrayElement> getElements() {
+ return elements;
+ }
+
+ public List<List<String>> getArrayPath() {
+ return arrayPath;
+ }
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public String getDatasetName() {
+ return datasetName;
+ }
+
+ private ArrayIndex(List<ArrayElement> elements, List<List<String>> arrayPath) {
+ this.elements = Collections.unmodifiableList(elements);
+ this.arrayPath = Collections.unmodifiableList(arrayPath);
+ }
+
+ public static class Builder {
+ public static abstract class ValueSupplier {
+ public abstract BaseWisconsinTable.Field getAtomicBaseField();
+
+ public abstract BaseWisconsinTable.Field getArrayBaseField();
+
+ public abstract List<String> getFieldName(BaseWisconsinTable.Field baseField);
+
+ public abstract List<String> getGroupFieldName(int nestingLevel);
+ }
+
+ private int numberOfAtomicPrefixes;
+ private int numberOfFieldsInArray;
+ private int numberOfAtomicSuffixes;
+ private boolean isArrayOfScalars;
+ private int depthOfArray;
+
+ private final String indexName;
+ private final String datasetName;
+ private ValueSupplier valueSupplier;
+
+ public void setNumberOfAtomicPrefixes(int numberOfAtomicPrefixes) {
+ this.numberOfAtomicPrefixes = numberOfAtomicPrefixes;
+ }
+
+ public void setNumberOfFieldsInArray(int numberOfFieldsInArray) {
+ this.numberOfFieldsInArray = numberOfFieldsInArray;
+ }
+
+ public void setNumberOfAtomicSuffixes(int numberOfAtomicSuffixes) {
+ this.numberOfAtomicSuffixes = numberOfAtomicSuffixes;
+ }
+
+ public void setDepthOfArray(int depthOfArray) {
+ this.depthOfArray = depthOfArray;
+ }
+
+ public void setIsArrayOfScalars(boolean isArrayOfScalars) {
+ this.isArrayOfScalars = isArrayOfScalars;
+ }
+
+ public void setValueSupplier(ValueSupplier valueSupplier) {
+ this.valueSupplier = valueSupplier;
+ }
+
+ public Builder(String indexName, String datasetName) {
+ this.indexName = indexName;
+ this.datasetName = datasetName;
+ }
+
+ public ArrayIndex build() {
+ final List<ArrayElement> elements = new ArrayList<>();
+ final List<List<String>> arrayPath = new ArrayList<>();
+
+ for (int i = 0; i < numberOfAtomicPrefixes; i++) {
+ ArrayElement element = new ArrayElement(ArrayElement.Kind.ATOMIC, elements.size());
+ BaseWisconsinTable.Field field = valueSupplier.getAtomicBaseField();
+ List<String> fieldName = valueSupplier.getFieldName(field);
+ element.projectList.add(new ArrayElement.TableField(fieldName, field));
+ elements.add(element);
+ }
+
+ ArrayElement arrayElement = new ArrayElement(
+ (isArrayOfScalars) ? ArrayElement.Kind.UNNEST_VALUE : ArrayElement.Kind.UNNEST_OBJECT,
+ elements.size());
+ for (int i = 0; i < depthOfArray; i++) {
+ ArrayElement.TableField tableField;
+ if (isArrayOfScalars && i == depthOfArray - 1) {
+ BaseWisconsinTable.Field field = valueSupplier.getArrayBaseField();
+ List<String> fieldName = valueSupplier.getFieldName(field);
+ tableField = new ArrayElement.TableField(fieldName, field);
+ } else {
+ List<String> fieldName = valueSupplier.getGroupFieldName(i + 1);
+ tableField = new ArrayElement.TableField(fieldName, null);
+ }
+ arrayElement.unnestList.add(tableField);
+ arrayPath.add(tableField.getFieldName());
+ }
+ if (!isArrayOfScalars) {
+ for (int i = 0; i < numberOfFieldsInArray; i++) {
+ BaseWisconsinTable.Field field = valueSupplier.getArrayBaseField();
+ List<String> fieldName = valueSupplier.getFieldName(field);
+ arrayElement.projectList.add(new ArrayElement.TableField(fieldName, field));
+ }
+ }
+ elements.add(arrayElement);
+
+ for (int i = 0; i < numberOfAtomicSuffixes; i++) {
+ ArrayElement element = new ArrayElement(ArrayElement.Kind.ATOMIC, elements.size());
+ BaseWisconsinTable.Field field = valueSupplier.getAtomicBaseField();
+ List<String> fieldName = valueSupplier.getFieldName(field);
+ element.projectList.add(new ArrayElement.TableField(fieldName, field));
+ elements.add(element);
+ }
+
+ ArrayIndex index = new ArrayIndex(elements, arrayPath);
+ index.ddlStatement = buildIndexDDL(index.elements);
+ index.datasetName = datasetName;
+ index.indexName = indexName;
+ return index;
+ }
+
+ private String buildIndexDDL(List<ArrayElement> elements) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("CREATE INDEX ").append(indexName);
+ sb.append(" ON ").append(datasetName).append(" ( ");
+ for (int i = 0; i < elements.size(); i++) {
+ ArrayElement e = elements.get(i);
+ if (!e.unnestList.isEmpty()) {
+ sb.append("( ");
+ }
+ for (ArrayElement.TableField unnestPart : e.unnestList) {
+ sb.append("UNNEST ");
+ sb.append(unnestPart.getFullFieldName());
+ sb.append(" ");
+ }
+ if (e.projectList.isEmpty()) {
+ sb.append(": ").append(e.unnestList.get(e.unnestList.size() - 1).getFieldType()).append(" )");
+ } else if (!e.unnestList.isEmpty()) {
+ sb.append("SELECT ");
+ List<ArrayElement.TableField> projectList = e.projectList;
+ for (int j = 0; j < projectList.size(); j++) {
+ sb.append(projectList.get(j).getFullFieldName());
+ sb.append(": ").append(projectList.get(j).getFieldType());
+ sb.append((j != projectList.size() - 1) ? ", " : " ");
+ }
+ sb.append(" )");
+ } else {
+ sb.append(e.projectList.get(0).getFullFieldName());
+ sb.append(": ").append(e.projectList.get(0).getFieldType());
+ }
+ if (i < elements.size() - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(" );\n");
+ return sb.toString();
+ }
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQuery.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQuery.java
new file mode 100644
index 0000000..325e061
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQuery.java
@@ -0,0 +1,494 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+public class ArrayQuery {
+ private final List<FromExpr> fromExprs = new ArrayList<>();
+ private final List<UnnestStep> unnestSteps = new ArrayList<>();
+ private final List<JoinStep> joinSteps = new ArrayList<>();
+ private final List<SelectExpr> selectExprs = new ArrayList<>();
+ private final List<Conjunct> whereConjuncts = new ArrayList<>();
+ private String queryString;
+
+ @Override
+ public String toString() {
+ return queryString;
+ }
+
+ public List<FromExpr> getFromExprs() {
+ return fromExprs;
+ }
+
+ public List<UnnestStep> getUnnestSteps() {
+ return unnestSteps;
+ }
+
+ public List<JoinStep> getJoinSteps() {
+ return joinSteps;
+ }
+
+ public List<SelectExpr> getSelectExprs() {
+ return selectExprs;
+ }
+
+ public List<Conjunct> getWhereConjuncts() {
+ return whereConjuncts;
+ }
+
+ public static class FromExpr {
+ final String datasetName;
+ final String alias;
+
+ public FromExpr(String datasetName, String alias) {
+ this.datasetName = datasetName;
+ this.alias = alias;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s AS %s", datasetName, alias);
+ }
+ }
+
+ public static class UnnestStep {
+ final String sourceAlias;
+ final String arrayField;
+ final String alias;
+
+ public UnnestStep(String sourceAlias, String arrayField, String alias) {
+ this.sourceAlias = sourceAlias;
+ this.arrayField = arrayField;
+ this.alias = alias;
+ }
+
+ public String getNamedExpr() {
+ return sourceAlias + "." + arrayField;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("UNNEST %s AS %s", getNamedExpr(), alias);
+ }
+ }
+
+ public static class SelectExpr {
+ final String expr;
+ final String alias;
+
+ public SelectExpr(String expr, String alias) {
+ this.expr = expr;
+ this.alias = alias;
+ }
+
+ public String asKeyValueString() {
+ return String.format("\"%s\":%s", alias, expr);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s AS %s", expr, alias);
+ }
+ }
+
+ public interface Conjunct {
+ // Note: this is just a marker interface.
+ String toString();
+ }
+
+ public static class SimpleConjunct implements Conjunct {
+ final String expressionOne;
+ final String expressionTwo;
+ final String expressionThree;
+ final String operator;
+ final String annotation;
+
+ public SimpleConjunct(String e1, String e2, String e3, String operator, String annotation) {
+ this.expressionOne = e1;
+ this.expressionTwo = e2;
+ this.expressionThree = e3;
+ this.operator = operator;
+ this.annotation = annotation;
+ }
+
+ public SimpleConjunct(String e1, String e2, String operator, String annotation) {
+ this.expressionOne = e1;
+ this.expressionTwo = e2;
+ this.expressionThree = null;
+ this.operator = operator;
+ this.annotation = annotation;
+ }
+
+ @Override
+ public String toString() {
+ String a = (annotation == null) ? "" : (" " + annotation);
+ if (operator.equals("BETWEEN")) {
+ return String.format("( %s%s BETWEEN %s AND %s )", expressionOne, a, expressionTwo, expressionThree);
+
+ } else {
+ return String.format("( %s%s %s %s )", expressionOne, a, operator, expressionTwo);
+ }
+ }
+ }
+
+ public static class QuantifiedConjunct implements Conjunct {
+ final List<String> arraysToQuantify;
+ final List<String> quantifiedVars;
+ final List<Conjunct> conjuncts;
+ final String quantificationType;
+
+ public QuantifiedConjunct(List<String> arraysToQuantify, List<String> quantifiedVars, List<Conjunct> conjuncts,
+ String quantificationType) {
+ this.arraysToQuantify = arraysToQuantify;
+ this.quantifiedVars = quantifiedVars;
+ this.conjuncts = conjuncts;
+ this.quantificationType = quantificationType;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < arraysToQuantify.size(); i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(quantifiedVars.get(i)).append(" IN ").append(arraysToQuantify.get(i));
+ }
+ String quantifiedBuildExpr = sb.toString();
+
+ return String.format("( %s %s SATISFIES %s )", quantificationType, quantifiedBuildExpr,
+ conjuncts.stream().map(Conjunct::toString).collect(Collectors.joining(" AND ")));
+ }
+ }
+
+ public static class ExistsConjunct implements Conjunct {
+ final FromExpr fromExpr;
+ final List<UnnestStep> unnestSteps;
+ final List<SimpleConjunct> conjuncts;
+
+ public ExistsConjunct(FromExpr fromExpr, List<UnnestStep> unnestSteps, List<SimpleConjunct> conjuncts) {
+ this.fromExpr = fromExpr;
+ this.unnestSteps = unnestSteps;
+ this.conjuncts = conjuncts;
+ }
+
+ @Override
+ public String toString() {
+ String unnestClause = unnestSteps.isEmpty() ? ""
+ : unnestSteps.stream().map(UnnestStep::toString).collect(Collectors.joining(" ")) + " ";
+ return String.format("EXISTS ( FROM %s %sWHERE %s SELECT 1 )", fromExpr.toString(), unnestClause,
+ conjuncts.stream().map(Conjunct::toString).collect(Collectors.joining(" AND ")));
+ }
+ }
+
+ public static class JoinStep {
+ final FromExpr subqueryFromExpr;
+ final List<UnnestStep> subqueryUnnestSteps;
+ final List<SelectExpr> subquerySelectExprs;
+ final List<SimpleConjunct> onExprConjuncts;
+ final String joinType;
+ final String joinAlias;
+
+ public JoinStep(List<UnnestStep> subqueryUnnestSteps, List<SelectExpr> subquerySelectExprs,
+ FromExpr subqueryFromExpr, List<SimpleConjunct> onExprConjuncts, String joinType, String joinAlias) {
+ this.subqueryUnnestSteps = subqueryUnnestSteps;
+ this.subquerySelectExprs = subquerySelectExprs;
+ this.subqueryFromExpr = subqueryFromExpr;
+ this.onExprConjuncts = onExprConjuncts;
+ this.joinType = joinType;
+ this.joinAlias = joinAlias;
+ }
+
+ public String getJoinExpr() {
+ String keyValuePairs = subquerySelectExprs.stream().map(SelectExpr::asKeyValueString)
+ .collect(Collectors.joining(",\n\t\t"));
+ return String.format("(\n\tFROM %s\n\t%s\n\tSELECT VALUE { \n\t\t%s\n\t} )", subqueryFromExpr,
+ subqueryUnnestSteps.stream().map(UnnestStep::toString).collect(Collectors.joining("\n\t")),
+ keyValuePairs);
+ }
+
+ @Override
+ public String toString() {
+ String onExpr = onExprConjuncts.stream().map(SimpleConjunct::toString).collect(Collectors.joining(" AND "));
+ return String.format("%s JOIN %s AS %s\nON %s", joinType, getJoinExpr(), joinAlias, onExpr);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static class Builder {
+ public static abstract class ValueSupplier {
+ public abstract List<UnnestStep> getExtraUnnestSteps(String alias);
+
+ public abstract String getJoinType();
+
+ public abstract boolean getIsConditionOnUnnest();
+
+ public abstract boolean getIsConstantConditionWithJoins();
+
+ public abstract boolean getIsCrossProductOnProbes();
+
+ public abstract String getOperatorForJoin();
+
+ public abstract String getOperatorForConstant();
+
+ public abstract Pair<String, String> getRangeFromDomain(BaseWisconsinTable.Domain domain);
+
+ public abstract boolean getIsBetweenConjunct();
+
+ public abstract String getQuantifier();
+
+ public abstract List<Conjunct> getExtraConjuncts(String alias);
+
+ public abstract List<Conjunct> getExtraQuantifiersAndConjuncts(List<String> arraysToQuantify,
+ List<String> quantifiedVars, String alias);
+
+ public abstract boolean getIsUseNestedQuantification();
+ }
+
+ private int limitCount;
+ private int unnestStepDepth;
+ private int numberOfJoins;
+ private int numberOfExplicitJoins;
+
+ private final ArrayIndex arrayIndex;
+ private final ArrayQuery arrayQuery;
+ private String workingUnnestAlias;
+ private ValueSupplier valueSupplier;
+
+ public Builder(ArrayIndex arrayIndex) {
+ this.arrayQuery = new ArrayQuery();
+ this.arrayIndex = arrayIndex;
+ }
+
+ public void setUnnestStepDepth(int unnestStepDepth) {
+ this.unnestStepDepth = unnestStepDepth;
+ }
+
+ public void setNumberOfJoins(int numberOfJoins) {
+ this.numberOfJoins = numberOfJoins;
+ }
+
+ public void setNumberOfExplicitJoins(int numberOfExplicitJoins) {
+ this.numberOfExplicitJoins = numberOfExplicitJoins;
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ public void setLimitCount(int limitCount) {
+ this.limitCount = limitCount;
+ }
+
+ public void setValueSupplier(ValueSupplier valueSupplier) {
+ this.valueSupplier = valueSupplier;
+ }
+
+ public ArrayQuery build() {
+ StringBuilder sb = new StringBuilder();
+
+ // Start with our FROM clause. These will include all datasets to join with.
+ buildStartingFromClause(sb);
+
+ // Add the UNNEST steps expressions. These will always follow after the FROM expressions.
+ buildUnnestSteps(sb);
+
+ // Add the JOIN steps expressions. These will always follow after the UNNEST step expressions.
+ buildJoinSteps(sb);
+
+ // Add the WHERE clauses next. This will include implicit JOINs and quantified expressions.
+ buildWhereClause(sb);
+
+ // Add the SELECT clause. This consists of the primary keys from all involved datasets.
+ buildSelectClause(sb);
+
+ // We will ORDER BY all fields in our SELECT clause, and LIMIT accordingly.
+ buildQuerySuffix(sb);
+
+ arrayQuery.queryString = sb.toString();
+ return arrayQuery;
+ }
+
+ private void buildStartingFromClause(StringBuilder sb) {
+ for (int i = 0; i < numberOfJoins; i++) {
+ FromExpr fromExpr = new FromExpr("ProbeDataset" + (i + 1), "D" + (i + 2));
+ arrayQuery.fromExprs.add(fromExpr);
+ }
+ if (numberOfJoins == 0 || numberOfJoins != numberOfExplicitJoins) {
+ arrayQuery.fromExprs.add(new FromExpr(arrayIndex.getDatasetName(), "D1"));
+ }
+
+ sb.append("FROM ");
+ sb.append(arrayQuery.fromExprs.stream().map(FromExpr::toString).collect(Collectors.joining(",\n\t")));
+ sb.append('\n');
+ }
+
+ private void buildUnnestSteps(StringBuilder sb) {
+ if (unnestStepDepth == 0) {
+ workingUnnestAlias = "D1";
+
+ } else {
+ arrayQuery.unnestSteps.addAll(ArrayQueryUtil.createUnnestSteps(valueSupplier, "D1",
+ arrayIndex.getArrayPath(), unnestStepDepth, "P", "G", "G"));
+ workingUnnestAlias = arrayQuery.unnestSteps.get(arrayQuery.unnestSteps.size() - 1).alias;
+ String unnestSteps =
+ arrayQuery.unnestSteps.stream().map(UnnestStep::toString).collect(Collectors.joining("\n"));
+ sb.append(unnestSteps).append('\n');
+ }
+ }
+
+ private void buildJoinSteps(StringBuilder sb) {
+ if (numberOfExplicitJoins == 0) {
+ return;
+ }
+
+ // Build the expression to JOIN with. This will be a subquery that UNNESTs the array part that has
+ // not yet been UNNESTed.
+ List<UnnestStep> subqueryUnnestSteps = new ArrayList<>();
+ String prevSubqueryUnnestAlias = "D1";
+ for (int i = unnestStepDepth; i < arrayIndex.getArrayPath().size(); i++) {
+ String arrayField = String.join(".", arrayIndex.getArrayPath().get(i));
+ subqueryUnnestSteps.add(new UnnestStep(prevSubqueryUnnestAlias, arrayField, "G" + (i + 1)));
+ prevSubqueryUnnestAlias = "G" + (i + 1);
+ }
+ List<SelectExpr> subquerySelectExprs = new ArrayList<>();
+ String finalSubqueryUnnestAlias = prevSubqueryUnnestAlias;
+ ArrayQueryUtil.createFieldStream(arrayIndex.getElements()).forEach(e -> {
+ ArrayElement.TableField tableField = e.getRight();
+ String exprInSelect;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ exprInSelect = "D1." + tableField.getFullFieldName();
+ subquerySelectExprs.add(new SelectExpr(exprInSelect, tableField.getLastFieldName()));
+ break;
+ case UNNEST_VALUE:
+ exprInSelect = finalSubqueryUnnestAlias;
+ subquerySelectExprs.add(new SelectExpr(exprInSelect, finalSubqueryUnnestAlias));
+ break;
+ case UNNEST_OBJECT:
+ exprInSelect = finalSubqueryUnnestAlias + "." + tableField.getFullFieldName();
+ subquerySelectExprs.add(new SelectExpr(exprInSelect, tableField.getLastFieldName()));
+ break;
+ }
+ });
+
+ // Now build each JOIN step.
+ for (int i = 0; i < numberOfExplicitJoins; i++) {
+ List<SimpleConjunct> onConjuncts = ArrayQueryUtil.createOnConjuncts(valueSupplier,
+ arrayIndex.getElements(), finalSubqueryUnnestAlias, i);
+ FromExpr indexedDataset = new FromExpr(arrayIndex.getDatasetName(), "D1");
+ arrayQuery.joinSteps.add(new JoinStep(subqueryUnnestSteps, subquerySelectExprs, indexedDataset,
+ onConjuncts, valueSupplier.getJoinType(), "J" + (i + 1)));
+ }
+ sb.append(arrayQuery.joinSteps.stream().map(JoinStep::toString).collect(Collectors.joining("\n")));
+ sb.append('\n');
+ }
+
+ private void buildWhereClause(StringBuilder sb) {
+ boolean isConditionOnUnnestPossible = unnestStepDepth == arrayIndex.getArrayPath().size();
+
+ // JOIN the remaining tables.
+ for (int i = arrayQuery.joinSteps.size(); i < numberOfJoins; i++) {
+ int joinPosition = i;
+ if (isConditionOnUnnestPossible && valueSupplier.getIsConditionOnUnnest()) {
+ // Having UNNESTed the indexed array(s), join with said array.
+ arrayQuery.whereConjuncts
+ .addAll(ArrayQueryUtil.createFieldStream(arrayIndex.getElements())
+ .map(e -> ArrayQueryUtil.createConjunctForUnnestJoins(valueSupplier,
+ workingUnnestAlias, e.getRight(), e.getLeft(), joinPosition))
+ .collect(Collectors.toList()));
+
+ } else {
+ // We are going to perform a quantified join. Join the atomic fields outside the quantification.
+ arrayQuery.whereConjuncts
+ .addAll(ArrayQueryUtil.createFieldStream(arrayIndex.getElements())
+ .filter(e -> e.getLeft() == ArrayElement.Kind.ATOMIC)
+ .map(e -> ArrayQueryUtil.createConjunctForUnnestJoins(valueSupplier,
+ workingUnnestAlias, e.getRight(), e.getLeft(), joinPosition))
+ .collect(Collectors.toList()));
+
+ // Create the quantified expression conjunct.
+ arrayQuery.whereConjuncts.add(ArrayQueryUtil.createConjunctForQuantifiedJoins(valueSupplier,
+ arrayIndex.getElements(), arrayIndex.getArrayPath(), "D1", joinPosition));
+ }
+ }
+
+ // If there are no JOINs, then we must condition on all constants in the index.
+ if (numberOfJoins == 0 || valueSupplier.getIsConstantConditionWithJoins()) {
+ // Condition on the atomic fields. Similar to joins, do not include these in the quantification.
+ arrayQuery.whereConjuncts.addAll(ArrayQueryUtil.createFieldStream(arrayIndex.getElements())
+ .filter(e -> e.getLeft() == ArrayElement.Kind.ATOMIC)
+ .map(e -> ArrayQueryUtil.createConjunctForUnnestNonJoins(valueSupplier,
+ "D1." + e.getRight().getFullFieldName(), e.getRight(), e.getLeft()))
+ .collect(Collectors.toList()));
+
+ if (isConditionOnUnnestPossible && valueSupplier.getIsConditionOnUnnest()) {
+ // Having UNNESTed the indexed array(s), condition on the items in said array.
+ arrayQuery.whereConjuncts
+ .addAll(ArrayQueryUtil.createFieldStream(arrayIndex.getElements())
+ .filter(e -> e.getLeft() != ArrayElement.Kind.ATOMIC)
+ .map(e -> ArrayQueryUtil.createConjunctForUnnestNonJoins(valueSupplier,
+ workingUnnestAlias, e.getRight(), e.getLeft()))
+ .collect(Collectors.toList()));
+
+ } else {
+ // Create the quantification expression conjunct.
+ arrayQuery.whereConjuncts.add(ArrayQueryUtil.createConjunctForQuantifiedNonJoins(valueSupplier,
+ arrayIndex.getElements(), arrayIndex.getArrayPath(), "D1"));
+ }
+ }
+
+ // If there is more than one probe, we must join each probe.
+ for (int i = 1; i < numberOfJoins; i++) {
+ String primaryKeyOne = "D" + (i + 1) + "._id";
+ String primaryKeyTwo = "D" + (i + 2) + "._id";
+ if (!valueSupplier.getIsCrossProductOnProbes()) {
+ arrayQuery.whereConjuncts.add(new SimpleConjunct(primaryKeyOne, primaryKeyTwo, "=", null));
+ }
+ }
+
+ if (!arrayQuery.whereConjuncts.isEmpty()) {
+ String d = " AND\n\t";
+ sb.append("WHERE ");
+ sb.append(arrayQuery.whereConjuncts.stream().map(Conjunct::toString).collect(Collectors.joining(d)));
+ sb.append('\n');
+ }
+ }
+
+ private void buildSelectClause(StringBuilder sb) {
+ sb.append("SELECT ");
+ if (numberOfJoins == 0 || numberOfJoins != numberOfExplicitJoins) {
+ arrayQuery.selectExprs.add(new SelectExpr("D1._id", "PK1"));
+ }
+ for (int i = 0; i < numberOfJoins; i++) {
+ arrayQuery.selectExprs.add(new SelectExpr("D" + (i + 2) + "._id", "PK" + (i + 2)));
+ }
+ sb.append(arrayQuery.selectExprs.stream().map(SelectExpr::toString).collect(Collectors.joining(", ")));
+ sb.append('\n');
+ }
+
+ private void buildQuerySuffix(StringBuilder sb) {
+ sb.append("ORDER BY ");
+ sb.append(arrayQuery.selectExprs.stream().map(e -> e.expr).collect(Collectors.joining(", "))).append('\n');
+ sb.append("LIMIT ").append(limitCount).append(";\n");
+ }
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQueryUtil.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQueryUtil.java
new file mode 100644
index 0000000..3f2807f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ArrayQueryUtil.java
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.asterix.test.array.ArrayElement.Kind;
+import org.apache.asterix.test.array.ArrayElement.TableField;
+import org.apache.asterix.test.array.ArrayQuery.Builder.ValueSupplier;
+import org.apache.asterix.test.array.ArrayQuery.Conjunct;
+import org.apache.asterix.test.array.ArrayQuery.ExistsConjunct;
+import org.apache.asterix.test.array.ArrayQuery.FromExpr;
+import org.apache.asterix.test.array.ArrayQuery.QuantifiedConjunct;
+import org.apache.asterix.test.array.ArrayQuery.SimpleConjunct;
+import org.apache.asterix.test.array.ArrayQuery.UnnestStep;
+import org.apache.commons.lang3.tuple.Pair;
+
+class ArrayQueryUtil {
+ public static Stream<Pair<Kind, TableField>> createFieldStream(List<ArrayElement> elements) {
+ return elements.stream().map(e -> {
+ switch (e.kind) {
+ case ATOMIC:
+ TableField atomicField = e.projectList.get(0);
+ return Collections.singletonList(Pair.of(e.kind, atomicField));
+
+ case UNNEST_VALUE:
+ TableField lastUnnestField = e.unnestList.get(e.unnestList.size() - 1);
+ return Collections.singletonList(Pair.of(e.kind, lastUnnestField));
+
+ default: // UNNEST_OBJECT
+ return e.projectList.stream().map(p -> Pair.of(e.kind, p)).collect(Collectors.toUnmodifiableList());
+ }
+ }).flatMap(Collection::stream);
+ }
+
+ public static List<UnnestStep> createUnnestSteps(ValueSupplier valueSupplier, String startingAlias,
+ List<List<String>> arrayPath, int depthToUnnest, String prefixA, String prefixB, String prefixC) {
+ List<UnnestStep> unnestSteps = new ArrayList<>();
+ String workingAlias = startingAlias;
+ for (int i = 0; i < depthToUnnest; i++) {
+ List<UnnestStep> extraUnnestSteps = valueSupplier.getExtraUnnestSteps(workingAlias);
+ for (int j = 0; j < extraUnnestSteps.size(); j++) {
+ String aliasForExtraUnnest = prefixA.repeat(i + 1) + (j + 1);
+ UnnestStep extraUnnestStep = extraUnnestSteps.get(j);
+ UnnestStep extraUnnestStepWithAlias =
+ new UnnestStep(extraUnnestStep.sourceAlias, extraUnnestStep.arrayField, aliasForExtraUnnest);
+ unnestSteps.add(extraUnnestStepWithAlias);
+ }
+
+ String arrayField = String.join(".", arrayPath.get(i));
+ UnnestStep unnestStep = new UnnestStep(workingAlias, arrayField, prefixB + (i + 1));
+ unnestSteps.add(unnestStep);
+ workingAlias = prefixC + (i + 1);
+ }
+ return unnestSteps;
+ }
+
+ public static List<SimpleConjunct> createOnConjuncts(ValueSupplier valueSupplier,
+ List<ArrayElement> arrayIndexElements, String finalSubqueryUnnestAlias, int joinPosition) {
+ return ArrayQueryUtil.createFieldStream(arrayIndexElements).map(e -> {
+ TableField tableField = e.getRight();
+ String leftExpr = null;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ case UNNEST_OBJECT:
+ leftExpr = "J" + (joinPosition + 1) + "." + tableField.getLastFieldName();
+ break;
+ case UNNEST_VALUE:
+ leftExpr = "J" + (joinPosition + 1) + "." + finalSubqueryUnnestAlias;
+ break;
+ }
+ String rightExpr = createProbeExpr(joinPosition, tableField);
+ String operator = valueSupplier.getOperatorForJoin();
+ return new SimpleConjunct(leftExpr, rightExpr, operator, "/* +indexnl */");
+ }).collect(Collectors.toList());
+ }
+
+ public static SimpleConjunct createConjunctForUnnestJoins(ValueSupplier valueSupplier, String unnestAlias,
+ ArrayElement.TableField tableField, ArrayElement.Kind fieldKind, int joinPosition) {
+ String leftExpr = null;
+ switch (fieldKind) {
+ case ATOMIC:
+ leftExpr = "D1." + tableField.getFullFieldName();
+ break;
+ case UNNEST_VALUE:
+ leftExpr = unnestAlias;
+ break;
+ case UNNEST_OBJECT:
+ leftExpr = unnestAlias + "." + tableField.getFullFieldName();
+ break;
+ }
+ String rightExpr = createProbeExpr(joinPosition, tableField);
+ return new SimpleConjunct(leftExpr, rightExpr, valueSupplier.getOperatorForJoin(), "/* +indexnl */");
+ }
+
+ public static QuantifiedConjunct createConjunctForQuantifiedJoins(ValueSupplier valueSupplier,
+ List<ArrayElement> arrayIndexElements, List<List<String>> workingArray, String prefix, int joinPosition) {
+ List<String> arraysToQuantify = new ArrayList<>();
+ List<String> quantifiedVars = new ArrayList<>();
+ List<Conjunct> conjuncts = new ArrayList<>();
+ int remainingDepthOfArray = workingArray.size();
+
+ if (remainingDepthOfArray > 1) {
+ String containingArray = String.join(".", workingArray.get(0));
+ arraysToQuantify.add(String.format("%s.%s", prefix, containingArray));
+ String itemVar = "V" + remainingDepthOfArray;
+ quantifiedVars.add(itemVar);
+
+ if (valueSupplier.getIsUseNestedQuantification()) {
+ // Recurse and create a nested quantification expression to quantify over the rest of our arrays.
+ conjuncts.add(createConjunctForQuantifiedJoins(valueSupplier, arrayIndexElements,
+ workingArray.subList(1, workingArray.size()), itemVar, joinPosition));
+
+ } else {
+ // We are now using an EXISTS clause to quantify over the rest of our arrays.
+ List<List<String>> remainingArray = workingArray.subList(1, workingArray.size());
+ conjuncts.add(createConjunctForExistsJoins(valueSupplier, arrayIndexElements, remainingArray, itemVar,
+ joinPosition));
+ }
+
+ } else {
+ conjuncts.addAll(createFieldStream(arrayIndexElements).filter(e -> e.getLeft() != Kind.ATOMIC)
+ .peek(e -> appendQuantifiedVars(workingArray, prefix, arraysToQuantify, quantifiedVars, e))
+ .map(e -> {
+ TableField tableField = e.getRight();
+ String operator = valueSupplier.getOperatorForJoin();
+ String leftExpr = null;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ throw new IllegalStateException("Unexpected atomic element!");
+ case UNNEST_VALUE:
+ leftExpr = "V1";
+ break;
+ case UNNEST_OBJECT:
+ leftExpr = "V1." + tableField.getFullFieldName();
+ break;
+ }
+ String rightExpr = createProbeExpr(joinPosition, tableField);
+ return new SimpleConjunct(leftExpr, rightExpr, operator, "/* +indexnl */");
+ }).collect(Collectors.toList()));
+ }
+
+ return new QuantifiedConjunct(arraysToQuantify, quantifiedVars, conjuncts, valueSupplier.getQuantifier());
+ }
+
+ public static SimpleConjunct createConjunctForUnnestNonJoins(ValueSupplier valueSupplier, String unnestAlias,
+ ArrayElement.TableField tableField, ArrayElement.Kind fieldKind) {
+ String variableExpr = null;
+ switch (fieldKind) {
+ case ATOMIC:
+ variableExpr = "D1." + tableField.getFullFieldName();
+ break;
+ case UNNEST_VALUE:
+ variableExpr = unnestAlias;
+ break;
+ case UNNEST_OBJECT:
+ variableExpr = unnestAlias + "." + tableField.getFullFieldName();
+ break;
+ }
+
+ return createSimpleConjunctForNonJoins(valueSupplier, tableField, variableExpr);
+ }
+
+ public static QuantifiedConjunct createConjunctForQuantifiedNonJoins(ValueSupplier valueSupplier,
+ List<ArrayElement> indexElements, List<List<String>> workingArray, String prefix) {
+ List<String> arraysToQuantify = new ArrayList<>();
+ List<String> quantifiedVars = new ArrayList<>();
+ List<Conjunct> conjuncts = new ArrayList<>();
+ int remainingDepthOfArray = workingArray.size();
+
+ if (remainingDepthOfArray > 1) {
+ String containingArray = String.join(".", workingArray.get(0));
+ arraysToQuantify.add(String.format("%s.%s", prefix, containingArray));
+ String itemVar = "V" + remainingDepthOfArray;
+ quantifiedVars.add(itemVar);
+
+ if (valueSupplier.getIsUseNestedQuantification()) {
+ // Recurse and create a nested quantification expression to quantify over the rest of our arrays.
+ conjuncts.add(createConjunctForQuantifiedNonJoins(valueSupplier, indexElements,
+ workingArray.subList(1, workingArray.size()), itemVar));
+
+ } else {
+ // We are now using an EXISTS clause to quantify over the rest of our arrays.
+ List<List<String>> remainingArray = workingArray.subList(1, workingArray.size());
+ conjuncts.add(createConjunctForExistsNonJoins(valueSupplier, indexElements, remainingArray, itemVar));
+ }
+
+ } else {
+ conjuncts.addAll(createFieldStream(indexElements).filter(e -> e.getLeft() != Kind.ATOMIC)
+ .peek(e -> appendQuantifiedVars(workingArray, prefix, arraysToQuantify, quantifiedVars, e))
+ .map(e -> {
+ ArrayElement.TableField tableField = e.getRight();
+ String variableExpr = null;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ throw new IllegalStateException("Unexpected atomic element!");
+ case UNNEST_VALUE:
+ variableExpr = "V1";
+ break;
+ case UNNEST_OBJECT:
+ variableExpr = "V1." + tableField.getFullFieldName();
+ break;
+ }
+ return createSimpleConjunctForNonJoins(valueSupplier, tableField, variableExpr);
+ }).collect(Collectors.toList()));
+ }
+
+ // Append any extra conjuncts from the indexed object.
+ if (ArrayQueryUtil.createFieldStream(indexElements).anyMatch(e -> e.getLeft() == Kind.UNNEST_OBJECT)) {
+ conjuncts.addAll(valueSupplier.getExtraConjuncts("V" + remainingDepthOfArray));
+ }
+
+ // Add any extra quantifiers.
+ conjuncts.addAll(valueSupplier.getExtraQuantifiersAndConjuncts(arraysToQuantify, quantifiedVars, prefix));
+
+ return new QuantifiedConjunct(arraysToQuantify, quantifiedVars, conjuncts, valueSupplier.getQuantifier());
+ }
+
+ private static void appendQuantifiedVars(List<List<String>> workingArray, String prefix,
+ List<String> arraysToQuantify, List<String> quantifiedVars, Pair<Kind, TableField> e) {
+ TableField tableField = e.getRight();
+ switch (e.getLeft()) {
+ case ATOMIC:
+ throw new IllegalStateException("Unexpected atomic element!");
+ case UNNEST_VALUE:
+ arraysToQuantify.add(String.format("%s.%s", prefix, tableField.getFullFieldName()));
+ quantifiedVars.add("V1");
+ break;
+ case UNNEST_OBJECT:
+ if (!quantifiedVars.contains("V1")) {
+ String containingArray = String.join(".", workingArray.get(0));
+ arraysToQuantify.add(String.format("%s.%s", prefix, containingArray));
+ quantifiedVars.add("V1");
+ }
+ break;
+ }
+ }
+
+ private static ExistsConjunct createConjunctForExistsJoins(ValueSupplier valueSupplier,
+ List<ArrayElement> arrayIndexElements, List<List<String>> arrayPath, String itemVar, int joinPosition) {
+ // Build our FROM and UNNEST clauses.
+ List<UnnestStep> unnestSteps = new ArrayList<>();
+ if (arrayPath.size() > 1) {
+ String prefixA = Character.toString('T' + joinPosition);
+ String prefixB = Character.toString('O' + joinPosition);
+ unnestSteps.addAll(ArrayQueryUtil.createUnnestSteps(valueSupplier, "GG1",
+ arrayPath.subList(1, arrayPath.size()), arrayPath.size() - 1, prefixA, prefixB, prefixB));
+ }
+ FromExpr fromExpr = new FromExpr(String.format("%s.%s", itemVar, String.join(".", arrayPath.get(0))), "GG1");
+
+ // Create the conjuncts for the JOIN.
+ String variableExpr = (unnestSteps.isEmpty()) ? "GG1" : unnestSteps.get(unnestSteps.size() - 1).alias;
+ List<SimpleConjunct> conjuncts =
+ createFieldStream(arrayIndexElements).filter(e -> e.getLeft() != Kind.ATOMIC).map(e -> {
+ TableField tableField = e.getRight();
+ String fieldName = tableField.getFullFieldName();
+ String operator = valueSupplier.getOperatorForJoin();
+ String leftExpr = null;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ throw new IllegalStateException("Unexpected atomic element!");
+ case UNNEST_VALUE:
+ leftExpr = variableExpr;
+ break;
+ case UNNEST_OBJECT:
+ leftExpr = variableExpr + "." + fieldName;
+ break;
+ }
+ String rightExpr = createProbeExpr(joinPosition, tableField);
+ return new SimpleConjunct(leftExpr, rightExpr, operator, "/* +indexnl */");
+ }).collect(Collectors.toList());
+
+ return new ExistsConjunct(fromExpr, unnestSteps, conjuncts);
+ }
+
+ private static String createProbeExpr(int joinPosition, TableField tableField) {
+ String rightExpr = "D" + (joinPosition + 2) + "." + tableField.getSourceField().fieldName;
+ switch (tableField.getFieldType()) {
+ case BIGINT:
+ rightExpr = String.format("TO_BIGINT(%s)", rightExpr);
+ break;
+ case DOUBLE:
+ rightExpr = String.format("(TO_DOUBLE(%s) + 0.5)", rightExpr.replace("double", "integer"));
+ break;
+ case STRING:
+ rightExpr = String.format("CODEPOINT_TO_STRING([100 + %s])", rightExpr);
+ break;
+ }
+ return rightExpr;
+ }
+
+ private static SimpleConjunct createSimpleConjunctForNonJoins(ValueSupplier valueSupplier, TableField tableField,
+ String variableExpr) {
+ Pair<String, String> bounds = valueSupplier.getRangeFromDomain(tableField.getSourceField().domain);
+ if (valueSupplier.getIsBetweenConjunct()) {
+ return new SimpleConjunct(variableExpr, bounds.getLeft(), bounds.getRight(), "BETWEEN", null);
+
+ } else {
+ switch (valueSupplier.getOperatorForConstant()) {
+ case "=":
+ return new SimpleConjunct(variableExpr, bounds.getLeft(), "=", null);
+ case "<":
+ return new SimpleConjunct(variableExpr, bounds.getRight(), "<", null);
+ case ">":
+ return new SimpleConjunct(variableExpr, bounds.getLeft(), ">", null);
+ case "<=":
+ return new SimpleConjunct(variableExpr, bounds.getRight(), "<=", null);
+ default: // ">="
+ return new SimpleConjunct(variableExpr, bounds.getLeft(), ">=", null);
+ }
+ }
+ }
+
+ private static ExistsConjunct createConjunctForExistsNonJoins(ValueSupplier valueSupplier,
+ List<ArrayElement> arrayIndexElements, List<List<String>> arrayPath, String itemVar) {
+ // Build our FROM and UNNEST clauses.
+ List<UnnestStep> unnestSteps = new ArrayList<>();
+ if (arrayPath.size() > 1) {
+ unnestSteps.addAll(ArrayQueryUtil.createUnnestSteps(valueSupplier, "GG1",
+ arrayPath.subList(1, arrayPath.size()), arrayPath.size() - 1, "S", "N", "N"));
+ }
+ FromExpr fromExpr = new FromExpr(String.format("%s.%s", itemVar, String.join(".", arrayPath.get(0))), "GG1");
+
+ // Create the conjuncts for the JOIN.
+ String variableExpr = (unnestSteps.isEmpty()) ? "GG1" : unnestSteps.get(unnestSteps.size() - 1).alias;
+ List<SimpleConjunct> conjuncts =
+ createFieldStream(arrayIndexElements).filter(e -> e.getLeft() != Kind.ATOMIC).map(e -> {
+ TableField tableField = e.getRight();
+ String variableExprForConjunct = null;
+ switch (e.getLeft()) {
+ case ATOMIC:
+ throw new IllegalStateException("Unexpected atomic element!");
+ case UNNEST_VALUE:
+ variableExprForConjunct = variableExpr;
+ break;
+ case UNNEST_OBJECT:
+ variableExprForConjunct = variableExpr + "." + tableField.getFullFieldName();
+ break;
+ }
+ return createSimpleConjunctForNonJoins(valueSupplier, tableField, variableExprForConjunct);
+ }).collect(Collectors.toList());
+
+ return new ExistsConjunct(fromExpr, unnestSteps, conjuncts);
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/BaseWisconsinTable.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/BaseWisconsinTable.java
new file mode 100644
index 0000000..97c00bf
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/BaseWisconsinTable.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class BaseWisconsinTable {
+ public static final String TABLE_NAME = "BaseWisconsinTable";
+ public static final Path TABLE_FILE = Paths.get("data", "array-index.adm");
+
+ static final Field[] GROUPING_FIELDS =
+ new Field[] { Field.GROUPING_1000, Field.GROUPING_500, Field.GROUPING_250, Field.GROUPING_100 };
+ public static final int NUMBER_OF_GROUPING_FIELDS = GROUPING_FIELDS.length;
+ public static final int NUMBER_OF_NON_GROUPING_FIELDS = Field.values().length - NUMBER_OF_GROUPING_FIELDS;
+
+ @SuppressWarnings("rawtypes")
+ enum Field {
+ GROUPING_1000("grouping_1000", Type.BIGINT, new Domain<>(0, 999)),
+ GROUPING_500("grouping_500", Type.BIGINT, new Domain<>(0, 499)),
+ GROUPING_250("grouping_250", Type.BIGINT, new Domain<>(0, 249)),
+ GROUPING_100("grouping_100", Type.BIGINT, new Domain<>(0, 99)),
+
+ INTEGER_RAND_2000("integer_rand_2000", Type.BIGINT, new Domain<>(0, 1999)),
+ INTEGER_SEQ_2000("integer_seq_2000", Type.BIGINT, new Domain<>(0, 1999)),
+ INTEGER_SEQ_2("integer_rand_2", Type.BIGINT, new Domain<>(0, 1)),
+ INTEGER_SEQ_4("integer_rand_4", Type.BIGINT, new Domain<>(0, 3)),
+ INTEGER_SEQ_10("integer_rand_10", Type.BIGINT, new Domain<>(0, 9)),
+ INTEGER_SEQ_20("integer_rand_20", Type.BIGINT, new Domain<>(0, 19)),
+
+ DOUBLE_RAND_2000("double_rand_2000", Type.DOUBLE, new Domain<>(0.5, 1999.5)),
+ DOUBLE_SEQ_2000("double_seq_2000", Type.DOUBLE, new Domain<>(0.5, 1999.5)),
+ DOUBLE_SEQ_2("double_rand_2", Type.DOUBLE, new Domain<>(0.5, 1.5)),
+ DOUBLE_SEQ_4("double_rand_4", Type.DOUBLE, new Domain<>(0.5, 3.5)),
+ DOUBLE_SEQ_10("double_rand_10", Type.DOUBLE, new Domain<>(0.5, 9.5)),
+ DOUBLE_SEQ_20("double_rand_20", Type.DOUBLE, new Domain<>(0.5, 19.5)),
+
+ STRING_RAND_26_A("string_rand_26_a", Type.STRING, new Domain<>('A', 'Z')),
+ STRING_RAND_26_B("string_rand_26_b", Type.STRING, new Domain<>('A', 'Z')),
+ STRING_RAND_26_C("string_rand_26_c", Type.STRING, new Domain<>('A', 'Z'));
+
+ final String fieldName;
+ final Type fieldType;
+ final Domain domain;
+
+ Field(String fieldName, Type fieldType, Domain domain) {
+ this.fieldName = fieldName;
+ this.fieldType = fieldType;
+ this.domain = domain;
+ }
+
+ enum Type {
+ BIGINT,
+ DOUBLE,
+ STRING
+ }
+ }
+
+ static class Domain<T> {
+ final T minimum;
+ final T maximum;
+
+ Domain(T minimum, T maximum) {
+ this.minimum = minimum;
+ this.maximum = maximum;
+ }
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/SqlppArrayIndexRQGTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/SqlppArrayIndexRQGTest.java
new file mode 100644
index 0000000..070e29a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/SqlppArrayIndexRQGTest.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.asterix.common.utils.Servlets;
+import org.apache.asterix.test.array.ArrayQuery.Conjunct;
+import org.apache.asterix.test.array.ArrayQuery.ExistsConjunct;
+import org.apache.asterix.test.array.ArrayQuery.QuantifiedConjunct;
+import org.apache.asterix.test.array.ArrayQuery.SimpleConjunct;
+import org.apache.asterix.test.array.ArrayQuery.UnnestStep;
+import org.apache.asterix.test.common.TestExecutor;
+import org.apache.asterix.test.runtime.LangExecutionUtil;
+import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.asterix.testframework.xml.ParameterTypeEnum;
+import org.apache.asterix.testframework.xml.TestCase;
+import org.apache.commons.math3.distribution.ExponentialDistribution;
+import org.apache.commons.math3.random.MersenneTwister;
+import org.apache.commons.math3.random.RandomGenerator;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectReader;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * This test will perform the following, using a flat schema that is defined ahead of time:
+ * <ol>
+ * <li>Generate a random schema for a single dataset using fields from the predefined flat schema, composed of
+ * various nested objects and an array of scalars or objects (whose contents can themselves contain scalars, arrays of
+ * scalars or arrays of objects following the same definition this is defined in).</li>
+ * <li>Using the randomly generated schema, create a query that will build the corresponding dataset from the flat
+ * schema using a series of CTEs and GROUP BY GROUP AS clauses.</li>
+ * <li>Create the array index DDL using the randomly generated schema.</li>
+ * <li>Randomly generate a query that will utilize the aforementioned array index, exploring the parameter space:<ul>
+ * <li>The number of non-indexed field terms defined in the query.</li>
+ * <li>The number of joins to perform for the query.</li>
+ * <li>The type of query.<ul>
+ *
+ * <li>For quantification queries...<ul>
+ * <li>The type of quantification (SOME AND EVERY | SOME).</li>
+ * <li>The presence of multiple quantifiers.</li>
+ * <li>Whether to use specify multiple levels of nesting with EXISTs or another quantification expression.</li>
+ * </ul></li>
+ *
+ * <li>For UNNEST queries...<ul>
+ * <li>The number of unrelated UNNESTs.</li>
+ * </ul></li>
+ *
+ * <li>For JOIN queries...<ul>
+ * <li>The type of JOIN (INNER | LEFT OUTER | Quantified).</li>
+ * <li><i>All of the options from the previous two items.</i></li>
+ * </ul></li>
+ * </ul></li>
+ * </ul>
+ * <li>Execute the query to build the dataset of our random schema and then execute the array index DDL, OR execute
+ * the array index DDL then build the dataset of our random schema. This decision is made randomly.</li>
+ * <li>Execute the randomly generated query with array index optimization enabled and without array index optimization
+ * enabled. Verify that the two result sets are exactly the same AND verify that the array index is being utilized.</li>
+ * <li>Repeat this entire process (from step 1) {@code ArrayIndexRQGIT.limit} amount of times.</li>
+ * </ol>
+ */
+@RunWith(Parameterized.class)
+public class SqlppArrayIndexRQGTest {
+ private static final Logger LOGGER = LogManager.getLogger(SqlppArrayIndexRQGTest.class);
+ private static final String TEST_CONFIG_FILE_NAME = "src/test/resources/cc.conf";
+ private static final String CONF_PROPERTY_LIMIT = "ArrayIndexRQGIT.limit";
+ private static final String CONF_PROPERTY_SEED = "ArrayIndexRQGIT.seed";
+ private static final String CONF_PROPERTY_JOIN = "ArrayIndexRQGIT.join";
+ private static final long CONF_PROPERTY_SEED_DEFAULT = System.currentTimeMillis();
+ private static final int CONF_PROPERTY_LIMIT_DEFAULT = 50;
+ private static final int CONF_PROPERTY_JOIN_DEFAULT = 25;
+ private static TestExecutor testExecutor;
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ private static final ObjectReader OBJECT_READER = OBJECT_MAPPER.readerFor(ObjectNode.class);
+
+ private static final int GROUP_MEMORY_MB = 4;
+ private static final int JOIN_MEMORY_MB = 4;
+ private static final int PROBE_DOCUMENT_LIMIT = 50;
+ private static final int QUERY_RESULT_LIMIT = 100;
+ private static final int JOIN_COUNT_LIMIT = 3;
+ private final TestInstance testInstance;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ testExecutor = new TestExecutor();
+ LangExecutionUtil.setUp(TEST_CONFIG_FILE_NAME, testExecutor);
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("DROP DATAVERSE TestDataverse IF EXISTS;\n");
+ sb.append("CREATE DATAVERSE TestDataverse;\n");
+ sb.append("USE TestDataverse;\n\n");
+ sb.append("CREATE TYPE TestType AS { _id: uuid };\n");
+ sb.append("CREATE DATASET ").append(BaseWisconsinTable.TABLE_NAME);
+ sb.append(" (TestType)\nPRIMARY KEY _id AUTOGENERATED;\n");
+ sb.append("LOAD DATASET ").append(BaseWisconsinTable.TABLE_NAME).append('\n');
+ sb.append("USING localfs").append(String.format("((\"path\"=\"%s\"),(\"format\"=\"adm\"));\n\n",
+ "asterix_nc1://" + BaseWisconsinTable.TABLE_FILE));
+ for (int i = 0; i < JOIN_COUNT_LIMIT; i++) {
+ sb.append("CREATE DATASET ProbeDataset").append(i + 1);
+ sb.append(" (TestType)\nPRIMARY KEY _id AUTOGENERATED;\n");
+ sb.append("INSERT INTO ProbeDataset").append(i + 1).append('\n');
+ sb.append("FROM ").append(BaseWisconsinTable.TABLE_NAME);
+ sb.append(" B\nSELECT VALUE B LIMIT ").append(PROBE_DOCUMENT_LIMIT).append(";\n");
+ }
+
+ LOGGER.debug("Now executing setup DDL:\n" + sb);
+ testExecutor.executeSqlppUpdateOrDdl(sb.toString(), TestCaseContext.OutputFormat.ADM);
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ LangExecutionUtil.tearDown();
+ }
+
+ private static long getConfigurationProperty(String propertyName, long defValue) {
+ String textValue = System.getProperty(propertyName);
+ if (textValue != null) {
+ try {
+ return Long.parseLong(textValue);
+
+ } catch (NumberFormatException e) {
+ LOGGER.warn(String.format("Cannot parse configuration property: %s. Will use default value: %d",
+ propertyName, defValue));
+ }
+ }
+ return defValue;
+ }
+
+ @Parameterized.Parameters(name = "ArrayIndexRQGIT {index}: {3}")
+ public static Collection<TestInstance> tests() {
+ List<TestInstance> testCases = new ArrayList<>();
+
+ long seed = getConfigurationProperty(CONF_PROPERTY_SEED, CONF_PROPERTY_SEED_DEFAULT);
+ int limit = (int) getConfigurationProperty(CONF_PROPERTY_LIMIT, CONF_PROPERTY_LIMIT_DEFAULT);
+ int join = (int) getConfigurationProperty(CONF_PROPERTY_JOIN, CONF_PROPERTY_JOIN_DEFAULT);
+ LOGGER.info(String.format("Testsuite configuration: -D%s=%d -D%s=%d -D%s=%d", CONF_PROPERTY_SEED, seed,
+ CONF_PROPERTY_LIMIT, limit, CONF_PROPERTY_JOIN, join));
+
+ // Initialize our random number generators.
+ BuilderContext context = new BuilderContext();
+ context.randomGenerator = new MersenneTwister(seed);
+ context.distBelow05 = new ExponentialDistribution(context.randomGenerator, 0.25, 1e-9);
+ context.distBelow1 = new ExponentialDistribution(context.randomGenerator, 0.5, 1e-9);
+ context.distEqual1 = new ExponentialDistribution(context.randomGenerator, 1.0, 1e-9);
+ context.distAbove1 = new ExponentialDistribution(context.randomGenerator, 1.5, 1e-9);
+ context.valueSupplierFactory = new ValueSupplierFactory(context.distBelow1, context.distEqual1,
+ context.distAbove1, context.randomGenerator);
+
+ for (int i = 0; i < limit; i++) {
+ TestInstance testCase = new TestInstance(i, i < join, context.randomGenerator.nextBoolean());
+ context.isJoin = testCase.isJoin;
+
+ // Build the array index first (implicitly, the schema for our dataset).
+ testCase.arrayIndex = buildArrayIndex(context);
+
+ // Build the dataset that corresponds to the array index.
+ testCase.arrayDataset = buildArrayDataset(context);
+
+ // Build the query that corresponds to the array index.
+ testCase.arrayQuery = buildArrayQuery(context);
+
+ // Finally, add the test case to our test cases.
+ testCases.add(testCase);
+ }
+
+ return testCases;
+ }
+
+ private static ArrayIndex buildArrayIndex(BuilderContext context) {
+ ArrayIndex.Builder indexBuilder = new ArrayIndex.Builder("testIndex", "IndexedDataset");
+
+ // Determine the number of fields and the depth of our array.
+ int totalNumberOfFields, depthOfArray;
+ do {
+ int numberOfAtomicPrefixes, numberOfFieldsInArray, numberOfAtomicSuffixes;
+ if (context.isJoin) {
+ // TODO (GLENN): Avoid performing joins with composite-atomic indexes for now.
+ numberOfAtomicPrefixes = 0; // (int) Math.round(context.distBelow05.sample());
+ numberOfFieldsInArray = Math.max(1, (int) Math.round(context.distBelow1.sample()));
+ numberOfAtomicSuffixes = 0; // (int) Math.round(context.distBelow05.sample());
+ } else {
+ numberOfAtomicPrefixes = (int) Math.round(context.distBelow05.sample());
+ numberOfFieldsInArray = Math.max(1, (int) Math.round(context.distBelow1.sample()));
+ numberOfAtomicSuffixes = (int) Math.round(context.distBelow05.sample());
+ }
+ indexBuilder.setNumberOfAtomicPrefixes(numberOfAtomicPrefixes);
+ indexBuilder.setNumberOfFieldsInArray(numberOfFieldsInArray);
+ indexBuilder.setNumberOfAtomicSuffixes(numberOfAtomicSuffixes);
+ indexBuilder.setIsArrayOfScalars(numberOfFieldsInArray == 1 && context.randomGenerator.nextBoolean());
+ depthOfArray = Math.max(1, (int) Math.round(context.distBelow1.sample()));
+ indexBuilder.setDepthOfArray(depthOfArray);
+ totalNumberOfFields = numberOfAtomicPrefixes + numberOfFieldsInArray + numberOfAtomicSuffixes;
+ } while (totalNumberOfFields > BaseWisconsinTable.NUMBER_OF_NON_GROUPING_FIELDS
+ || depthOfArray > BaseWisconsinTable.NUMBER_OF_GROUPING_FIELDS);
+
+ // Characterize how fields are generated (uniformly random).
+ indexBuilder.setValueSupplier(context.valueSupplierFactory.getCompleteArrayIndexValueSupplier());
+ context.arrayIndex = indexBuilder.build();
+ return context.arrayIndex;
+ }
+
+ private static ArrayDataset buildArrayDataset(BuilderContext context) {
+ ArrayDataset.Builder datasetBuilder = new ArrayDataset.Builder();
+ context.arrayIndex.getElements().forEach(datasetBuilder::addElement);
+ return datasetBuilder.build();
+ }
+
+ private static ArrayQuery buildArrayQuery(BuilderContext context) {
+ ArrayQuery.Builder queryBuilder = new ArrayQuery.Builder(context.arrayIndex);
+ queryBuilder.setLimitCount(QUERY_RESULT_LIMIT);
+
+ // Determine constants that should only be generated once.
+ int joinCount = Math.min(JOIN_COUNT_LIMIT, 1 + (int) Math.round(context.distBelow1.sample()));
+ int depthOfArray = context.arrayIndex.getArrayPath().size();
+ if (context.isJoin) {
+ // TODO: This is to avoid performing UNNEST joins on composite-atomic indexes. Refer to ASTERIXDB-2964.
+ // queryBuilder.setUnnestStepDepth(Math.min(depthOfArray, (int) Math.round(context.distBelow1.sample())));
+ queryBuilder.setUnnestStepDepth(0);
+ queryBuilder.setNumberOfJoins(joinCount);
+ if (joinCount == 1) {
+ // TODO: This is to avoid performing multiple UNNEST style explicit joins (falls under ASTERIXDB-2964).
+ queryBuilder.setNumberOfExplicitJoins(context.randomGenerator.nextBoolean() ? 1 : 0);
+ } else {
+ queryBuilder.setNumberOfExplicitJoins(0);
+ }
+ } else {
+ // TODO: This is to avoid specifying extra UNNESTs. Refer to ASTERIXDB-2962.
+ // queryBuilder.setUnnestStepDepth(Math.min(depthOfArray, (int) Math.round(context.distBelow1.sample())));
+ queryBuilder.setUnnestStepDepth(depthOfArray);
+ queryBuilder.setNumberOfJoins(0);
+ queryBuilder.setNumberOfExplicitJoins(0);
+ }
+
+ // Characterize the randomness in areas that occur more than once.
+ queryBuilder.setValueSupplier(context.valueSupplierFactory.getWorkingArrayQueryValueSupplier());
+ return queryBuilder.build();
+ }
+
+ public SqlppArrayIndexRQGTest(TestInstance testInstance) {
+ this.testInstance = testInstance;
+ }
+
+ @Test
+ public void test() throws Exception {
+ LOGGER.info("\n" + testInstance);
+ LOGGER.debug("Now executing test setup:\n" + testInstance.getTestSetup());
+ testExecutor.executeSqlppUpdateOrDdl(testInstance.getTestSetup(), TestCaseContext.OutputFormat.ADM);
+
+ // In addition to the results, we want the query plan as well.
+ String nonOptimizedQueryPrefix = "SET `compiler.arrayindex` \"false\";\n";
+ String optimizedQueryPrefix = "SET `compiler.arrayindex` \"true\";\n";
+ TestCase.CompilationUnit.Parameter planParameter = new TestCase.CompilationUnit.Parameter();
+ planParameter.setName("optimized-logical-plan");
+ planParameter.setValue("true");
+ planParameter.setType(ParameterTypeEnum.STRING);
+
+ try (InputStream notOptimizedResultStream =
+ testExecutor.executeQueryService(nonOptimizedQueryPrefix + testInstance.getTestQuery(),
+ TestCaseContext.OutputFormat.ADM, testExecutor.getEndpoint(Servlets.QUERY_SERVICE),
+ Collections.singletonList(planParameter), true, StandardCharsets.UTF_8);
+ InputStream optimizedResultStream =
+ testExecutor.executeQueryService(optimizedQueryPrefix + testInstance.getTestQuery(),
+ TestCaseContext.OutputFormat.ADM, testExecutor.getEndpoint(Servlets.QUERY_SERVICE),
+ Collections.singletonList(planParameter), true, StandardCharsets.UTF_8)) {
+ LOGGER.debug("Now executing query:\n" + testInstance.getTestQuery());
+
+ // Verify that the optimized result is the same as the non optimized result.
+ ObjectNode r1 = OBJECT_READER.readValue(notOptimizedResultStream);
+ ObjectNode r2 = OBJECT_READER.readValue(optimizedResultStream);
+ boolean doesR1HaveErrors = (r1.get("errors") != null);
+ boolean doesR2HaveErrors = (r2.get("errors") != null);
+
+ if (r1.get("results") == null || r2.get("results") == null) {
+ LOGGER.error("Results not found. Errors are:\n"
+ + (doesR1HaveErrors ? ("Non Optimized Error: " + r1.get("errors") + "\n")
+ : ("No errors thrown from the non-optimized query!\n"))
+ + (doesR2HaveErrors ? ("Optimized Error: " + r2.get("errors") + "\n")
+ : ("No errors thrown from the optimized query!\n")));
+ if (!doesR1HaveErrors && doesR2HaveErrors) {
+ Assert.fail("Optimized query resulted in an error.");
+ } else {
+ LOGGER.error("Both queries have resulted in an error (not logging issue w/ query gen itself).");
+ }
+
+ } else if (!r1.get("results").equals(r2.get("results"))) {
+ LOGGER.error("Non optimized query returned: " + r1.get("results") + "\n");
+ LOGGER.error("Optimized query returned: " + r2.get("results") + "\n");
+ Assert.fail("Optimized result is not equal to the non-optimized result.");
+
+ } else {
+ Iterator<JsonNode> results = r1.get("results").elements();
+ if (!results.hasNext()) {
+ LOGGER.error("Query has produced no results!");
+ } else {
+ LOGGER.debug("First result of query is: " + results.next().toString());
+ }
+ }
+
+ // Verify that the array index is being used by the "optimized" query.
+ String indexName = testInstance.arrayIndex.getIndexName();
+ if (!doesR1HaveErrors && !doesR2HaveErrors
+ && !r2.get("plans").get("optimizedLogicalPlan").asText().contains(indexName)) {
+ LOGGER.error("Optimized query plan: \n" + r2.get("plans").get("optimizedLogicalPlan").asText());
+ Assert.fail("Index " + indexName + " is not being used.");
+ }
+ }
+ }
+
+ private static class TestInstance {
+ private final int testCaseID;
+ private final boolean isJoin;
+ private final boolean isLoadFirst;
+
+ private ArrayDataset arrayDataset;
+ private ArrayIndex arrayIndex;
+ private ArrayQuery arrayQuery;
+
+ private String getTestSetup() {
+ String compilerSetStmt = "SET `compiler.groupmemory` \"" + GROUP_MEMORY_MB + "MB\";\n"
+ + "SET `compiler.joinmemory` \"" + JOIN_MEMORY_MB + "MB\";\n";
+ String dropDatasetStmt = "DROP DATASET IndexedDataset IF EXISTS;\n";
+ String createDatasetStmt = "CREATE DATASET IndexedDataset (TestType)\nPRIMARY KEY _id AUTOGENERATED;\n";
+ String leadingStatements = compilerSetStmt + "USE TestDataverse;\n" + dropDatasetStmt + createDatasetStmt;
+ if (isLoadFirst) {
+ return leadingStatements + "INSERT INTO IndexedDataset (\n" + arrayDataset + "\n);\n" + arrayIndex;
+ } else {
+ return leadingStatements + arrayIndex + "INSERT INTO IndexedDataset (\n" + arrayDataset + "\n);\n";
+ }
+ }
+
+ private String getTestQuery() {
+ String groupMemStmt = "SET `compiler.groupmemory` \"" + GROUP_MEMORY_MB + "MB\";\n";
+ String joinMemStmt = "SET `compiler.joinmemory` \"" + JOIN_MEMORY_MB + "MB\";\n";
+ String dataverseUseStmt = "USE TestDataverse;\n";
+ return groupMemStmt + joinMemStmt + dataverseUseStmt + arrayQuery;
+ }
+
+ public TestInstance(int testCaseID, boolean isJoin, boolean isLoadFirst) {
+ this.testCaseID = testCaseID;
+ this.isJoin = isJoin;
+ this.isLoadFirst = isLoadFirst;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("-------------------------------------------------------\n");
+ sb.append("Test Case Name: #").append(testCaseID).append('\n');
+ sb.append("Test Type: ").append(isJoin ? "JOIN" : "NON-JOIN").append('\n');
+ sb.append("Test Order: ");
+ sb.append(isLoadFirst ? "INSERT -> CREATE INDEX" : "CREATE INDEX -> INSERT").append(" -> QUERY\n");
+ sb.append("Indexed Elements:\n");
+ arrayIndex.getElements().forEach(e -> {
+ sb.append("\tElement #").append(e.elementPosition).append(":\n");
+ sb.append("\t\tKind: ").append(e.kind).append('\n');
+ e.unnestList.forEach(f -> sb.append("\t\tUNNEST Field: ").append(f).append('\n'));
+ e.projectList.forEach(f -> sb.append("\t\tPROJECT Field: ").append(f).append('\n'));
+ });
+ sb.append("Indexed Query: \n");
+ arrayQuery.getFromExprs().forEach(e -> {
+ sb.append("\tStarting FROM Expr:\n");
+ sb.append("\t\tDataset Name: ").append(e.datasetName).append('\n');
+ sb.append("\t\tAs Alias: ").append(e.alias).append('\n');
+ });
+ arrayQuery.getUnnestSteps().forEach(e -> {
+ sb.append("\tUNNEST Step:\n");
+ sb.append("\t\tSource Alias: ").append(e.sourceAlias).append('\n');
+ sb.append("\t\tArray Field: ").append(e.arrayField).append('\n');
+ sb.append("\t\tAs Alias: ").append(e.alias).append('\n');
+ });
+ arrayQuery.getJoinSteps().forEach(e -> {
+ sb.append("\tJoin Step:\n");
+ sb.append("\t\tSubquery FROM Expr:\n");
+ sb.append("\t\t\tDataset Name: ").append(e.subqueryFromExpr.datasetName).append('\n');
+ sb.append("\t\t\tAs Alias: ").append(e.subqueryFromExpr.alias).append('\n');
+ for (UnnestStep unnestStep : e.subqueryUnnestSteps) {
+ sb.append("\t\tSubquery UNNEST Step:\n");
+ sb.append("\t\t\tSource Alias: ").append(unnestStep.sourceAlias).append('\n');
+ sb.append("\t\t\tArray Field: ").append(unnestStep.arrayField).append('\n');
+ sb.append("\t\t\tAs Alias: ").append(unnestStep.alias).append('\n');
+ }
+ });
+ arrayQuery.getWhereConjuncts().forEach(e -> printConjunct(sb, e, 1));
+ arrayQuery.getSelectExprs().forEach(e -> {
+ sb.append("\tSelect Expr:\n");
+ sb.append("\t\tExpr: ").append(e.expr).append('\n');
+ sb.append("\t\tAs Alias: ").append(e.alias).append('\n');
+ });
+ sb.append("-------------------------------------------------------\n");
+ return sb.toString();
+ }
+
+ private static void printConjunct(StringBuilder sb, Conjunct conjunct, int depth) {
+ String localTabPrefix = "\t".repeat(depth);
+ if (conjunct instanceof SimpleConjunct) {
+ SimpleConjunct simpleConjunct = (SimpleConjunct) conjunct;
+ sb.append(localTabPrefix).append("WHERE Conjunct (Simple):\n");
+ localTabPrefix = localTabPrefix + "\t";
+ sb.append(localTabPrefix).append("Expression 1: ").append(simpleConjunct.expressionOne).append('\n');
+ sb.append(localTabPrefix).append("Expression 2: ").append(simpleConjunct.expressionTwo).append('\n');
+ sb.append(localTabPrefix).append("Expression 3: ").append(simpleConjunct.expressionThree).append('\n');
+ sb.append(localTabPrefix).append("Operator: ").append(simpleConjunct.operator).append('\n');
+ sb.append(localTabPrefix).append("Annotation: ").append(simpleConjunct.annotation).append('\n');
+
+ } else if (conjunct instanceof QuantifiedConjunct) {
+ QuantifiedConjunct quantifiedConjunct = (QuantifiedConjunct) conjunct;
+ sb.append(localTabPrefix).append("WHERE Conjunct (Quantified):\n");
+ localTabPrefix = localTabPrefix + "\t";
+ for (int i = 0; i < quantifiedConjunct.arraysToQuantify.size(); i++) {
+ String arrayToQuantify = quantifiedConjunct.arraysToQuantify.get(i);
+ String quantifiedVar = quantifiedConjunct.quantifiedVars.get(i);
+ sb.append(localTabPrefix).append("Quantified Array: ").append(arrayToQuantify).append('\n');
+ sb.append(localTabPrefix).append('\t').append("As Alias: ").append(quantifiedVar).append('\n');
+ }
+ quantifiedConjunct.conjuncts.forEach(e -> printConjunct(sb, e, depth + 1));
+
+ } else {
+ ExistsConjunct existsConjunct = (ExistsConjunct) conjunct;
+ ArrayQuery.FromExpr fromExpr = existsConjunct.fromExpr;
+ sb.append(localTabPrefix).append("WHERE Conjunct (EXISTS):\n");
+ localTabPrefix = localTabPrefix + "\t";
+ sb.append(localTabPrefix).append("Subquery FROM Expr:\n");
+ sb.append(localTabPrefix).append("\t").append("FROM Expr: ").append(fromExpr.datasetName).append('\n');
+ sb.append(localTabPrefix).append("\t").append("As Alias: ").append(fromExpr.alias).append('\n');
+ for (UnnestStep e : existsConjunct.unnestSteps) {
+ sb.append(localTabPrefix).append("Subquery UNNEST Steps:\n");
+ sb.append(localTabPrefix).append('\t').append("Source Alias: ").append(e.sourceAlias).append('\n');
+ sb.append(localTabPrefix).append('\t').append("Array Field: ").append(e.arrayField).append('\n');
+ sb.append(localTabPrefix).append('\t').append("As Alias: ").append(e.alias).append('\n');
+ }
+ sb.append(localTabPrefix).append("Subquery WHERE Conjuncts:\n");
+ existsConjunct.conjuncts.forEach(e -> printConjunct(sb, e, depth + 1));
+ }
+ }
+ }
+
+ private static class BuilderContext {
+ ValueSupplierFactory valueSupplierFactory;
+ ExponentialDistribution distBelow05;
+ ExponentialDistribution distBelow1;
+ ExponentialDistribution distEqual1;
+ ExponentialDistribution distAbove1;
+ RandomGenerator randomGenerator;
+ ArrayIndex arrayIndex;
+ boolean isJoin;
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ValueSupplierFactory.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ValueSupplierFactory.java
new file mode 100644
index 0000000..efacf78
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/array/ValueSupplierFactory.java
@@ -0,0 +1,274 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.test.array;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.asterix.test.array.ArrayQuery.Builder.ValueSupplier;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.math3.distribution.ExponentialDistribution;
+import org.apache.commons.math3.random.RandomGenerator;
+
+public class ValueSupplierFactory {
+ private final ExponentialDistribution distBelow1;
+ private final ExponentialDistribution distEqual1;
+ private final ExponentialDistribution distAbove1;
+ private final RandomGenerator randomGenerator;
+
+ public ValueSupplierFactory(ExponentialDistribution distBelow1, ExponentialDistribution distEqual1,
+ ExponentialDistribution distAbove1, RandomGenerator randomGenerator) {
+ this.distBelow1 = distBelow1;
+ this.distEqual1 = distEqual1;
+ this.distAbove1 = distAbove1;
+ this.randomGenerator = randomGenerator;
+ }
+
+ private class BaseArrayIndexValueSupplier extends ArrayIndex.Builder.ValueSupplier {
+ private final Set<BaseWisconsinTable.Field> consumedFields = new LinkedHashSet<>();
+
+ @Override
+ public BaseWisconsinTable.Field getAtomicBaseField() {
+ BaseWisconsinTable.Field field;
+ do {
+ int index = BaseWisconsinTable.NUMBER_OF_GROUPING_FIELDS
+ + randomGenerator.nextInt(BaseWisconsinTable.NUMBER_OF_NON_GROUPING_FIELDS);
+ field = BaseWisconsinTable.Field.values()[index];
+ } while (consumedFields.contains(field) || field.fieldType != BaseWisconsinTable.Field.Type.BIGINT);
+ consumedFields.add(field);
+ return field;
+ }
+
+ @Override
+ public BaseWisconsinTable.Field getArrayBaseField() {
+ BaseWisconsinTable.Field field;
+ do {
+ int index = BaseWisconsinTable.NUMBER_OF_GROUPING_FIELDS
+ + randomGenerator.nextInt(BaseWisconsinTable.NUMBER_OF_NON_GROUPING_FIELDS);
+ field = BaseWisconsinTable.Field.values()[index];
+ } while (consumedFields.contains(field));
+ consumedFields.add(field);
+ return field;
+ }
+
+ @Override
+ public List<String> getFieldName(BaseWisconsinTable.Field baseField) {
+ List<String> fieldName = new ArrayList<>();
+ if (randomGenerator.nextBoolean()) {
+ int index = randomGenerator.nextInt(ArrayDataset.CONTAINER_OBJECT_NAMES.length);
+ fieldName.add(ArrayDataset.CONTAINER_OBJECT_NAMES[index]);
+ }
+ fieldName.add(baseField.fieldName);
+ if (randomGenerator.nextBoolean()) {
+ int index = randomGenerator.nextInt(ArrayDataset.CONTAINED_OBJECT_NAMES.length);
+ fieldName.add(ArrayDataset.CONTAINED_OBJECT_NAMES[index]);
+ }
+ return fieldName;
+ }
+
+ @Override
+ public List<String> getGroupFieldName(int nestingLevel) {
+ List<String> fieldName = new ArrayList<>();
+ if (randomGenerator.nextBoolean()) {
+ int index = randomGenerator.nextInt(ArrayDataset.CONTAINER_OBJECT_NAMES.length);
+ fieldName.add(ArrayDataset.CONTAINER_OBJECT_NAMES[index]);
+ }
+ fieldName.add("nesting_" + nestingLevel);
+ if (randomGenerator.nextBoolean()) {
+ int index = randomGenerator.nextInt(ArrayDataset.CONTAINED_OBJECT_NAMES.length);
+ fieldName.add(ArrayDataset.CONTAINED_OBJECT_NAMES[index]);
+ }
+ return fieldName;
+ }
+ }
+
+ private class BaseArrayQueryValueSupplier extends ValueSupplier {
+ @Override
+ public String getJoinType() {
+ return ((int) Math.round(distEqual1.sample()) == 0) ? "INNER" : "LEFT OUTER";
+ }
+
+ @Override
+ public String getOperatorForJoin() {
+ boolean isEquiJoin = randomGenerator.nextBoolean();
+ switch (isEquiJoin ? 0 : (1 + randomGenerator.nextInt(4))) {
+ case 0:
+ return "=";
+ case 1:
+ return "<";
+ case 2:
+ return ">";
+ case 3:
+ return "<=";
+ default:
+ return ">=";
+ }
+ }
+
+ @Override
+ public String getOperatorForConstant() {
+ boolean isEqualityPredicate = distBelow1.sample() > 2;
+ switch (isEqualityPredicate ? 0 : (1 + randomGenerator.nextInt(4))) {
+ case 0:
+ return "=";
+ case 1:
+ return "<";
+ case 2:
+ return ">";
+ case 3:
+ return "<=";
+ default:
+ return ">=";
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Pair<String, String> getRangeFromDomain(BaseWisconsinTable.Domain domain) {
+ if (domain.minimum instanceof Integer && domain.maximum instanceof Integer) {
+ int domainMinimum = (int) domain.minimum, domainMaximum = (int) domain.maximum;
+ return Pair.of(String.valueOf(domainMinimum), String.valueOf(domainMaximum));
+
+ } else if (domain.minimum instanceof Character && domain.maximum instanceof Character) {
+ int domainMinimum = (char) domain.minimum, domainMaximum = (char) domain.maximum;
+ return Pair.of("\"" + (char) domainMinimum + "\"", "\"" + (char) domainMaximum + "\"");
+
+ } else if (domain.minimum instanceof Double && domain.maximum instanceof Double) {
+ int domainMinimum = (int) ((double) domain.minimum - 0.5);
+ int domainMaximum = (int) ((double) domain.maximum - 0.5);
+ return Pair.of(String.valueOf(domainMinimum), String.valueOf(domainMaximum));
+
+ } else {
+ throw new UnsupportedOperationException("Unknown / unsupported type for domain value.");
+ }
+ }
+
+ @Override
+ public boolean getIsBetweenConjunct() {
+ return randomGenerator.nextBoolean();
+ }
+
+ @Override
+ public String getQuantifier() {
+ return (distBelow1.sample() < 1) ? "SOME" : "SOME AND EVERY";
+ }
+
+ @Override
+ public boolean getIsConditionOnUnnest() {
+ return randomGenerator.nextBoolean();
+ }
+
+ @Override
+ public boolean getIsConstantConditionWithJoins() {
+ return distBelow1.sample() > 1;
+ }
+
+ @Override
+ public boolean getIsCrossProductOnProbes() {
+ return distBelow1.sample() > 1;
+ }
+
+ @Override
+ public boolean getIsUseNestedQuantification() {
+ return randomGenerator.nextBoolean();
+ }
+
+ @Override
+ public List<ArrayQuery.UnnestStep> getExtraUnnestSteps(String alias) {
+ List<ArrayQuery.UnnestStep> unnestSteps = new ArrayList<>();
+ int numberOfAdditionalGroups = ArrayDataset.ADDITIONAL_GROUPS.length;
+ for (int i = 0; i < randomGenerator.nextInt(numberOfAdditionalGroups + 1); i++) {
+ unnestSteps.add(new ArrayQuery.UnnestStep(alias, ArrayDataset.ADDITIONAL_GROUPS[i], null));
+ }
+ return unnestSteps;
+ }
+
+ @Override
+ public List<ArrayQuery.Conjunct> getExtraConjuncts(String alias) {
+ List<ArrayQuery.Conjunct> extraConjuncts = new ArrayList<>();
+ if (distBelow1.sample() > 1) {
+ String variableExpr = String.format("%s.%s", alias, ArrayDataset.ADDITIONAL_FIELDS[0]);
+ String value = ArrayDataset.VALUES_FOR_ADDITIONAL_FIELDS[0];
+ extraConjuncts.add(new ArrayQuery.SimpleConjunct(variableExpr, value, "=", null));
+ }
+ if (distBelow1.sample() > 1) {
+ String variableExpr = String.format("%s.%s", alias, ArrayDataset.ADDITIONAL_FIELDS[1]);
+ String value = ArrayDataset.VALUES_FOR_ADDITIONAL_FIELDS[1];
+ extraConjuncts.add(new ArrayQuery.SimpleConjunct(variableExpr, value, "=", null));
+ }
+ return extraConjuncts;
+ }
+
+ @Override
+ public List<ArrayQuery.Conjunct> getExtraQuantifiersAndConjuncts(List<String> arraysToQuantify,
+ List<String> quantifiedVars, String alias) {
+ List<ArrayQuery.Conjunct> extraConjuncts = new ArrayList<>();
+ if (distBelow1.sample() > 1) {
+ int i = randomGenerator.nextInt(ArrayDataset.VALUES_FOR_ADDITIONAL_GROUPS.length);
+ String valueExpr = ArrayDataset.VALUES_FOR_ADDITIONAL_GROUPS[i];
+ arraysToQuantify.add(String.format("%s.%s", alias, ArrayDataset.ADDITIONAL_GROUPS[0]));
+ quantifiedVars.add("W1");
+ extraConjuncts.add(new ArrayQuery.SimpleConjunct("W1", valueExpr, "=", null));
+ }
+ if (distBelow1.sample() > 1) {
+ int i = randomGenerator.nextInt(ArrayDataset.VALUES_FOR_ADDITIONAL_GROUPS.length);
+ String valueExpr = ArrayDataset.VALUES_FOR_ADDITIONAL_GROUPS[i];
+ arraysToQuantify.add(String.format("%s.%s", alias, ArrayDataset.ADDITIONAL_GROUPS[1]));
+ quantifiedVars.add("W2");
+ extraConjuncts.add(new ArrayQuery.SimpleConjunct("W2", valueExpr, "=", null));
+ }
+ return extraConjuncts;
+ }
+ }
+
+ public ArrayIndex.Builder.ValueSupplier getCompleteArrayIndexValueSupplier() {
+ return new BaseArrayIndexValueSupplier();
+ }
+
+ public ValueSupplier getCompleteArrayQueryValueSupplier() {
+ return new BaseArrayQueryValueSupplier();
+ }
+
+ /**
+ * @return Return a supplier that generates queries that get picked up and index-accelerated by the optimizer.
+ */
+ public ValueSupplier getWorkingArrayQueryValueSupplier() {
+ return new BaseArrayQueryValueSupplier() {
+ @Override
+ public boolean getIsConditionOnUnnest() {
+ // TODO: This is to avoid specifying extra UNNESTs. Refer to ASTERIXDB-2962.
+ return true;
+ }
+
+ @Override
+ public boolean getIsConstantConditionWithJoins() {
+ // TODO: This is to avoid specifying extra conjuncts in the presence of joins.
+ return false;
+ }
+
+ @Override
+ public boolean getIsCrossProductOnProbes() {
+ // TODO: This is to avoid performing a cross product with probes. Refer to ASTERIXDB-2966.
+ return false;
+ }
+ };
+ }
+}
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query8.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query8.plan
index 4d5a668..ea7ceef 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query8.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query8.plan
@@ -30,8 +30,9 @@
-- BROADCAST_EXCHANGE |PARTITIONED|
-- RUNNING_AGGREGATE |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN (TestDataverse.Dataset2) |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (TestDataverse.Dataset2) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query9.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query9.plan
index 5e62aa2..b47e122 100644
--- a/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query9.plan
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/array-index/atomic-and-array-queries/query9.plan
@@ -39,8 +39,9 @@
-- BROADCAST_EXCHANGE |PARTITIONED|
-- RUNNING_AGGREGATE |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN (TestDataverse.Dataset2) |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (TestDataverse.Dataset2) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/SecondaryArrayIndexBTreeOperationsHelper.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/SecondaryArrayIndexBTreeOperationsHelper.java
index 5d80dca..32138dc 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/SecondaryArrayIndexBTreeOperationsHelper.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/SecondaryArrayIndexBTreeOperationsHelper.java
@@ -22,11 +22,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.Queue;
-import java.util.Stack;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -571,8 +573,8 @@
}
class LoadingJobBuilder implements ArrayIndexUtil.ActionCounterCommandExecutor {
- private final Stack<RecordDescriptor> recDescStack = evalFactoryAndRecDescStackBuilder.buildRecDescStack();
- private final Stack<List<IScalarEvaluatorFactory>> sefStack =
+ private final Deque<RecordDescriptor> recDescStack = evalFactoryAndRecDescStackBuilder.buildRecDescStack();
+ private final Deque<List<IScalarEvaluatorFactory>> sefStack =
evalFactoryAndRecDescStackBuilder.buildEvalFactoryStack();
private final JobSpecification spec;
@@ -595,9 +597,9 @@
@Override
public void executeActionOnFirstArrayStep() throws AlgebricksException {
+ IScalarEvaluatorFactory sef = sefStack.pop().get(0);
nextRecDesc = recDescStack.pop();
- targetOpRef
- .setValue(createUnnestOp(spec, workingRecDesc.getFieldCount(), sefStack.pop().get(0), nextRecDesc));
+ targetOpRef.setValue(createUnnestOp(spec, workingRecDesc.getFieldCount(), sef, nextRecDesc));
connectAndMoveToNextOp();
}
@@ -611,45 +613,57 @@
workingRecDesc.getFieldCount(), sefStack.pop(), nextRecDesc));
connectAndMoveToNextOp();
+ IScalarEvaluatorFactory sef = sefStack.pop().get(0);
nextRecDesc = recDescStack.pop();
- targetOpRef
- .setValue(createUnnestOp(spec, workingRecDesc.getFieldCount(), sefStack.pop().get(0), nextRecDesc));
+ targetOpRef.setValue(createUnnestOp(spec, workingRecDesc.getFieldCount(), sef, nextRecDesc));
connectAndMoveToNextOp();
}
@Override
- public void executeActionOnFinalArrayStep(int numberOfActionsAlreadyPerformed) {
+ public void executeActionOnFinalArrayStep(int numberOfActionsAlreadyPerformed) throws AlgebricksException {
+ nextRecDesc = recDescStack.pop();
targetOpRef.setValue(createFinalAssignOp(spec, numberOfActionsAlreadyPerformed < 2,
- workingRecDesc.getFieldCount(), sefStack.pop(), recDescStack.pop()));
+ workingRecDesc.getFieldCount(), sefStack.pop(), nextRecDesc));
connectAndMoveToNextOp();
}
}
class EvalFactoryAndRecDescStackBuilder {
- private final Stack<IScalarEvaluatorFactory> unnestEvalFactories = new Stack<>();
- private final List<IScalarEvaluatorFactory> atomicSKEvalFactories = new ArrayList<>();
- private final List<IScalarEvaluatorFactory> finalArraySKEvalFactories = new ArrayList<>();
+ class EvalFactoryAndPosition {
+ final IScalarEvaluatorFactory scalarEvaluatorFactory;
+ final int position;
+
+ EvalFactoryAndPosition(IScalarEvaluatorFactory scalarEvaluatorFactory) {
+ this.scalarEvaluatorFactory = scalarEvaluatorFactory;
+ this.position = workingPosition++;
+ }
+ }
+
+ private final Deque<EvalFactoryAndPosition> unnestEvalFactories = new ArrayDeque<>();
+ private final List<EvalFactoryAndPosition> atomicSKEvalFactories = new ArrayList<>();
+ private final List<EvalFactoryAndPosition> finalArraySKEvalFactories = new ArrayList<>();
private final Queue<IAType> unnestEvalTypes = new LinkedList<>();
private final List<IAType> atomicSKEvalTypes = new ArrayList<>();
- private IScalarEvaluatorFactory filterEvalFactory = null;
+ private EvalFactoryAndPosition filterEvalFactory = null;
private IAType filterEvalType = null;
+ private int workingPosition = 0;
public void addAtomicSK(IScalarEvaluatorFactory sef, IAType type) {
- atomicSKEvalFactories.add(sef);
+ atomicSKEvalFactories.add(new EvalFactoryAndPosition(sef));
atomicSKEvalTypes.add(type);
}
public void addFilter(IScalarEvaluatorFactory sef, IAType type) {
- filterEvalFactory = sef;
+ filterEvalFactory = new EvalFactoryAndPosition(sef);
filterEvalType = type;
}
public void addFinalArraySK(IScalarEvaluatorFactory sef) {
- finalArraySKEvalFactories.add(sef);
+ finalArraySKEvalFactories.add(new EvalFactoryAndPosition(sef));
}
public void addUnnest(IScalarEvaluatorFactory sef, IAType type) {
- unnestEvalFactories.push(sef);
+ unnestEvalFactories.push(new EvalFactoryAndPosition(sef));
unnestEvalTypes.add(type);
}
@@ -669,8 +683,8 @@
* [ final ASSIGN SEFs -- array SKs (record accessors) ---------------- ]
* </pre>
*/
- public Stack<List<IScalarEvaluatorFactory>> buildEvalFactoryStack() {
- Stack<List<IScalarEvaluatorFactory>> resultant = new Stack<>();
+ public Deque<List<IScalarEvaluatorFactory>> buildEvalFactoryStack() {
+ Deque<List<EvalFactoryAndPosition>> resultant = new ArrayDeque<>();
resultant.push(finalArraySKEvalFactories);
int initialUnnestEvalFactorySize = unnestEvalFactories.size();
for (int i = 0; i < initialUnnestEvalFactorySize - 1; i++) {
@@ -682,12 +696,22 @@
resultant.push(new ArrayList<>());
}
}
+
+ // Sort the SEFs according to the index order.
resultant.peek().addAll(atomicSKEvalFactories);
+ List<EvalFactoryAndPosition> reorderedSEFs = new ArrayList<>(Objects.requireNonNull(resultant.peek()));
+ reorderedSEFs.sort(Comparator.comparingInt(s -> s.position));
+ resultant.pop();
+ resultant.push(reorderedSEFs);
+
+ // Append our filter eval factory last.
if (filterEvalFactory != null) {
resultant.peek().add(filterEvalFactory);
}
resultant.push(Collections.singletonList(unnestEvalFactories.pop()));
- return resultant;
+ return resultant.stream()
+ .map(l -> l.stream().map(s -> s.scalarEvaluatorFactory).collect(Collectors.toList()))
+ .collect(Collectors.toCollection(ArrayDeque::new));
}
/**
@@ -704,9 +728,9 @@
* [ secondary record descriptor ------------------------------------- ]
* </pre>
*/
- public Stack<RecordDescriptor> buildRecDescStack() throws AlgebricksException {
+ public Deque<RecordDescriptor> buildRecDescStack() throws AlgebricksException {
int initialUnnestEvalTypesSize = unnestEvalTypes.size();
- Deque<RecordDescriptor> resultantAsDeque = new ArrayDeque<>();
+ Deque<RecordDescriptor> resultant = new ArrayDeque<>();
RecordDescriptor recDescBeforeFirstUnnest = primaryRecDesc;
if (dataset.hasMetaPart()) {
ISerializerDeserializer[] fields = new ISerializerDeserializer[primaryRecDesc.getFieldCount() - 1];
@@ -717,15 +741,13 @@
}
recDescBeforeFirstUnnest = new RecordDescriptor(fields, typeTraits);
}
- resultantAsDeque.addFirst(recDescBeforeFirstUnnest);
- resultantAsDeque.addFirst(createUnnestRecDesc(recDescBeforeFirstUnnest, unnestEvalTypes.remove()));
+ resultant.addLast(recDescBeforeFirstUnnest);
+ resultant.addLast(createUnnestRecDesc(recDescBeforeFirstUnnest, unnestEvalTypes.remove()));
for (int i = 0; i < initialUnnestEvalTypesSize - 1; i++) {
- resultantAsDeque.addFirst(createAssignRecDesc(resultantAsDeque.getFirst(), i == 0));
- resultantAsDeque.addFirst(createUnnestRecDesc(resultantAsDeque.getFirst(), unnestEvalTypes.remove()));
+ resultant.addLast(createAssignRecDesc(resultant.getLast(), i == 0));
+ resultant.addLast(createUnnestRecDesc(resultant.getLast(), unnestEvalTypes.remove()));
}
- resultantAsDeque.addFirst(secondaryRecDesc);
- Stack<RecordDescriptor> resultant = new Stack<>();
- resultant.addAll(resultantAsDeque);
+ resultant.addLast(secondaryRecDesc);
return resultant;
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
index 8a9236e..b48e0a9 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
@@ -203,6 +203,7 @@
while (!typeStack.isEmpty()) {
Triple<IAType, String, Boolean> typeFromStack = typeStack.pop();
IAType typeIntermediate = unnestArrayType(typeFromStack.first, typeFromStack.third);
+ typeIntermediate = TypeComputeUtils.getActualType(typeIntermediate);
ARecordType recordType = (ARecordType) typeIntermediate;
IAType[] fieldTypes = recordType.getFieldTypes().clone();
fieldTypes[recordType.getFieldIndex(typeFromStack.second)] = resultant;