You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by pr...@apache.org on 2025/09/09 10:47:04 UTC

(asterixdb) branch master updated: [ASTERIXDB-3632] Fix NPEs in Index Advisor and add error handling for missing samples

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

preetham02 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new f9c6fe50c6 [ASTERIXDB-3632] Fix NPEs in Index Advisor and add error handling for missing samples
f9c6fe50c6 is described below

commit f9c6fe50c6c2f87b3ee6d32fdca321095df4233f
Author: preetham0202 <pr...@couchbase.com>
AuthorDate: Fri Aug 29 16:55:46 2025 +0530

    [ASTERIXDB-3632] Fix NPEs in Index Advisor and add error handling for missing samples
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Ext-ref: MB-66492
    
    Details:
    This patch addresses several corner cases in the Index Advisor:
    
    - Fixes null pointer exceptions that occur in scenarios such as:
      - Collections with secondary primary indexes
      - Cases where CBO bails out
    - Adds proper error handling when an `ADVISE` query is issued without CBO enabled
    - Introduces error reporting for collections that have no samples, suggesting the use of ANALYSE SAMPLE before issuing advise
    
    Change-Id: I346728dd634934416d7115a06ab15572b5a98854
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20282
    Reviewed-by: Ali Alsuliman <al...@gmail.com>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Preetham Poluparthi <pr...@apache.org>
    Tested-by: Preetham Poluparthi <pr...@apache.org>
---
 .../rules/am/IntroduceJoinAccessMethodRule.java    |  2 +-
 .../rules/am/IntroduceSelectAccessMethodRule.java  |  2 +-
 .../optimizer/rules/cbo/EnumerateJoinsRule.java    | 50 +++++++++++++--
 .../rules/cbo/indexadvisor/AdviseIndexRule.java    |  9 +++
 .../cbo/indexadvisor/AdvisorConditionParser.java   | 72 ++++++++++++----------
 .../rules/cbo/indexadvisor/FakeIndexProvider.java  |  8 ++-
 .../apache/asterix/api/common/APIFramework.java    |  8 +++
 .../algebricks/core/algebra/base/IndexAdvisor.java |  1 -
 .../apache/hyracks/api/exceptions/ErrorCode.java   |  3 +-
 .../src/main/resources/errormsg/en.properties      |  3 +-
 10 files changed, 116 insertions(+), 42 deletions(-)

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 5bc1e90b5d..09cf843592 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
@@ -123,7 +123,7 @@ public class IntroduceJoinAccessMethodRule extends AbstractIntroduceAccessMethod
             throws AlgebricksException {
         clear();
         boolean adviseIndex = context.getIndexAdvisor().getAdvise();
-        if (adviseIndex) {
+        if (adviseIndex && context.getIndexAdvisor().getFakeIndexProvider() != null) {
             setMetadataIndexDeclarations(context, (IIndexProvider) context.getIndexAdvisor().getFakeIndexProvider());
         } else {
             setMetadataIndexDeclarations(context, (IIndexProvider) context.getMetadataProvider());
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
index 56ee034d19..df9fb2cf5a 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceSelectAccessMethodRule.java
@@ -138,7 +138,7 @@ public class IntroduceSelectAccessMethodRule extends AbstractIntroduceAccessMeth
         clear();
 
         boolean adviseIndex = context.getIndexAdvisor().getAdvise();
-        if (adviseIndex) {
+        if (adviseIndex && context.getIndexAdvisor().getFakeIndexProvider() != null) {
             setMetadataIndexDeclarations(context, (IIndexProvider) context.getIndexAdvisor().getFakeIndexProvider());
         } else {
             setMetadataIndexDeclarations(context, (IIndexProvider) context.getMetadataProvider());
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
index 6e4208d14e..b02301f260 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java
@@ -28,6 +28,8 @@ import java.util.Map;
 
 import org.apache.asterix.common.annotations.IndexedNLJoinExpressionAnnotation;
 import org.apache.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation;
+import org.apache.asterix.common.metadata.DatasetFullyQualifiedName;
+import org.apache.asterix.metadata.declared.DatasetDataSource;
 import org.apache.asterix.metadata.declared.IIndexProvider;
 import org.apache.asterix.metadata.entities.Index;
 import org.apache.asterix.optimizer.rules.cbo.indexadvisor.AdvisorPlanParser;
@@ -71,6 +73,7 @@ import org.apache.hyracks.algebricks.core.algebra.prettyprint.IPlanPrettyPrinter
 import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
 import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
 import org.apache.hyracks.algebricks.core.rewriter.base.PhysicalOptimizationConfig;
+import org.apache.hyracks.api.exceptions.ErrorCode;
 import org.apache.hyracks.api.exceptions.IWarningCollector;
 import org.apache.hyracks.api.exceptions.Warning;
 import org.apache.logging.log4j.LogManager;
@@ -140,8 +143,8 @@ public class EnumerateJoinsRule implements IAlgebraicRewriteRule {
     public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
             throws AlgebricksException {
 
-        boolean cboMode = this.getCBOMode(context);
-        boolean cboTestMode = this.getCBOTestMode(context);
+        boolean cboMode = getCBOMode(context);
+        boolean cboTestMode = getCBOTestMode(context);
 
         if (!(cboMode || cboTestMode)) {
             return false;
@@ -215,6 +218,9 @@ public class EnumerateJoinsRule implements IAlgebraicRewriteRule {
             joinEnum.stats = new Stats(context, joinEnum);
             if (cboMode) {
                 if (!doAllDataSourcesHaveSamples(leafInputs, context)) {
+                    if (adviseIndex) {
+                        errorOutIndexAdvisorSamplesNotFound(leafInputs, context);
+                    }
                     return cleanUp();
                 }
             }
@@ -278,6 +284,9 @@ public class EnumerateJoinsRule implements IAlgebraicRewriteRule {
                 fakeLeafInputsMap, context, indexProvider);
         if (cboMode) {
             if (!doAllDataSourcesHaveSamples(leafInputs, context)) {
+                if (adviseIndex) {
+                    errorOutIndexAdvisorSamplesNotFound(leafInputs, context);
+                }
                 return cleanUp();
             }
         }
@@ -768,12 +777,12 @@ public class EnumerateJoinsRule implements IAlgebraicRewriteRule {
         }
     }
 
-    private boolean getCBOMode(IOptimizationContext context) {
+    public static boolean getCBOMode(IOptimizationContext context) {
         PhysicalOptimizationConfig physOptConfig = context.getPhysicalOptimizationConfig();
         return physOptConfig.getCBOMode();
     }
 
-    private boolean getCBOTestMode(IOptimizationContext context) {
+    public static boolean getCBOTestMode(IOptimizationContext context) {
         PhysicalOptimizationConfig physOptConfig = context.getPhysicalOptimizationConfig();
         return physOptConfig.getCBOTestMode();
     }
@@ -1521,4 +1530,37 @@ public class EnumerateJoinsRule implements IAlgebraicRewriteRule {
         }
         return (leafInputs.size() == n);
     }
+
+    private void errorOutIndexAdvisorSamplesNotFound(List<ILogicalOperator> leafInputs, IOptimizationContext context)
+            throws AlgebricksException {
+        for (ILogicalOperator li : leafInputs) {
+            DataSourceScanOperator scanOp = joinEnum.findDataSourceScanOperator(li);
+            if (scanOp == null) {
+                // Scan Operator not found
+                continue;
+            }
+            Stats handle = joinEnum.getStatsHandle();
+            if (handle == null) {
+                continue;
+            }
+            Index index = handle.findSampleIndex(scanOp, context);
+            if (index == null) {
+                errorOutIndexAdvisorSampleNotFound(scanOp, context);
+            }
+        }
+    }
+
+    private void errorOutIndexAdvisorSampleNotFound(DataSourceScanOperator scanOperator, IOptimizationContext context) throws AlgebricksException {
+        if (!(scanOperator.getDataSource() instanceof DatasetDataSource dataSource)) {
+            return;
+        }
+        DatasetFullyQualifiedName fullyQualifiedName = dataSource.getDataset().getDatasetFullyQualifiedName();
+        throw new AlgebricksException(ErrorCode.INDEX_ADVISOR_SAMPLE_NOT_FOUND, createSampleStatement(fullyQualifiedName));
+    }
+
+    private static String createSampleStatement(DatasetFullyQualifiedName dqn) {
+        return "ANALYZE COLLECTION `" + dqn.getDatabaseName() + "`.`" + dqn.getDataverseName() + "`.`"
+                + dqn.getDatasetName() + "`;";
+    }
+
 }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdviseIndexRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdviseIndexRule.java
index 9a7fbdd53e..7e34d25663 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdviseIndexRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdviseIndexRule.java
@@ -121,7 +121,16 @@ public class AdviseIndexRule implements IAlgebraicRewriteRule {
             DataverseName dataverse = jobGenParams.getDataverseName();
             String datasetName = jobGenParams.getDatasetName();
 
+            if(fakeIndexProvider == null) {
+                // Case when CBO can't parse the plan correctly and the fake index provider is not set.
+                return;
+            }
             Index fakeIndex = fakeIndexProvider.getIndex(databaseName, dataverse, datasetName, indexName);
+            if (fakeIndex == null || !(fakeIndex.getIndexDetails() instanceof Index.ValueIndexDetails)) {
+                // skips secondary primary index like
+                // create primary index sec_primary_idx on A;
+                return;
+            }
             Index actualIndex = lookupIndex(databaseName, dataverse, datasetName,
                     ((Index.ValueIndexDetails) fakeIndex.getIndexDetails()).getKeyFieldNames(), actualIndexProvider);
 
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdvisorConditionParser.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdvisorConditionParser.java
index a86b1b5df2..05039aa5d2 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdvisorConditionParser.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/AdvisorConditionParser.java
@@ -47,11 +47,27 @@ import org.apache.hyracks.algebricks.core.algebra.util.OperatorManipulationUtil;
 
 public class AdvisorConditionParser {
 
+    private static class ExprRef {
+        private final ILogicalExpression expr;
+        private final ILogicalOperator op;
+
+        public ExprRef(Mutable<ILogicalExpression> expr, ILogicalOperator op) {
+            this.expr = expr.getValue().cloneExpression();
+            this.op = op;
+        }
+
+        public ILogicalExpression getExpr() {
+            return expr;
+        }
+
+        public ILogicalOperator getOp() {
+            return op;
+        }
+    }
+
     public static ScanFilter parseScanNode(ILogicalOperator op, IOptimizationContext context)
             throws AlgebricksException {
-
-        List<Mutable<ILogicalExpression>> filterExprs = new ArrayList<>();
-        IVariableTypeEnvironment typeEnv = PushdownUtil.getTypeEnv(op, context);
+        List<ExprRef> filterExprRefs = new ArrayList<>();
         ILogicalOperator tempOp = op;
         do {
             if (tempOp.getOperatorTag() == LogicalOperatorTag.SELECT) {
@@ -59,35 +75,33 @@ public class AdvisorConditionParser {
                 ILogicalExpression condition = selectOp.getCondition().getValue();
                 List<Mutable<ILogicalExpression>> conjs = new ArrayList<>();
                 if (condition.splitIntoConjuncts(conjs)) {
-                    filterExprs.addAll(conjs);
+                    filterExprRefs.addAll(conjs.stream().map(expr -> new ExprRef(expr, selectOp)).toList());
                 } else {
-                    filterExprs.add(selectOp.getCondition());
+                    filterExprRefs.add(new ExprRef(selectOp.getCondition(), selectOp));
                 }
             }
             tempOp = tempOp.getInputs().getFirst().getValue();
         } while (tempOp.hasInputs());
 
-        filterExprs = OperatorManipulationUtil.cloneExpressions(filterExprs);
-
-        filterExprs.removeIf(expr -> !(expr.getValue() instanceof AbstractFunctionCallExpression));
+        filterExprRefs.removeIf(exprRef -> !(exprRef.getExpr() instanceof AbstractFunctionCallExpression));
 
         tempOp = op;
         do {
             if (tempOp.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
-                replaceExprsWithAssign((AssignOperator) tempOp, filterExprs);
+                replaceExprsWithAssign((AssignOperator) tempOp, filterExprRefs);
             }
             tempOp = tempOp.getInputs().getFirst().getValue();
         } while (tempOp.hasInputs());
 
         List<ScanFilterCondition> filterConditions = new ArrayList<>();
 
-        for (Mutable<ILogicalExpression> filterExpr : filterExprs) {
-            ScanFilterCondition filterCondition = parseCondition(filterExpr.getValue(), typeEnv);
+        for (ExprRef exprRef : filterExprRefs) {
+            IVariableTypeEnvironment typeEnv = PushdownUtil.getTypeEnv(exprRef.getOp(), context);
+            ScanFilterCondition filterCondition = parseCondition(exprRef.getExpr(), typeEnv);
             if (filterCondition != null) {
                 filterConditions.add(filterCondition);
             }
         }
-
         return new ScanFilter(filterConditions);
     }
 
@@ -96,9 +110,7 @@ public class AdvisorConditionParser {
         if (!(logicalExpression instanceof AbstractFunctionCallExpression expr)) {
             return null;
         }
-
         FunctionIdentifier fi = expr.getFunctionIdentifier();
-
         if (!BTreeAccessMethod.INSTANCE.getOptimizableFunctions().contains(new Pair<>(fi, false))) {
             return null;
         }
@@ -137,6 +149,9 @@ public class AdvisorConditionParser {
 
             expr = functionCallExpr.getArguments().getFirst().getValue();
         }
+        if (fieldNames.isEmpty()) {
+            return null;
+        }
 
         VariableReferenceExpression varRef = (VariableReferenceExpression) expr;
         LogicalVariable var = varRef.getVariableReference();
@@ -145,23 +160,21 @@ public class AdvisorConditionParser {
 
     public static JoinFilter parseJoinNode(AbstractBinaryJoinOperator joinOp, IOptimizationContext context)
             throws AlgebricksException {
-        List<Mutable<ILogicalExpression>> joinExprs = new ArrayList<>();
-        IVariableTypeEnvironment typeEnv = PushdownUtil.getTypeEnv(joinOp, context);
-
+        List<ExprRef> joinExprs = new ArrayList<>();
         ILogicalExpression joinExpression = joinOp.getCondition().getValue();
         List<Mutable<ILogicalExpression>> conjs = new ArrayList<>();
         if (joinExpression.splitIntoConjuncts(conjs)) {
-            joinExprs.addAll(conjs);
+            joinExprs.addAll(conjs.stream().map(expr -> new ExprRef(expr, joinOp)).toList());
         } else {
-            joinExprs.add(joinOp.getCondition());
+            joinExprs.add(new ExprRef(joinOp.getCondition(), joinOp));
         }
-        joinExprs = OperatorManipulationUtil.cloneExpressions(joinExprs);
-        traverseAndReplace(joinOp, joinExprs);
 
+        traverseAndReplace(joinOp, joinExprs);
         List<JoinFilterCondition> joinConditions = new ArrayList<>();
 
-        for (Mutable<ILogicalExpression> joinExpr : joinExprs) {
-            JoinFilterCondition joinCondition = parseJoinCondition(joinExpr.getValue(), typeEnv);
+        for (ExprRef joinExprRef : joinExprs) {
+            IVariableTypeEnvironment typeEnv = PushdownUtil.getTypeEnv(joinExprRef.getOp(), context);
+            JoinFilterCondition joinCondition = parseJoinCondition(joinExprRef.getExpr(), typeEnv);
             if (joinCondition != null) {
                 joinConditions.add(joinCondition);
             }
@@ -170,25 +183,22 @@ public class AdvisorConditionParser {
         return new JoinFilter(joinConditions);
     }
 
-    private static void traverseAndReplace(AbstractLogicalOperator op, List<Mutable<ILogicalExpression>> exprs) {
-
+    private static void traverseAndReplace(AbstractLogicalOperator op, List<ExprRef> exprs) {
         if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
             replaceExprsWithAssign((AssignOperator) op, exprs);
         }
-
         for (Mutable<ILogicalOperator> input : op.getInputs()) {
             traverseAndReplace((AbstractLogicalOperator) input.getValue(), exprs);
         }
-
     }
 
-    public static void replaceExprsWithAssign(AssignOperator assignOp, List<Mutable<ILogicalExpression>> exprs) {
-        for (Mutable<ILogicalExpression> filterExpr : exprs) {
-            if (filterExpr.getValue().getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+    private static void replaceExprsWithAssign(AssignOperator assignOp, List<ExprRef> exprRefs) {
+        for (ExprRef exprRef : exprRefs) {
+            if (exprRef.getExpr().getExpressionTag() == LogicalExpressionTag.CONSTANT) {
                 continue;
             }
             for (int i = 0; i < assignOp.getVariables().size(); i++) {
-                OperatorManipulationUtil.replaceVarWithExpr((AbstractFunctionCallExpression) filterExpr.getValue(),
+                OperatorManipulationUtil.replaceVarWithExpr((AbstractFunctionCallExpression) exprRef.getExpr(),
                         assignOp.getVariables().get(i), assignOp.getExpressions().get(i).getValue());
             }
         }
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/FakeIndexProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/FakeIndexProvider.java
index ee487dd146..1b33096206 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/FakeIndexProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/indexadvisor/FakeIndexProvider.java
@@ -20,6 +20,7 @@ package org.apache.asterix.optimizer.rules.cbo.indexadvisor;
 
 import static java.util.UUID.randomUUID;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -131,6 +132,9 @@ public class FakeIndexProvider implements IIndexProvider {
         for (Map.Entry<DatasetFullyQualifiedName, Set<List<String>>> entry : joinDataSourceFieldNamesMap.entrySet()) {
             DatasetFullyQualifiedName qualifiedName = entry.getKey();
             Set<List<String>> fieldNames = entry.getValue();
+            if (fieldNames.isEmpty()) {
+                continue;
+            }
 
             joinIndexEnumerator.init(fieldNames);
             Iterator<List<List<String>>> itr = joinIndexEnumerator.getIterator();
@@ -169,8 +173,8 @@ public class FakeIndexProvider implements IIndexProvider {
     @Override
     public List<Index> getDatasetIndexes(String database, DataverseName dataverseName, String datasetName)
             throws AlgebricksException {
-        return filterIndexesMap.get(new DatasetFullyQualifiedName(database, dataverseName, datasetName)).values()
-                .stream().toList();
+        return filterIndexesMap.getOrDefault(new DatasetFullyQualifiedName(database, dataverseName, datasetName),
+                Collections.emptyMap()).values().stream().toList();
     }
 
 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
index 59e6dc2d09..aff78503f0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/common/APIFramework.java
@@ -312,6 +312,14 @@ public class APIFramework {
             builder.setNormalizedKeyComputerFactoryProvider(format.getNormalizedKeyComputerFactoryProvider());
 
             IndexAdvisor indexAdvisor = new IndexAdvisor(isAdviceOnly);
+
+            if (isAdviceOnly) {
+                if (!physOptConf.getCBOMode() && !physOptConf.getCBOTestMode()) {
+                    throw new CompilationException(ErrorCode.COMPILATION_ERROR,
+                            "Index advise cannot be used without CBO mode.");
+                }
+            }
+
             IRuleSetKind ruleSetKind = isAdviceOnly ? LOGICAL_ADVISOR : QUERY;
             ICompiler compiler = compilerFactory.createCompiler(plan, metadataProvider, t.getVarCounter(), ruleSetKind,
                     indexAdvisor);
diff --git a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/base/IndexAdvisor.java b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/base/IndexAdvisor.java
index d381afab43..1ba74ca3cf 100644
--- a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/base/IndexAdvisor.java
+++ b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/base/IndexAdvisor.java
@@ -130,7 +130,6 @@ public class IndexAdvisor {
         }
 
         public String getCreateIndexClause() {
-
             return "CREATE INDEX " + indexName + " ON `" + databaseName + "`.`" + dataverseName + "`.`" + datasetName
                     + "`" + getKeyFieldNamesClause() + ";";
         }
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java
index d7abf4c057..d83270f118 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/exceptions/ErrorCode.java
@@ -174,7 +174,8 @@ public enum ErrorCode implements IError {
     INAPPLICABLE_HINT(10006),
     CROSS_PRODUCT_JOIN(10007),
     GROUP_ALL_DECOR(10008),
-    EXPRESSION_CANNOT_BE_CONSTANT(10009);
+    EXPRESSION_CANNOT_BE_CONSTANT(10009),
+    INDEX_ADVISOR_SAMPLE_NOT_FOUND(10010);
 
     private static final String RESOURCE_PATH = "errormsg/en.properties";
     public static final String HYRACKS = "HYR";
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties b/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
index e9569be66f..8e16262c78 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/resources/errormsg/en.properties
@@ -163,4 +163,5 @@
 10006 = Could not apply %1$s hint: %2$s
 10007 = Encountered a cross product join
 10008 = Inappropriate use of group by all with decor variables
-10009 = '%1$s' expression cannot be a constant
\ No newline at end of file
+10009 = '%1$s' expression cannot be a constant
+10010 = No samples found for the collections in this query. Create samples with: '%1$s'
\ No newline at end of file