Full-text implementation step 3
- Implemented index-based full-text contains() function.
- Fixed a bug in the full-text code that can't process join cases well.
- Introduced full-text type index syntax. The functionality was already
in the codebase but it was not being used. So, using this syntax, we
can utilize the given index type - Not the length partitioned keyword index.
- Added the support for SQL++
- Default option will be set if a user doesn't provide any option.
Change-Id: I1087854ac7cf5b6ef5094e27a1646f12f6a8653f
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1388
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
BAD: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Ian Maxon <imaxon@apache.org>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
index 8bb1b22..7d8dcd1 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/algebra/operators/physical/InvertedIndexPOperator.java
@@ -144,7 +144,8 @@
metadataProvider, context, builder.getJobSpec(), unnestMapOp, opSchema, jobGenParams.getRetainInput(),
retainNull, jobGenParams.getDatasetName(), dataset, jobGenParams.getIndexName(),
jobGenParams.getSearchKeyType(), keyIndexes, jobGenParams.getSearchModifierType(),
- jobGenParams.getSimilarityThreshold(), minFilterFieldIndexes, maxFilterFieldIndexes);
+ jobGenParams.getSimilarityThreshold(), minFilterFieldIndexes, maxFilterFieldIndexes,
+ jobGenParams.getIsFullTextSearch());
// Contribute operator in hyracks job.
builder.contributeHyracksOperator(unnestMapOp, invIndexSearch.first);
@@ -158,7 +159,8 @@
AbstractUnnestMapOperator unnestMap, IOperatorSchema opSchema, boolean retainInput, boolean retainMissing,
String datasetName, Dataset dataset, String indexName, ATypeTag searchKeyType, int[] keyFields,
SearchModifierType searchModifierType, IAlgebricksConstantValue similarityThreshold,
- int[] minFilterFieldIndexes, int[] maxFilterFieldIndexes) throws AlgebricksException {
+ int[] minFilterFieldIndexes, int[] maxFilterFieldIndexes, boolean isFullTextSearchQuery)
+ throws AlgebricksException {
try {
IAObject simThresh = ((AsterixConstantValue) similarityThreshold).getObject();
@@ -288,7 +290,7 @@
invListsTypeTraits, invListsComparatorFactories, dataflowHelperFactory, queryTokenizerFactory,
searchModifierFactory, outputRecDesc, retainInput, retainMissing, context.getMissingWriterFactory(),
NoOpOperationCallbackFactory.INSTANCE, minFilterFieldIndexes, maxFilterFieldIndexes,
- LSMIndexUtil.getMetadataPageManagerFactory());
+ LSMIndexUtil.getMetadataPageManagerFactory(), isFullTextSearchQuery);
return new Pair<>(invIndexSearchOp, secondarySplitsAndConstraint.second);
} catch (MetadataException e) {
throw new AlgebricksException(e);
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckRule.java
index e36b87d..e589065 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckRule.java
@@ -22,6 +22,8 @@
import java.util.HashMap;
import java.util.List;
+import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.util.ConstantExpressionUtil;
@@ -34,6 +36,7 @@
import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
@@ -49,6 +52,13 @@
// parameter name and its value
HashMap<MutableObject<ILogicalExpression>, MutableObject<ILogicalExpression>> paramValueMap;
+ // the last expression position before the option argument in the arguments array
+ private static final int LAST_EXPRESSION_POS_BEFORE_OPTION = 1;
+ // The number of anticipated arguments for a full-text query when a user doesn't provide any option.
+ private static final int FULLTEXT_QUERY_WITHOUT_OPTION_NO_OF_ARGUMENTS = 2;
+ // The number of anticipated arguments for a full-text query when a user provide option(s) as a record.
+ private static final int FULLTEXT_QUERY_WITH_OPTION_NO_OF_ARGUMENTS = 3;
+
@Override
public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
throws AlgebricksException {
@@ -92,7 +102,19 @@
AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
FunctionIdentifier fi = funcExpr.getFunctionIdentifier();
+ // Collects the correct number of arguments - it can be 2 if a user doesn't provide any option.
+ int numberOfCorrectArguments = 0;
+ String functionName = "";
if (fi == BuiltinFunctions.FULLTEXT_CONTAINS) {
+ numberOfCorrectArguments = FULLTEXT_QUERY_WITH_OPTION_NO_OF_ARGUMENTS;
+ functionName = BuiltinFunctions.FULLTEXT_CONTAINS.getName();
+ } else if (fi == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
+ numberOfCorrectArguments = FULLTEXT_QUERY_WITHOUT_OPTION_NO_OF_ARGUMENTS;
+ functionName = BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION.getName();
+ }
+
+ // If numberOfCorrectArguments is greater than zero, then this is a full-text search query.
+ if (numberOfCorrectArguments > 0) {
// Don't need to check this operator again.
context.addToDontApplySet(this, op);
@@ -100,21 +122,26 @@
List<Mutable<ILogicalExpression>> newExprs = new ArrayList<>();
// The number of parameters should be three: exp1, exp2, and the option
- if (oldExprs.size() != 3) {
+ if (oldExprs.size() != numberOfCorrectArguments) {
throw new AlgebricksException(
- BuiltinFunctions.FULLTEXT_CONTAINS.getName() + " should have three parameters.");
+ functionName + " should have " + numberOfCorrectArguments + " parameters.");
}
- // The last expression is a record that contains the parameters. That's why we deduct -1.
- for (int i = 0; i < oldExprs.size() - 1; i++) {
+ // The last expression before the option needs to be copied first.
+ for (int i = 0; i <= LAST_EXPRESSION_POS_BEFORE_OPTION; i++) {
newExprs.add(new MutableObject<ILogicalExpression>((ILogicalExpression) oldExprs.get(i).getValue()));
}
// Sanity check for the types of the first two parameters
- checkFirstAndSecondParamter(oldExprs);
+ checkFirstAndSecondParamter(oldExprs, functionName);
// Checks and transforms the actual full-text parameters.
- checkAndSetDefaultValueForThirdParameter(oldExprs.get(2), newExprs);
+ if (numberOfCorrectArguments == FULLTEXT_QUERY_WITH_OPTION_NO_OF_ARGUMENTS) {
+ checkValueForThirdParameter(oldExprs.get(2), newExprs);
+ } else {
+ // no option provided case: sets the default option here.
+ setDefaultValueForThirdParameter(newExprs);
+ }
// Resets the last argument.
funcExpr.getArguments().clear();
@@ -130,13 +157,13 @@
* Checks the correctness of the first and second argument. If the argument is a constant, we can check
* it now. If the argument is not a constant, we will defer the checking until run-time.
*/
- void checkFirstAndSecondParamter(List<Mutable<ILogicalExpression>> exprs) throws AlgebricksException {
+ void checkFirstAndSecondParamter(List<Mutable<ILogicalExpression>> exprs, String functionName)
+ throws AlgebricksException {
// Check the first parameter - Expression1. If it's a constant, then we can check the type here.
ILogicalExpression firstExpr = exprs.get(0).getValue();
if (firstExpr.getExpressionTag() == LogicalExpressionTag.CONSTANT
&& ConstantExpressionUtil.getConstantIaObjectType(firstExpr) != ATypeTag.STRING) {
- throw new AlgebricksException("The first expression of "
- + BuiltinFunctions.FULLTEXT_CONTAINS.getName() + " should be a string.");
+ throw new AlgebricksException("The first expression of " + functionName + " should be a string.");
}
// Check the second parameter - Expression2. If it's a constant, then we can check the type here.
@@ -149,9 +176,8 @@
case ORDEREDLIST:
break;
default:
- throw new AlgebricksException(
- "The second expression of " + BuiltinFunctions.FULLTEXT_CONTAINS.getName()
- + "should be a string, an unordered list, or an ordered list.");
+ throw new AlgebricksException("The second expression of " + functionName
+ + "should be a string, an unordered list, or an ordered list.");
}
}
}
@@ -162,7 +188,7 @@
* @param expr
* @throws AlgebricksException
*/
- void checkAndSetDefaultValueForThirdParameter(Mutable<ILogicalExpression> expr,
+ void checkValueForThirdParameter(Mutable<ILogicalExpression> expr,
List<Mutable<ILogicalExpression>> newArgs) throws AlgebricksException {
// Get the last parameter - this should be a record-constructor.
AbstractFunctionCallExpression openRecConsExpr = (AbstractFunctionCallExpression) expr.getValue();
@@ -243,4 +269,21 @@
+ " or " + FullTextContainsDescriptor.DISJUNCTIVE_SEARCH_MODE_OPTION + ".");
}
}
+
+ /**
+ * Sets the default option value(s) when a user doesn't provide any option.
+ */
+ void setDefaultValueForThirdParameter(List<Mutable<ILogicalExpression>> newArgs)
+ throws AlgebricksException {
+ // Sets the search mode option: the default option is conjunctive search.
+ ILogicalExpression searchModeOptionExpr = new ConstantExpression(
+ new AsterixConstantValue(new AString(FullTextContainsDescriptor.SEARCH_MODE_OPTION)));
+ ILogicalExpression searchModeValExpr = new ConstantExpression(
+ new AsterixConstantValue(new AString(FullTextContainsDescriptor.CONJUNCTIVE_SEARCH_MODE_OPTION)));
+
+ // Add this option as arguments to the ftcontains().
+ newArgs.add(new MutableObject<ILogicalExpression>(searchModeOptionExpr));
+ newArgs.add(new MutableObject<ILogicalExpression>(searchModeValExpr));
+ }
+
}
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 0680183..e6cf12d 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
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -36,6 +37,8 @@
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AbstractCollectionType;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
@@ -296,9 +299,23 @@
boolean jaccardSimilarity = optFuncExpr.getFuncExpr().getFunctionIdentifier().getName()
.startsWith("similarity-jaccard-check");
+ // Full-text search consideration: an (un)ordered list of string type can be compatible with string
+ // type. i.e. an (un)ordered list can be provided as arguments to a string type field index.
+ List<IAType> elementTypes = matchedTypes;
+ if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ || optFuncExpr.getFuncExpr()
+ .getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
+ for (int j = 0; j < matchedTypes.size(); j++) {
+ if (matchedTypes.get(j).getTypeTag() == ATypeTag.ORDEREDLIST
+ || matchedTypes.get(j).getTypeTag() == ATypeTag.UNORDEREDLIST) {
+ elementTypes.set(j, ((AbstractCollectionType) matchedTypes.get(j)).getItemType());
+ }
+ }
+ }
+
for (int j = 0; j < matchedTypes.size(); j++) {
for (int k = j + 1; k < matchedTypes.size(); k++) {
- typeMatch &= isMatched(matchedTypes.get(j), matchedTypes.get(k), jaccardSimilarity);
+ typeMatch &= isMatched(elementTypes.get(j), elementTypes.get(k), jaccardSimilarity);
}
}
@@ -348,6 +365,10 @@
}
private boolean isMatched(IAType type1, IAType type2, boolean useListDomain) throws AlgebricksException {
+ // Sanity check - two types can't be NULL in order to be matched.
+ if (type1 == null || type2 == null) {
+ return false;
+ }
if (ATypeHierarchy.isSameTypeDomain(Index.getNonNullableType(type1).first.getTypeTag(),
Index.getNonNullableType(type2).first.getTypeTag(), useListDomain)) {
return true;
@@ -546,7 +567,7 @@
fieldName = getFieldNameFromSubTree(optFuncExpr, subTree, assignOrUnnestIndex, 0, subTree.getRecordType(),
funcVarIndex, optFuncExpr.getFuncExpr().getArguments().get(funcVarIndex).getValue(),
datasetRecordVar, subTree.getMetaRecordType(), datasetMetaVar);
- if (fieldName == null) {
+ if (fieldName.isEmpty()) {
return;
}
}
@@ -683,25 +704,25 @@
if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
AssignOperator assignOp = (AssignOperator) op;
expr = (AbstractLogicalExpression) assignOp.getExpressions().get(assignVarIndex).getValue();
- if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
- //Otherwise the cast for childFuncExpr would fail
- return null;
+ // Can't get a field name from a constant expression. So, return null.
+ if (expr.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+ return Collections.emptyList();
}
childFuncExpr = (AbstractFunctionCallExpression) expr;
} else {
UnnestOperator unnestOp = (UnnestOperator) op;
expr = (AbstractLogicalExpression) unnestOp.getExpressionRef().getValue();
if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
- return null;
+ return Collections.emptyList();
}
childFuncExpr = (AbstractFunctionCallExpression) expr;
if (childFuncExpr.getFunctionIdentifier() != BuiltinFunctions.SCAN_COLLECTION) {
- return null;
+ return Collections.emptyList();
}
expr = (AbstractLogicalExpression) childFuncExpr.getArguments().get(0).getValue();
}
if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
- return null;
+ return Collections.emptyList();
}
AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
FunctionIdentifier funcIdent = funcExpr.getFunctionIdentifier();
@@ -714,21 +735,21 @@
if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_NAME) {
fieldName = ConstantExpressionUtil.getStringArgument(funcExpr, 1);
if (fieldName == null) {
- return null;
+ return Collections.emptyList();
}
isFieldAccess = true;
isByName = true;
} else if (funcIdent == BuiltinFunctions.FIELD_ACCESS_BY_INDEX) {
Integer idx = ConstantExpressionUtil.getIntArgument(funcExpr, 1);
if (idx == null) {
- return null;
+ return Collections.emptyList();
}
fieldIndex = idx;
isFieldAccess = true;
} else if (funcIdent == BuiltinFunctions.FIELD_ACCESS_NESTED) {
ILogicalExpression nameArg = funcExpr.getArguments().get(1).getValue();
if (nameArg.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
- return null;
+ return Collections.emptyList();
}
ConstantExpression constExpr = (ConstantExpression) nameArg;
AOrderedList orderedNestedFieldName = (AOrderedList) ((AsterixConstantValue) constExpr.getValue())
@@ -783,10 +804,10 @@
assignAndExpressionIndexes[0], assignAndExpressionIndexes[1], recordType, funcVarIndex,
parentFuncExpr, recordVar, metaType, metaVar);
- if (parentFieldNames == null) {
+ if (parentFieldNames.isEmpty()) {
//Nested assign was not a field access.
//We will not use index
- return null;
+ return Collections.emptyList();
}
if (!isByName) {
@@ -820,7 +841,7 @@
}
if (!funcIDSetThatRetainFieldName.contains(funcIdent)) {
- return null;
+ return Collections.emptyList();
}
// We use a part of the field in edit distance computation
if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CHECK) {
@@ -830,7 +851,7 @@
// cannot apply an index.
ILogicalExpression argExpr = funcExpr.getArguments().get(0).getValue();
if (argExpr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
- return null;
+ return Collections.emptyList();
}
LogicalVariable curVar = ((VariableReferenceExpression) argExpr).getVariableReference();
// We look for the assign or unnest operator that produces curVar below
@@ -858,6 +879,6 @@
}
}
}
- return null;
+ return Collections.emptyList();
}
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
index 661786c..2e6518b 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
@@ -39,10 +39,13 @@
import org.apache.asterix.om.base.ABoolean;
import org.apache.asterix.om.base.AInt32;
import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.base.IACursor;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.BuiltinFunctions;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.om.util.ConstantExpressionUtil;
@@ -77,6 +80,7 @@
import org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
import org.apache.hyracks.algebricks.core.algebra.plan.ALogicalPlanImpl;
import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.DelimitedUTF8StringBinaryTokenizer;
/**
* Static helper functions for rewriting plans using indexes.
@@ -139,7 +143,9 @@
}
if (arg2.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
// The arguments of contains() function are asymmetrical, we can only use index if it is on the first argument
- if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.STRING_CONTAINS) {
+ if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.STRING_CONTAINS
+ || funcExpr.getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ || funcExpr.getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
return false;
}
IAType expressionType = constantRuntimeResultType(arg1, context, typeEnvironment);
@@ -159,6 +165,15 @@
}
constantExpressionType = expressionType;
constExpression = arg2;
+
+ // For a full-text search query, if the given predicate is a constant and not a single keyword,
+ // i.e. it's a phrase, then we currently throw an exception since we don't support a phrase search
+ // yet in the full-text search.
+ if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ && arg2.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+ checkFTSearchConstantExpression(constExpression);
+ }
+
VariableReferenceExpression varExpr = (VariableReferenceExpression) arg1;
fieldVar = varExpr.getVariableReference();
} else {
@@ -176,6 +191,62 @@
return true;
}
+ /**
+ * Fetches each element and calls the check for the type and value in the given list using the given cursor.
+ */
+ private static void checkEachElementInFTSearchListPredicate(IACursor oListCursor)
+ throws AlgebricksException {
+ String argValue;
+ IAObject element;
+ while (oListCursor.next()) {
+ element = oListCursor.get();
+ if (element.getType() == BuiltinType.ASTRING) {
+ argValue = ConstantExpressionUtil.getStringConstant(element);
+ checkAndGenerateFTSearchExceptionForStringPhrase(argValue);
+ } else {
+ throw new AlgebricksException("Each element in the list should be a string in the Full-text search.");
+ }
+ }
+ }
+
+ // Checks whether a proper constant expression is in place for the full-text search.
+ // A proper constant expression in the full-text search should be among string, string type (Un)ordered list.
+ public static void checkFTSearchConstantExpression(ILogicalExpression constExpression) throws AlgebricksException {
+ IAObject objectFromExpr = ConstantExpressionUtil.getConstantIaObject(constExpression, null);
+ String arg2Value;
+ IACursor oListCursor;
+
+ switch (objectFromExpr.getType().getTypeTag()) {
+ case STRING:
+ arg2Value = ConstantExpressionUtil.getStringConstant(objectFromExpr);
+ checkAndGenerateFTSearchExceptionForStringPhrase(arg2Value);
+ break;
+ case ORDEREDLIST:
+ oListCursor = ConstantExpressionUtil.getOrderedListConstant(objectFromExpr).getCursor();
+ checkEachElementInFTSearchListPredicate(oListCursor);
+ break;
+ case UNORDEREDLIST:
+ oListCursor = ConstantExpressionUtil.getUnorderedListConstant(objectFromExpr).getCursor();
+ checkEachElementInFTSearchListPredicate(oListCursor);
+ break;
+ default:
+ throw new AlgebricksException(
+ "A full-text Search predicate should be a string or an (un)ordered list.");
+ }
+ }
+
+ // Checks whether the given string is a phrase. If so, generates an exception since
+ // we don't support a phrase search in the full-text search yet.
+ public static void checkAndGenerateFTSearchExceptionForStringPhrase(String value) throws AlgebricksException {
+ for (int j = 0; j < value.length(); j++) {
+ if (DelimitedUTF8StringBinaryTokenizer.isSeparator(value.charAt(j))) {
+ throw new AlgebricksException(
+ "Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted."
+ + value.charAt(j));
+ }
+ }
+ }
+
public static boolean analyzeFuncExprArgsForTwoVars(AbstractFunctionCallExpression funcExpr,
AccessMethodAnalysisContext analysisCtx) {
LogicalVariable fieldVar1 = null;
@@ -209,15 +280,13 @@
if (!primaryKeysOnly) {
switch (index.getIndexType()) {
case BTREE:
- case SINGLE_PARTITION_WORD_INVIX:
- case SINGLE_PARTITION_NGRAM_INVIX: {
dest.addAll(KeyFieldTypeUtils.getBTreeIndexKeyTypes(index, recordType, metaRecordType));
break;
- }
- case RTREE: {
+ case RTREE:
dest.addAll(KeyFieldTypeUtils.getRTreeIndexKeyTypes(index, recordType, metaRecordType));
break;
- }
+ case SINGLE_PARTITION_WORD_INVIX:
+ case SINGLE_PARTITION_NGRAM_INVIX:
case LENGTH_PARTITIONED_NGRAM_INVIX:
case LENGTH_PARTITIONED_WORD_INVIX:
default:
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
index 2dfe850..30866cf 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
@@ -36,6 +36,7 @@
import org.apache.asterix.om.base.AFloat;
import org.apache.asterix.om.base.AInt32;
import org.apache.asterix.om.base.AMissing;
+import org.apache.asterix.om.base.ANull;
import org.apache.asterix.om.base.AString;
import org.apache.asterix.om.base.IACollection;
import org.apache.asterix.om.base.IAObject;
@@ -46,6 +47,8 @@
import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
+import org.apache.asterix.om.util.ConstantExpressionUtil;
+import org.apache.asterix.runtime.evaluators.functions.FullTextContainsDescriptor;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -81,6 +84,7 @@
import org.apache.hyracks.storage.am.lsm.invertedindex.search.ConjunctiveEditDistanceSearchModifierFactory;
import org.apache.hyracks.storage.am.lsm.invertedindex.search.ConjunctiveListEditDistanceSearchModifierFactory;
import org.apache.hyracks.storage.am.lsm.invertedindex.search.ConjunctiveSearchModifierFactory;
+import org.apache.hyracks.storage.am.lsm.invertedindex.search.DisjunctiveSearchModifierFactory;
import org.apache.hyracks.storage.am.lsm.invertedindex.search.EditDistanceSearchModifierFactory;
import org.apache.hyracks.storage.am.lsm.invertedindex.search.JaccardSearchModifierFactory;
import org.apache.hyracks.storage.am.lsm.invertedindex.search.ListEditDistanceSearchModifierFactory;
@@ -97,7 +101,8 @@
JACCARD,
EDIT_DISTANCE,
CONJUNCTIVE_EDIT_DISTANCE,
- INVALID
+ INVALID,
+ DISJUNCTIVE
}
private static List<FunctionIdentifier> funcIdents = new ArrayList<>();
@@ -107,6 +112,9 @@
// For matching similarity-check functions. For example, similarity-jaccard-check returns a list of two items,
// and the select condition will get the first list-item and check whether it evaluates to true.
funcIdents.add(BuiltinFunctions.GET_ITEM);
+ // Full-text search function
+ funcIdents.add(BuiltinFunctions.FULLTEXT_CONTAINS);
+ funcIdents.add(BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION);
}
// These function identifiers are matched in this AM's analyzeFuncExprArgs(),
@@ -131,7 +139,9 @@
List<AbstractLogicalOperator> assignsAndUnnests, AccessMethodAnalysisContext analysisCtx,
IOptimizationContext context, IVariableTypeEnvironment typeEnvironment) throws AlgebricksException {
- if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.STRING_CONTAINS) {
+ if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.STRING_CONTAINS
+ || funcExpr.getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ || funcExpr.getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
boolean matches = AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVar(funcExpr, analysisCtx, context,
typeEnvironment);
if (!matches) {
@@ -828,6 +838,7 @@
if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.STRING_CONTAINS) {
jobGenParams.setSearchModifierType(SearchModifierType.CONJUNCTIVE);
jobGenParams.setSimilarityThreshold(new AsterixConstantValue(AMissing.MISSING));
+ return;
}
if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.SIMILARITY_JACCARD_CHECK) {
jobGenParams.setSearchModifierType(SearchModifierType.JACCARD);
@@ -835,6 +846,7 @@
jobGenParams.setSimilarityThreshold(
((ConstantExpression) optFuncExpr.getConstantExpr(optFuncExpr.getNumConstantExpr() - 1))
.getValue());
+ return;
}
if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.EDIT_DISTANCE_CHECK
|| optFuncExpr.getFuncExpr()
@@ -848,7 +860,40 @@
jobGenParams.setSimilarityThreshold(
((ConstantExpression) optFuncExpr.getConstantExpr(optFuncExpr.getNumConstantExpr() - 1))
.getValue());
+ return;
}
+ if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ || optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
+ // Let the job Gen pass the full-text search information.
+ jobGenParams.setIsFullTextSearch(true);
+
+ // We check the last argument of the given full-text search to see whether conjunctive or disjunctive
+ // search parameter is given. This is the last argument of the function call expression.
+ AbstractFunctionCallExpression funcExpr = optFuncExpr.getFuncExpr();
+ jobGenParams.setSearchModifierType(getFullTextOption(funcExpr));
+
+ jobGenParams.setSimilarityThreshold(new AsterixConstantValue(ANull.NULL));
+ }
+ }
+
+ private static SearchModifierType getFullTextOption(AbstractFunctionCallExpression funcExpr) {
+ if (funcExpr.getArguments().size() < 3 || funcExpr.getArguments().size() % 2 != 0) {
+ // If no parameters or incorrect number of parameters are given, the default search type is returned.
+ return SearchModifierType.DISJUNCTIVE;
+ }
+ // From the third argument, it contains full-text search options.
+ for (int i = 2; i < funcExpr.getArguments().size(); i = i + 2) {
+ String optionName = ConstantExpressionUtil.getStringArgument(funcExpr, i);
+ if (optionName.equals(FullTextContainsDescriptor.SEARCH_MODE_OPTION)) {
+ String searchType = ConstantExpressionUtil.getStringArgument(funcExpr, i + 1);
+ if (searchType.equals(FullTextContainsDescriptor.CONJUNCTIVE_SEARCH_MODE_OPTION)) {
+ return SearchModifierType.CONJUNCTIVE;
+ } else {
+ return SearchModifierType.DISJUNCTIVE;
+ }
+ }
+ }
+ return null;
}
private void addKeyVarsAndExprs(IOptimizableFuncExpr optFuncExpr, ArrayList<LogicalVariable> keyVarList,
@@ -883,6 +928,11 @@
return isContainsFuncOptimizable(index, optFuncExpr);
}
+ if (optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS
+ || optFuncExpr.getFuncExpr().getFunctionIdentifier() == BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
+ return isFullTextContainsFuncOptimizable(index, optFuncExpr);
+ }
+
return false;
}
@@ -1012,6 +1062,40 @@
return false;
}
+ private boolean isFullTextContainsFuncCompatible(ATypeTag typeTag, IndexType indexType) {
+ //We can only optimize contains with full-text indexes.
+ return (typeTag == ATypeTag.STRING || typeTag == ATypeTag.ORDEREDLIST || typeTag == ATypeTag.UNORDEREDLIST)
+ && indexType == IndexType.SINGLE_PARTITION_WORD_INVIX;
+ }
+
+ // Does full-text search can utilize the given index?
+ private boolean isFullTextContainsFuncOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) {
+ if (optFuncExpr.getNumLogicalVars() == 2) {
+ return isFullTextContainsFuncJoinOptimizable(index, optFuncExpr);
+ } else {
+ return isFullTextContainsFuncSelectOptimizable(index, optFuncExpr);
+ }
+ }
+
+ // Checks whether the given index is compatible with full-text search and
+ // the type of the constant search predicate is STRING, ORDEREDLIST, or UNORDEREDLIST
+ private boolean isFullTextContainsFuncSelectOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) {
+ AsterixConstantValue strConstVal =
+ (AsterixConstantValue) ((ConstantExpression) optFuncExpr.getConstantExpr(0)).getValue();
+ IAObject strObj = strConstVal.getObject();
+ ATypeTag typeTag = strObj.getType().getTypeTag();
+
+ return isFullTextContainsFuncCompatible(typeTag, index.getIndexType());
+ }
+
+ private boolean isFullTextContainsFuncJoinOptimizable(Index index, IOptimizableFuncExpr optFuncExpr) {
+ if (index.isEnforcingKeyFileds()) {
+ return isFullTextContainsFuncCompatible(index.getKeyFieldTypes().get(0).getTypeTag(), index.getIndexType());
+ } else {
+ return isFullTextContainsFuncCompatible(optFuncExpr.getFieldType(0).getTypeTag(), index.getIndexType());
+ }
+ }
+
private ScalarFunctionCallExpression findTokensFunc(FunctionIdentifier funcId, IOptimizableFuncExpr optFuncExpr,
int subTreeIndex) {
//find either a gram-tokens or a word-tokens function that exists in optFuncExpr.subTrees' assignsAndUnnests
@@ -1150,15 +1234,15 @@
public static IInvertedIndexSearchModifierFactory getSearchModifierFactory(SearchModifierType searchModifierType,
IAObject simThresh, Index index) throws AlgebricksException {
switch (searchModifierType) {
- case CONJUNCTIVE: {
+ case CONJUNCTIVE:
return new ConjunctiveSearchModifierFactory();
- }
- case JACCARD: {
+ case DISJUNCTIVE:
+ return new DisjunctiveSearchModifierFactory();
+ case JACCARD:
float jaccThresh = ((AFloat) simThresh).getFloatValue();
return new JaccardSearchModifierFactory(jaccThresh);
- }
case EDIT_DISTANCE:
- case CONJUNCTIVE_EDIT_DISTANCE: {
+ case CONJUNCTIVE_EDIT_DISTANCE:
int edThresh = 0;
try {
edThresh = ((AInt32) ATypeHierarchy.convertNumericTypeObject(simThresh, ATypeTag.INT32))
@@ -1191,10 +1275,8 @@
+ "' for index type '" + index.getIndexType() + "'");
}
}
- }
- default: {
+ default:
throw new AlgebricksException("Unknown search modifier type '" + searchModifierType + "'.");
- }
}
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexJobGenParams.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexJobGenParams.java
index b6786ad..05122cd 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexJobGenParams.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexJobGenParams.java
@@ -42,6 +42,16 @@
protected ATypeTag searchKeyType;
protected List<LogicalVariable> keyVarList;
protected List<LogicalVariable> nonKeyVarList;
+ // TODO: Currently, we don't have positional information in an inverted index.
+ // Thus, we can't support the phrase search yet. So, for the full-text search,
+ // if a query predicate contains a phrase, we need to generate an exception.
+ // The following variable serves this purpose. i.e. Checks whether the query is a full-text search query or not.
+ protected boolean isFullTextSearchQuery = false;
+ protected static final int SEARCH_MODIFIER_INDEX = 0;
+ protected static final int SIM_THRESHOLD_INDEX = 1;
+ protected static final int SEARCH_KEY_TYPE_INDEX = 2;
+ protected static final int IS_FULLTEXT_SEARCH_INDEX = 3;
+ protected static final int KEY_VAR_INDEX = 4;
public InvertedIndexJobGenParams() {
}
@@ -55,6 +65,10 @@
this.searchModifierType = searchModifierType;
}
+ public void setIsFullTextSearch(boolean isFullTextSearchQuery) {
+ this.isFullTextSearchQuery = isFullTextSearchQuery;
+ }
+
public void setSimilarityThreshold(IAlgebricksConstantValue similarityThreshold) {
this.similarityThreshold = similarityThreshold;
}
@@ -78,6 +92,9 @@
// Write search key type.
funcArgs.add(
new MutableObject<ILogicalExpression>(AccessMethodUtils.createInt32Constant(searchKeyType.ordinal())));
+ // Write full-text search information.
+ funcArgs.add(
+ new MutableObject<ILogicalExpression>(AccessMethodUtils.createBooleanConstant(isFullTextSearchQuery)));
// Write key var list.
writeVarList(keyVarList, funcArgs);
// Write non-key var list.
@@ -91,16 +108,18 @@
super.readFromFuncArgs(funcArgs);
int index = super.getNumParams();
// Read search modifier type.
- int searchModifierOrdinal = AccessMethodUtils.getInt32Constant(funcArgs.get(index));
+ int searchModifierOrdinal = AccessMethodUtils.getInt32Constant(funcArgs.get(index + SEARCH_MODIFIER_INDEX));
searchModifierType = SearchModifierType.values()[searchModifierOrdinal];
// Read similarity threshold. Concrete type depends on search modifier.
- similarityThreshold = (((ConstantExpression) funcArgs.get(index + 1).getValue()).getValue());
+ similarityThreshold = ((ConstantExpression) funcArgs.get(index + SIM_THRESHOLD_INDEX).getValue()).getValue();
// Read type of search key.
- int typeTagOrdinal = AccessMethodUtils.getInt32Constant(funcArgs.get(index + 2));
+ int typeTagOrdinal = AccessMethodUtils.getInt32Constant(funcArgs.get(index + SEARCH_KEY_TYPE_INDEX));
searchKeyType = ATypeTag.values()[typeTagOrdinal];
+ // Read full-text search information.
+ isFullTextSearchQuery = AccessMethodUtils.getBooleanConstant(funcArgs.get(index + IS_FULLTEXT_SEARCH_INDEX));
// Read key var list.
keyVarList = new ArrayList<LogicalVariable>();
- readVarList(funcArgs, index + 3, keyVarList);
+ readVarList(funcArgs, index + KEY_VAR_INDEX, keyVarList);
// TODO: We could possibly simplify things if we did read the non-key var list here.
// We don't need to read the non-key var list.
nonKeyVarList = null;
@@ -110,6 +129,10 @@
return searchModifierType;
}
+ public boolean getIsFullTextSearch() {
+ return isFullTextSearchQuery;
+ }
+
public IAlgebricksConstantValue getSimilarityThreshold() {
return similarityThreshold;
}
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
index 144531e..dc9ff17 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
@@ -153,6 +153,7 @@
import org.apache.asterix.runtime.evaluators.functions.EditDistanceListIsFilterableDescriptor;
import org.apache.asterix.runtime.evaluators.functions.EditDistanceStringIsFilterableDescriptor;
import org.apache.asterix.runtime.evaluators.functions.FullTextContainsDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.FullTextContainsWithoutOptionDescriptor;
import org.apache.asterix.runtime.evaluators.functions.GetItemDescriptor;
import org.apache.asterix.runtime.evaluators.functions.GramTokensDescriptor;
import org.apache.asterix.runtime.evaluators.functions.HashedGramTokensDescriptor;
@@ -598,6 +599,7 @@
// full-text function
functionsToInjectUnkownHandling.add(FullTextContainsDescriptor.FACTORY);
+ functionsToInjectUnkownHandling.add(FullTextContainsWithoutOptionDescriptor.FACTORY);
// Record functions.
functionsToInjectUnkownHandling.add(GetRecordFieldsDescriptor.FACTORY);
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains-without-option.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains-without-option.aql
new file mode 100644
index 0000000..eee411c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains-without-option.aql
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Tests whether an full-text index is applied to optimize a selection query
+ * : using the ftcontains function. The index should be applied.
+ * Success : Yes
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
+
+write output to asterix_nc1:"rttest/inverted-index-basic_fulltext-contains-without-option.adm";
+
+for $o in dataset MyData
+where ftcontains($o.title, "database")
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains.aql b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains.aql
new file mode 100644
index 0000000..bc697df
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/inverted-index-basic/fulltext-contains.aql
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Tests whether an full-text index is applied to optimize a selection query
+ * : using the ftcontains function. The index should be applied.
+ * Success : Yes
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
+
+write output to asterix_nc1:"rttest/inverted-index-basic_fulltext-contains.adm";
+
+for $o in dataset MyData
+where ftcontains($o.title, "database", {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains-without-option.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains-without-option.plan
new file mode 100644
index 0000000..8e1f97c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains-without-option.plan
@@ -0,0 +1,16 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- SORT_MERGE_EXCHANGE [$$7(ASC) ] |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$12(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains.plan b/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains.plan
new file mode 100644
index 0000000..fc894d9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/optimizerts/results/inverted-index-basic/fulltext-contains.plan
@@ -0,0 +1,16 @@
+-- DISTRIBUTE_RESULT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- SORT_MERGE_EXCHANGE [$$8(ASC) ] |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$13(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- SINGLE_PARTITION_INVERTED_INDEX_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.1.ddl.aql
index 6c731a9..3619c65 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.1.ddl.aql
@@ -23,6 +23,9 @@
* : query #3 - single string value query
* : query #4 - single string value in an ordered list query
* : query #5 - single string value in an unordered list query
+ * : query #6 - the same as #3, but without any option
+ * : query #7 - the same as #4, but without any option
+ * : query #8 - the same as #5, but without any option
* Expected Result : Success
*
*/
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.6.query.aql
new file mode 100644
index 0000000..93e7d2b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.6.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, "database")
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.7.query.aql
new file mode 100644
index 0000000..7409e15
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.7.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["database"])
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.8.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.8.query.aql
new file mode 100644
index 0000000..8ef67dd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-01/fulltext-01.8.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"database"}})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.1.ddl.aql
index eba30c4..e374593 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.1.ddl.aql
@@ -28,6 +28,8 @@
* : in this case, "any" option that enforces a disjunctive search will be applied.
* : query #6 - the same as query #6, but with a different option - "all"
* : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #7 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #8 - the same as query #6, but without any option that is equivalent to "all".
* Expected Result : Success
*
*/
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.7.query.aql
new file mode 100644
index 0000000..16478b2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.7.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["object","database"])
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.8.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.8.query.aql
new file mode 100644
index 0000000..cd8165c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-02/fulltext-02.8.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"object","database"}})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.1.ddl.aql
index 9096d89..8b35f2c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.1.ddl.aql
@@ -33,6 +33,9 @@
* : in this case, "any" option that enforces a disjunctive search will be applied.
* : query #8 - the same as query #7, but with a different option - "all"
* : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #9 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #10 - the same as query #6, but without any option that is equivalent to "all".
+ * : query #11 - the same as query #8, but without any option that is equivalent to "all".
* Expected Result : Success
*
*/
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.10.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.10.query.aql
new file mode 100644
index 0000000..402c25c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.10.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := {{"object", "database"}}
+where ftcontains($o.title, $list)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.11.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.11.query.aql
new file mode 100644
index 0000000..06adaaa
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.11.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, for $list in dataset MyKeywordData return $list.keyword_text)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.9.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.9.query.aql
new file mode 100644
index 0000000..93df951
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-03/fulltext-03.9.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := ["object", "database"]
+where ftcontains($o.title, $list)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-05/fulltext-05.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-05/fulltext-05.1.ddl.aql
index 011a86e..a80fbed 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-05/fulltext-05.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-05/fulltext-05.1.ddl.aql
@@ -54,5 +54,3 @@
create dataset MyKeywordData(MyKeyword)
primary key keyword_text;
-
-create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-06/fulltext-06.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-06/fulltext-06.1.ddl.aql
index e155ba8..bfed240 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-06/fulltext-06.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-06/fulltext-06.1.ddl.aql
@@ -54,5 +54,3 @@
create dataset MyKeywordData(MyKeyword)
primary key keyword_text;
-
-create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.1.ddl.aql
index 13e5506..7cdc675 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.1.ddl.aql
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.1.ddl.aql
@@ -20,11 +20,14 @@
/*
* Description : Full-text search non-index test
* : This test is intended to verify that the full-text search works as expected.
+ * : But, the form of the query is join. So, each keyword from the outer dataset will be processed
+ * : separately. Thus, query #3 and query #4 should generate the same result.
* : query #3 - two string values in [an ordered list] query with "any" option.
* : an ordered list is first initialized by let clause and is being used.
* : in this case, "any" option that enforces a disjunctive search will be applied.
* : query #4 - the same as query #3, but with a different option - "all"
* : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - the same as query #4, but without any option that is equivalent to "all".
* Expected Result : Success
*
*/
@@ -57,5 +60,3 @@
create dataset MyKeywordData(MyKeyword)
primary key keyword_text;
-
-create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.5.query.aql
new file mode 100644
index 0000000..ceeb2ad
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-07/fulltext-07.5.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $k in dataset MyKeywordData
+for $t in dataset MyData
+where ftcontains($t.title, $k.keyword_text, {"mode":"all"})
+order by $t.id
+return {"id":$t.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.aql
new file mode 100644
index 0000000..bfef89a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.aql
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - single string value query
+ * : query #4 - single string value in an ordered list query
+ * : query #5 - single string value in an unordered list query
+ * : query #6 - the same as #3, but without any option
+ * : query #7 - the same as #4, but without any option
+ * : query #8 - the same as #5, but without any option
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.2.update.aql
new file mode 100644
index 0000000..c627cf1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.2.update.aql
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.3.query.aql
new file mode 100644
index 0000000..bc47bb6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.3.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, "database", {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.4.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.4.query.aql
new file mode 100644
index 0000000..53cecb6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.4.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["database"], {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.5.query.aql
new file mode 100644
index 0000000..2a4ddea
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.5.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"database"}}, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.6.query.aql
new file mode 100644
index 0000000..93e7d2b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.6.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, "database")
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.7.query.aql
new file mode 100644
index 0000000..7409e15
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.7.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["database"])
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.8.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.8.query.aql
new file mode 100644
index 0000000..8ef67dd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-01/fulltext-index-01.8.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"database"}})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.aql
new file mode 100644
index 0000000..8d47c6d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.aql
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - two string values in [an ordered list] query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #4 - the same as query #3, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - two string values in {{an unordered list}} query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #6 - the same as query #6, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #7 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #8 - the same as query #6, but without any option that is equivalent to "all".
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.2.update.aql
new file mode 100644
index 0000000..c627cf1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.2.update.aql
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.3.query.aql
new file mode 100644
index 0000000..caa4a9a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.3.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["object","database"], {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.4.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.4.query.aql
new file mode 100644
index 0000000..dc2b30a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.4.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["object","database"], {"mode":"all"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.5.query.aql
new file mode 100644
index 0000000..05c2a37
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.5.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"object","database"}}, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.6.query.aql
new file mode 100644
index 0000000..7cd2428
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.6.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"object","database"}}, {"mode":"all"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.7.query.aql
new file mode 100644
index 0000000..16478b2
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.7.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["object","database"])
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.8.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.8.query.aql
new file mode 100644
index 0000000..cd8165c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-02/fulltext-index-02.8.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"object","database"}})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.1.ddl.aql
new file mode 100644
index 0000000..46ddb71
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.1.ddl.aql
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : In this test, search predicate is provided as a variable.
+ * : query #3 - two string values in [an ordered list] query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #4 - the same as query #3, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - two string values in {{an unordered list}} query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #6 - the same as query #5, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #7 - two string values in a dataset query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #8 - the same as query #7, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #9 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #10 - the same as query #6, but without any option that is equivalent to "all".
+ * : query #11 - the same as query #8, but without any option that is equivalent to "all".
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create type MyKeyword as closed {
+ keyword_text: string
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create dataset MyKeywordData(MyKeyword)
+ primary key keyword_text;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.10.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.10.query.aql
new file mode 100644
index 0000000..402c25c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.10.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := {{"object", "database"}}
+where ftcontains($o.title, $list)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.11.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.11.query.aql
new file mode 100644
index 0000000..06adaaa
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.11.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, for $list in dataset MyKeywordData return $list.keyword_text)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.2.update.aql
new file mode 100644
index 0000000..d60dd6a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.2.update.aql
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
+
+insert into dataset MyKeywordData ({"keyword_text":"object"});
+
+insert into dataset MyKeywordData ({"keyword_text":"database"});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.3.query.aql
new file mode 100644
index 0000000..dcf61c5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.3.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := ["object", "database"]
+where ftcontains($o.title, $list, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.4.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.4.query.aql
new file mode 100644
index 0000000..86fe5d4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.4.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := ["object", "database"]
+where ftcontains($o.title, $list, {"mode":"all"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.5.query.aql
new file mode 100644
index 0000000..5d0a546
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.5.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := {{"object", "database"}}
+where ftcontains($o.title, $list, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.6.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.6.query.aql
new file mode 100644
index 0000000..7def1fa
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.6.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := {{"object", "database"}}
+where ftcontains($o.title, $list, {"mode":"all"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.7.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.7.query.aql
new file mode 100644
index 0000000..4cc2f45
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.7.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, for $list in dataset MyKeywordData return $list.keyword_text, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.8.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.8.query.aql
new file mode 100644
index 0000000..bae1da5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.8.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, for $list in dataset MyKeywordData return $list.keyword_text, {"mode":"all"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.9.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.9.query.aql
new file mode 100644
index 0000000..93df951
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-03/fulltext-index-03.9.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+let $list := ["object", "database"]
+where ftcontains($o.title, $list)
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.1.ddl.aql
new file mode 100644
index 0000000..5664ee9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.1.ddl.aql
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search DOES NOT work as expected.
+ * : query #3 - a string phrase is provided as a query predicate.
+ * : this should throw an exception since we don't support a phrase search yet.
+ * Expected Result : Exception
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create type MyKeyword as closed {
+ keyword_text: string
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create dataset MyKeywordData(MyKeyword)
+ primary key keyword_text;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.2.update.aql
new file mode 100644
index 0000000..bd244d0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.2.update.aql
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.3.query.aql
new file mode 100644
index 0000000..2769cbd
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-04/fulltext-index-04.3.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, "object database", {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.1.ddl.aql
new file mode 100644
index 0000000..07ebb6c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.1.ddl.aql
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search DOES NOT work as expected.
+ * : query #3 - a string phrase in an ordered list is provided as a query predicate.
+ * : this should throw an exception since we don't support a phrase search yet.
+ * Expected Result : Exception
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create type MyKeyword as closed {
+ keyword_text: string
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create dataset MyKeywordData(MyKeyword)
+ primary key keyword_text;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.2.update.aql
new file mode 100644
index 0000000..bd244d0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.2.update.aql
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.3.query.aql
new file mode 100644
index 0000000..5d4bd2f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-05/fulltext-index-05.3.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, ["object database","systems"], {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.1.ddl.aql
new file mode 100644
index 0000000..7295edf
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.1.ddl.aql
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search DOES NOT work as expected.
+ * : query #3 - a string phrase in an unordered list is provided as a query predicate.
+ * : this should throw an exception since we don't support a phrase search yet.
+ * Expected Result : Exception
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create type MyKeyword as closed {
+ keyword_text: string
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create dataset MyKeywordData(MyKeyword)
+ primary key keyword_text;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.2.update.aql
new file mode 100644
index 0000000..bd244d0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.2.update.aql
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.3.query.aql
new file mode 100644
index 0000000..a509e10
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-06/fulltext-index-06.3.query.aql
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $o in dataset MyData
+where ftcontains($o.title, {{"object database","systems"}}, {"mode":"any"})
+order by $o.id
+return {"id":$o.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.1.ddl.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.1.ddl.aql
new file mode 100644
index 0000000..4776959
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.1.ddl.aql
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : But, the form of the query is join. So, each keyword from the outer dataset will be processed
+ * : separately. Thus, query #3 and query #4 should generate the same result.
+ * : query #3 - two string values in [an ordered list] query with "any" option.
+ * : an ordered list is first initialized by let clause and is being used.
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #4 - the same as query #3, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - the same as query #4, but without any option that is equivalent to "all".
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create type MyKeyword as closed {
+ keyword_text: string
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create dataset MyKeywordData(MyKeyword)
+ primary key keyword_text;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.2.update.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.2.update.aql
new file mode 100644
index 0000000..d60dd6a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.2.update.aql
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
+
+insert into dataset MyKeywordData ({"keyword_text":"object"});
+
+insert into dataset MyKeywordData ({"keyword_text":"database"});
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.3.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.3.query.aql
new file mode 100644
index 0000000..f567c7b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.3.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $k in dataset MyKeywordData
+for $t in dataset MyData
+where ftcontains($t.title, $k.keyword_text, {"mode":"any"})
+order by $t.id
+return {"id":$t.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.4.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.4.query.aql
new file mode 100644
index 0000000..ceeb2ad
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.4.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $k in dataset MyKeywordData
+for $t in dataset MyData
+where ftcontains($t.title, $k.keyword_text, {"mode":"all"})
+order by $t.id
+return {"id":$t.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.5.query.aql b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.5.query.aql
new file mode 100644
index 0000000..8fabc02
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries/fulltext/fulltext-index-07/fulltext-index-07.5.query.aql
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+use dataverse test;
+
+for $k in dataset MyKeywordData
+for $t in dataset MyData
+where ftcontains($t.title, $k.keyword_text)
+order by $t.id
+return {"id":$t.id}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.1.ddl.sqlpp
new file mode 100644
index 0000000..2812177
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.1.ddl.sqlpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search non-index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - single string value query
+ * : query #4 - single string value in an ordered list query
+ * : query #5 - single string value in an unordered list query
+ * : query #6 - the same as #3, but without any option
+ * : query #7 - the same as #4, but without any option
+ * : query #8 - the same as #5, but without any option
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.2.update.sqlpp
new file mode 100644
index 0000000..9b7c1f6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.3.query.sqlpp
new file mode 100644
index 0000000..8ffc5c1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, "database", {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.4.query.sqlpp
new file mode 100644
index 0000000..a9278e3
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.4.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["database"], {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.5.query.sqlpp
new file mode 100644
index 0000000..a054829
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.5.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"database"}}, {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.6.query.sqlpp
new file mode 100644
index 0000000..c4869b5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, "database")
+order by ftval.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.7.query.sqlpp
new file mode 100644
index 0000000..ef3c4e4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.7.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["database"])
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.8.query.sqlpp
new file mode 100644
index 0000000..895b73e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-01/fulltext-01.8.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"database"}})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.1.ddl.sqlpp
new file mode 100644
index 0000000..6bff4a1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.1.ddl.sqlpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search non-index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - two string values in [an ordered list] query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #4 - the same as query #3, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - two string values in {{an unordered list}} query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #6 - the same as query #6, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #7 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #8 - the same as query #6, but without any option that is equivalent to "all".
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.2.update.sqlpp
new file mode 100644
index 0000000..9b7c1f6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.3.query.sqlpp
new file mode 100644
index 0000000..28c4190
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"], {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.4.query.sqlpp
new file mode 100644
index 0000000..75346ef
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.4.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"], {"mode":"all"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.5.query.sqlpp
new file mode 100644
index 0000000..b61316c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.5.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}}, {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.6.query.sqlpp
new file mode 100644
index 0000000..d5b6a1a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}}, {"mode":"all"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.7.query.sqlpp
new file mode 100644
index 0000000..7fcf906
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.7.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"])
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.8.query.sqlpp
new file mode 100644
index 0000000..ae78564
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-02/fulltext-02.8.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.sqlpp
new file mode 100644
index 0000000..ef7c98d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.1.ddl.sqlpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - single string value query
+ * : query #4 - single string value in an ordered list query
+ * : query #5 - single string value in an unordered list query
+ * : query #6 - the same as #3, but without any option
+ * : query #7 - the same as #4, but without any option
+ * : query #8 - the same as #5, but without any option
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.2.update.sqlpp
new file mode 100644
index 0000000..9b7c1f6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.3.query.sqlpp
new file mode 100644
index 0000000..8ffc5c1
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, "database", {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.4.query.sqlpp
new file mode 100644
index 0000000..a9278e3
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.4.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["database"], {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.5.query.sqlpp
new file mode 100644
index 0000000..a054829
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.5.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"database"}}, {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.6.query.sqlpp
new file mode 100644
index 0000000..c4869b5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, "database")
+order by ftval.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.7.query.sqlpp
new file mode 100644
index 0000000..ef3c4e4
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.7.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["database"])
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.8.query.sqlpp
new file mode 100644
index 0000000..895b73e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-01/fulltext-index-01.8.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"database"}})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.sqlpp
new file mode 100644
index 0000000..63b0a65
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.1.ddl.sqlpp
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description : Full-text search index test
+ * : This test is intended to verify that the full-text search works as expected.
+ * : query #3 - two string values in [an ordered list] query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #4 - the same as query #3, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #5 - two string values in {{an unordered list}} query with "any" option
+ * : in this case, "any" option that enforces a disjunctive search will be applied.
+ * : query #6 - the same as query #6, but with a different option - "all"
+ * : in this case, we explicitly specify "all" option that enforces a conjunctive search.
+ * : query #7 - the same as query #4, but without any option that is equivalent to "all".
+ * : query #8 - the same as query #6, but without any option that is equivalent to "all".
+ * Expected Result : Success
+ *
+*/
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+create type MyRecord as closed {
+ id: int64,
+ docid: int64,
+ val1: int64,
+ title: string,
+ point: point,
+ kwds: string,
+ line1: line,
+ line2: line,
+ poly1: polygon,
+ poly2: polygon,
+ rec: rectangle,
+ circle: circle
+}
+
+create dataset MyData(MyRecord)
+ primary key id;
+
+create index fulltext_index_title on MyData(title) type fulltext;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.2.update.sqlpp
new file mode 100644
index 0000000..9b7c1f6
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.2.update.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+use test;
+
+load dataset MyData
+using localfs
+(("path"="asterix_nc1://data/spatial/spatialData2.json"),("format"="adm"));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.3.query.sqlpp
new file mode 100644
index 0000000..28c4190
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.3.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"], {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.4.query.sqlpp
new file mode 100644
index 0000000..75346ef
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.4.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"], {"mode":"all"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.5.query.sqlpp
new file mode 100644
index 0000000..b61316c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.5.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}}, {"mode":"any"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.6.query.sqlpp
new file mode 100644
index 0000000..d5b6a1a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.6.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}}, {"mode":"all"})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.7.query.sqlpp
new file mode 100644
index 0000000..7fcf906
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.7.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, ["object","database"])
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.8.query.sqlpp
new file mode 100644
index 0000000..ae78564
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/fulltext/fulltext-index-02/fulltext-index-02.8.query.sqlpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select element {"id":ftval.id}
+from MyData as ftval
+where test.ftcontains(ftval.title, {{"object","database"}})
+order by ftval.id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.6.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.6.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.7.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.7.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.8.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-01/fulltext-01.8.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.7.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.7.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.8.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-02/fulltext-02.8.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.10.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.10.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.10.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.11.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.11.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.11.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.9.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-03/fulltext-03.9.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.3.adm
index 9b34c44..cb8dd44 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.3.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.3.adm
@@ -3,36 +3,50 @@
{ "id": 5 }
{ "id": 6 }
{ "id": 8 }
+{ "id": 8 }
{ "id": 11 }
{ "id": 12 }
{ "id": 13 }
+{ "id": 13 }
+{ "id": 16 }
{ "id": 16 }
{ "id": 17 }
{ "id": 19 }
+{ "id": 19 }
{ "id": 20 }
{ "id": 21 }
{ "id": 22 }
{ "id": 23 }
+{ "id": 23 }
+{ "id": 26 }
{ "id": 26 }
{ "id": 27 }
{ "id": 29 }
+{ "id": 29 }
{ "id": 30 }
{ "id": 31 }
{ "id": 32 }
{ "id": 35 }
{ "id": 36 }
{ "id": 38 }
+{ "id": 38 }
{ "id": 41 }
{ "id": 42 }
{ "id": 43 }
+{ "id": 43 }
+{ "id": 46 }
{ "id": 46 }
{ "id": 47 }
{ "id": 49 }
+{ "id": 49 }
{ "id": 50 }
{ "id": 51 }
{ "id": 52 }
{ "id": 53 }
+{ "id": 53 }
+{ "id": 56 }
{ "id": 56 }
{ "id": 57 }
{ "id": 59 }
+{ "id": 59 }
{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.4.adm
index acde73f..cb8dd44 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.4.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.4.adm
@@ -1,14 +1,52 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
{ "id": 8 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
{ "id": 13 }
{ "id": 16 }
+{ "id": 16 }
+{ "id": 17 }
{ "id": 19 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
{ "id": 23 }
{ "id": 26 }
+{ "id": 26 }
+{ "id": 27 }
{ "id": 29 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
{ "id": 38 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
{ "id": 43 }
{ "id": 46 }
+{ "id": 46 }
+{ "id": 47 }
{ "id": 49 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
{ "id": 53 }
{ "id": 56 }
+{ "id": 56 }
+{ "id": 57 }
{ "id": 59 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.5.adm
new file mode 100644
index 0000000..cb8dd44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-07/fulltext-07.5.adm
@@ -0,0 +1,52 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.3.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.3.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.4.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.4.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.5.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.5.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.6.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.6.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.7.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.7.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.8.adm
new file mode 100644
index 0000000..a64e700
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-01/fulltext-index-01.8.adm
@@ -0,0 +1,20 @@
+{ "id": 5 }
+{ "id": 8 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 35 }
+{ "id": 38 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.3.adm
new file mode 100644
index 0000000..9b34c44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.3.adm
@@ -0,0 +1,38 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.4.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.4.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.5.adm
new file mode 100644
index 0000000..9b34c44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.5.adm
@@ -0,0 +1,38 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.6.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.6.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.7.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.7.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.8.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-02/fulltext-index-02.8.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.10.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.10.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.10.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.11.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.11.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.11.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.3.adm
new file mode 100644
index 0000000..9b34c44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.3.adm
@@ -0,0 +1,38 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.4.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.4.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.5.adm
new file mode 100644
index 0000000..9b34c44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.5.adm
@@ -0,0 +1,38 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.6.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.6.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.7.adm
new file mode 100644
index 0000000..9b34c44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.7.adm
@@ -0,0 +1,38 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.8.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.8.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.9.adm
new file mode 100644
index 0000000..acde73f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-03/fulltext-index-03.9.adm
@@ -0,0 +1,14 @@
+{ "id": 8 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 19 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 29 }
+{ "id": 38 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 49 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 59 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-04/fulltext-index-04.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-04/fulltext-index-04.3.adm
new file mode 100644
index 0000000..0787798
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-04/fulltext-index-04.3.adm
@@ -0,0 +1 @@
+{ "id": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-05/fulltext-index-05.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-05/fulltext-index-05.3.adm
new file mode 100644
index 0000000..0787798
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-05/fulltext-index-05.3.adm
@@ -0,0 +1 @@
+{ "id": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-06/fulltext-index-06.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-06/fulltext-index-06.3.adm
new file mode 100644
index 0000000..0787798
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-06/fulltext-index-06.3.adm
@@ -0,0 +1 @@
+{ "id": 1 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.3.adm
new file mode 100644
index 0000000..cb8dd44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.3.adm
@@ -0,0 +1,52 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.4.adm
new file mode 100644
index 0000000..cb8dd44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.4.adm
@@ -0,0 +1,52 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.5.adm
new file mode 100644
index 0000000..cb8dd44
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/fulltext/fulltext-index-07/fulltext-index-07.5.adm
@@ -0,0 +1,52 @@
+{ "id": 1 }
+{ "id": 2 }
+{ "id": 5 }
+{ "id": 6 }
+{ "id": 8 }
+{ "id": 8 }
+{ "id": 11 }
+{ "id": 12 }
+{ "id": 13 }
+{ "id": 13 }
+{ "id": 16 }
+{ "id": 16 }
+{ "id": 17 }
+{ "id": 19 }
+{ "id": 19 }
+{ "id": 20 }
+{ "id": 21 }
+{ "id": 22 }
+{ "id": 23 }
+{ "id": 23 }
+{ "id": 26 }
+{ "id": 26 }
+{ "id": 27 }
+{ "id": 29 }
+{ "id": 29 }
+{ "id": 30 }
+{ "id": 31 }
+{ "id": 32 }
+{ "id": 35 }
+{ "id": 36 }
+{ "id": 38 }
+{ "id": 38 }
+{ "id": 41 }
+{ "id": 42 }
+{ "id": 43 }
+{ "id": 43 }
+{ "id": 46 }
+{ "id": 46 }
+{ "id": 47 }
+{ "id": 49 }
+{ "id": 49 }
+{ "id": 50 }
+{ "id": 51 }
+{ "id": 52 }
+{ "id": 53 }
+{ "id": 53 }
+{ "id": 56 }
+{ "id": 56 }
+{ "id": 57 }
+{ "id": 59 }
+{ "id": 59 }
+{ "id": 60 }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
index 3f33680..65ec9d9 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -387,6 +387,77 @@
<output-dir compare="Text">fulltext-01</output-dir>
</compilation-unit>
</test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-02">
+ <output-dir compare="Text">fulltext-02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-03">
+ <output-dir compare="Text">fulltext-03</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-04">
+ <output-dir compare="Text">fulltext-04</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-05">
+ <output-dir compare="Text">fulltext-05</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-06">
+ <output-dir compare="Text">fulltext-06</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-07">
+ <output-dir compare="Text">fulltext-07</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-01">
+ <output-dir compare="Text">fulltext-index-01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-02">
+ <output-dir compare="Text">fulltext-index-02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-03">
+ <output-dir compare="Text">fulltext-index-03</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-04">
+ <output-dir compare="Text">fulltext-index-04</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-05">
+ <output-dir compare="Text">fulltext-index-05</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-06">
+ <output-dir compare="Text">fulltext-index-06</output-dir>
+ <expected-error>Phrase search in Full-text is not yet supported. Only one keyword per expression is permitted. </expected-error>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-07">
+ <output-dir compare="Text">fulltext-index-07</output-dir>
+ </compilation-unit>
+ </test-case>
</test-group>
<test-group name="union">
<test-case FilePath="union">
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index ff1c530..c8785fe 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -2453,6 +2453,28 @@
</compilation-unit>
</test-case>
</test-group> -->
+ <test-group name="fulltext">
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-01">
+ <output-dir compare="Text">fulltext-01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-02">
+ <output-dir compare="Text">fulltext-02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-01">
+ <output-dir compare="Text">fulltext-index-01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="fulltext">
+ <compilation-unit name="fulltext-index-02">
+ <output-dir compare="Text">fulltext-index-02</output-dir>
+ </compilation-unit>
+ </test-case>
+ </test-group>
<test-group name="global-aggregate">
<test-case FilePath="global-aggregate">
<compilation-unit name="q01">
diff --git a/asterixdb/asterix-doc/src/site/markdown/aql/fulltext.md b/asterixdb/asterix-doc/src/site/markdown/aql/fulltext.md
index 921f0b3..4fe17ac 100644
--- a/asterixdb/asterix-doc/src/site/markdown/aql/fulltext.md
+++ b/asterixdb/asterix-doc/src/site/markdown/aql/fulltext.md
@@ -39,9 +39,10 @@
## <a id="Syntax">Syntax</a> <font size="4"><a href="#toc">[Back to TOC]</a></font> ##
The syntax of AsterixDB FTS follows a portion of the XQuery FullText Search syntax.
-A basic form is as follows:
+Two basic forms are as follows:
ftcontains(Expression1, Expression2, {FullTextOption})
+ ftcontains(Expression1, Expression2)
For example, we can execute the following query to find tweet messages where the `message-text` field includes
“voice” as a word. Please note that an FTS search is case-insensitive.
@@ -62,6 +63,7 @@
The following examples are all valid expressions.
+ ... where ftcontains($msg.message-text, "sound")
... where ftcontains($msg.message-text, "sound", {"mode":"any"})
... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"any"})
... where ftcontains($msg.message-text, {{"speed", "stand", "customization"}}, {"mode":"all"})
@@ -70,30 +72,34 @@
In the last example above, `$keyword_list` should evaluate to a string or an (un)ordered list of string value(s).
-The last `FullTextOption` parameter clarifies the given FTS request. Currently, we only have one option named `mode`.
+The last `FullTextOption` parameter clarifies the given FTS request. If you omit the `FullTextOption` parameter,
+then the default value will be set for each possible option. Currently, we only have one option named `mode`.
And as we extend the FTS feature, more options will be added. Please note that the format of `FullTextOption`
is a record, thus you need to put the option(s) in a record `{}`.
The `mode` option indicates whether the given FTS query is a conjunctive (AND) or disjunctive (OR) search request.
-This option can be either `“any”` or `“all”`. If one specifies `“any”`, a disjunctive search will be conducted.
-For example, the following query will find documents whose `message-text` field contains “sound” or “system”,
-so a document will be returned if it contains either “sound”, “system”, or both of the keywords.
+This option can be either `“any”` or `“all”`. The default value for `mode` is `“all”`. If one specifies `“any”`,
+a disjunctive search will be conducted. For example, the following query will find documents whose `message-text`
+field contains “sound” or “system”, so a document will be returned if it contains either “sound”, “system”,
+or both of the keywords.
... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"any"})
-The other option parameter,`“all”`, specifies a conjunctive search. The following example will find the documents whose
+The other option parameter,`“all”`, specifies a conjunctive search. The following examples will find the documents whose
`message-text` field contains both “sound” and “system”. If a document contains only “sound” or “system” but
not both, it will not be returned.
... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"all"})
+ ... where ftcontains($msg.message-text, ["sound", "system"])
Currently AsterixDB doesn’t (yet) support phrase searches, so the following query will not work.
... where ftcontains($msg.message-text, "sound system", {"mode":"any"})
As a workaround solution, the following query can be used to achieve a roughly similar goal. The difference is that
-the following query will find documents where `$msg.message-text` contains both “sound” and “system”, but the order
+the following queries will find documents where `$msg.message-text` contains both “sound” and “system”, but the order
and adjacency of “sound” and “system” are not checked, unlike in a phrase search. As a result, the query below would
also return documents with “sound system can be installed.”, “system sound is perfect.”,
or “sound is not clear. You may need to install a new system.”
... where ftcontains($msg.message-text, ["sound", "system"], {"mode":"all"})
+ ... where ftcontains($msg.message-text, ["sound", "system"])
diff --git a/asterixdb/asterix-doc/src/site/markdown/aql/manual.md b/asterixdb/asterix-doc/src/site/markdown/aql/manual.md
index ecdc715..95c752f 100644
--- a/asterixdb/asterix-doc/src/site/markdown/aql/manual.md
+++ b/asterixdb/asterix-doc/src/site/markdown/aql/manual.md
@@ -700,10 +700,11 @@
| "rtree"
| "keyword"
| "ngram" "(" IntegerLiteral ")"
+ | "fulltext"
The create index statement creates a secondary index on one or more fields of a specified dataset.
Supported index types include `btree` for totally ordered datatypes,
-`rtree` for spatial data, and `keyword` and `ngram` for textual (string) data.
+`rtree` for spatial data, and `keyword`, `ngram`, and `fulltext` for textual (string) data.
An index can be created on a nested field (or fields) by providing a valid path expression as an index field identifier.
An index field is not required to be part of the datatype associated with a dataset if that datatype is declared as
open and the field's type is provided along with its type and the `enforced` keyword is specified in the end of index definition.
@@ -759,6 +760,15 @@
create index fbMessageIdx on FacebookMessages(message) type keyword;
+The following example creates a full-text index called fbMessageIdx on the message field of the FacebookMessages dataset.
+This full-text index can be used to optimize queries with full-text search predicates on the message field.
+For details refer to the [document on full-text queries](fulltext.html#toc).
+
+##### Example
+
+ create index fbMessageIdx on FacebookMessages(message) type fulltext;
+
+
#### Functions
The create function statement creates a named function that can then be used and reused in AQL queries.
diff --git a/asterixdb/asterix-doc/src/site/site.xml b/asterixdb/asterix-doc/src/site/site.xml
index 4c0ba6e..0e2efc8 100644
--- a/asterixdb/asterix-doc/src/site/site.xml
+++ b/asterixdb/asterix-doc/src/site/site.xml
@@ -100,6 +100,7 @@
<menu name="Advanced Features">
<item name="Support of Similarity Queries" href="aql/similarity.html"/>
+ <item name="Support of Full-text Queries" href="aql/fulltext.html"/>
<item name="Accessing External Data" href="aql/externaldata.html"/>
<item name="Support for Data Ingestion" href="feeds/tutorial.html"/>
<item name="User Defined Functions" href="udf.html"/>
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index c43ff66..9be5f8a 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -631,6 +631,10 @@
{
type = IndexType.LENGTH_PARTITIONED_WORD_INVIX;
}
+ |<FULLTEXT>
+ {
+ type = IndexType.SINGLE_PARTITION_WORD_INVIX;
+ }
|<NGRAM> <LEFTPAREN> <INTEGER_LITERAL>
{
type = IndexType.LENGTH_PARTITIONED_NGRAM_INVIX;
@@ -2662,6 +2666,7 @@
| <FOR : "for">
| <FORMAT : "format">
| <FROM : "from">
+ | <FULLTEXT : "fulltext">
| <FUNCTION : "function">
| <GROUP : "group">
| <HINTS : "hints">
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index fb2d3bd..7a96fac 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -989,6 +989,8 @@
return "btree";
case RTREE:
return "rtree";
+ case SINGLE_PARTITION_WORD_INVIX:
+ return "fulltext";
case LENGTH_PARTITIONED_WORD_INVIX:
return "keyword";
case LENGTH_PARTITIONED_NGRAM_INVIX:
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index b6334c8..e08f758 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -673,6 +673,10 @@
{
type = IndexType.LENGTH_PARTITIONED_WORD_INVIX;
}
+ |<FULLTEXT>
+ {
+ type = IndexType.SINGLE_PARTITION_WORD_INVIX;
+ }
| <NGRAM> <LEFTPAREN> <INTEGER_LITERAL>
{
type = IndexType.LENGTH_PARTITIONED_NGRAM_INVIX;
@@ -3107,6 +3111,7 @@
| <FOR : "for">
| <FROM : "from">
| <FULL : "full">
+ | <FULLTEXT : "fulltext">
| <FUNCTION : "function">
| <GROUP : "group">
| <HAVING : "having">
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/AOrderedListBinaryTokenizer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/AOrderedListBinaryTokenizer.java
index 32207d3..ace692f 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/AOrderedListBinaryTokenizer.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/dataflow/data/common/AOrderedListBinaryTokenizer.java
@@ -26,6 +26,7 @@
import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.IBinaryTokenizer;
import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.IToken;
import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.ITokenFactory;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.TokenizerInfo.TokenizerType;
public class AOrderedListBinaryTokenizer implements IBinaryTokenizer {
@@ -90,4 +91,9 @@
public short getTokensCount() {
return (short) listLength;
}
+
+ @Override
+ public TokenizerType getTokenizerType() {
+ return TokenizerType.LIST;
+ }
}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index 089f804..3f3a5bd 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -487,8 +487,11 @@
"edit-distance-contains", 3);
// full-text
- public static final FunctionIdentifier FULLTEXT_CONTAINS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
- "ftcontains", 3);
+ public static final FunctionIdentifier FULLTEXT_CONTAINS =
+ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "ftcontains", 3);
+ // full-text without any option provided
+ public static final FunctionIdentifier FULLTEXT_CONTAINS_WO_OPTION =
+ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "ftcontains", 2);
// tokenizers:
public static final FunctionIdentifier WORD_TOKENS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
@@ -1033,6 +1036,7 @@
// Full-text function
addFunction(FULLTEXT_CONTAINS, ABooleanTypeComputer.INSTANCE, true);
+ addFunction(FULLTEXT_CONTAINS_WO_OPTION, ABooleanTypeComputer.INSTANCE, true);
// Spatial functions
addFunction(SPATIAL_AREA, ADoubleTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/util/ConstantExpressionUtil.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/util/ConstantExpressionUtil.java
index e627d95..406f356 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/util/ConstantExpressionUtil.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/util/ConstantExpressionUtil.java
@@ -21,7 +21,9 @@
import org.apache.asterix.om.base.ABoolean;
import org.apache.asterix.om.base.AInt32;
import org.apache.asterix.om.base.AInt64;
+import org.apache.asterix.om.base.AOrderedList;
import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.base.AUnorderedList;
import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.types.ATypeTag;
@@ -36,7 +38,7 @@
private ConstantExpressionUtil() {
}
- private static IAObject getConstantIaObject(ILogicalExpression expr, ATypeTag typeTag) {
+ public static IAObject getConstantIaObject(ILogicalExpression expr, ATypeTag typeTag) {
if (expr.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
return null;
}
@@ -72,6 +74,21 @@
return iaObject != null ? ((AString) iaObject).getStringValue() : null;
}
+ public static String getStringConstant(IAObject iaObject) {
+ // Make sure to call this method after checking the type of the given object.
+ return iaObject != null ? ((AString) iaObject).getStringValue() : null;
+ }
+
+ public static AOrderedList getOrderedListConstant(IAObject iaObject) {
+ // Make sure to call this method after checking the type of the given object.
+ return iaObject != null ? (AOrderedList) iaObject : null;
+ }
+
+ public static AUnorderedList getUnorderedListConstant(IAObject iaObject) {
+ // Make sure to call this method after checking the type of the given object.
+ return iaObject != null ? (AUnorderedList) iaObject : null;
+ }
+
public static Boolean getBooleanConstant(ILogicalExpression expr) {
final IAObject iaObject = getConstantIaObject(expr, ATypeTag.BOOLEAN);
return iaObject != null ? ((ABoolean) iaObject).getBoolean() : null;
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/FullTextContainsEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/FullTextContainsEvaluator.java
index 471b209..b94821f 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/FullTextContainsEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/common/FullTextContainsEvaluator.java
@@ -19,7 +19,6 @@
package org.apache.asterix.runtime.evaluators.common;
import java.io.DataOutput;
-import java.util.Arrays;
import org.apache.asterix.formats.nontagged.BinaryComparatorFactoryProvider;
import org.apache.asterix.formats.nontagged.BinaryTokenizerFactoryProvider;
@@ -92,8 +91,10 @@
// array that contains the key
private BinaryHashSet rightHashSet = null;
- // Checks whether the query array has been changed
+ // Keeps the query array. This is used to check whether the query predicate has been changed (e.g., join case)
private byte[] queryArray = null;
+ private int queryArrayStartOffset = -1;
+ private int queryArrayLength = -1;
// If the following is 1, then we will do a disjunctive search.
// Else if it is equal to the number of tokens, then we will do a conjunctive search.
@@ -172,11 +173,13 @@
*/
private boolean fullTextContainsWithArg(ATypeTag typeTag2, IPointable arg1, IPointable arg2)
throws HyracksDataException {
- // Since a fulltext search form is "X contains text Y",
+ // Since a fulltext search form is "ftcontains(X,Y,options)",
// X (document) is the left side and Y (query predicate) is the right side.
// Initialize variables that are required to conduct full-text search. (e.g., hash-set, tokenizer ...)
- initializeFullTextContains(typeTag2);
+ if (rightHashSet == null) {
+ initializeFullTextContains();
+ }
// Type tag checking is already done in the previous steps.
// So we directly conduct the full-text search process.
@@ -185,7 +188,8 @@
// Checks whether a new query predicate is introduced.
// If not, we can re-use the query predicate array we have already created.
- if (!Arrays.equals(queryArray, arg2Array)) {
+ if (!partOfArrayEquals(queryArray, queryArrayStartOffset, queryArrayLength, arg2Array, arg2.getStartOffset(),
+ arg2.getLength())) {
resetQueryArrayAndRight(arg2Array, typeTag2, arg2);
} else {
// The query predicate remains the same. However, the count of each token should be reset to zero.
@@ -196,23 +200,22 @@
return readLeftAndConductSearch(arg1);
}
- private void initializeFullTextContains(ATypeTag predicateTypeTag) {
+ private void initializeFullTextContains() {
// We use a hash set to store tokens from the right side (query predicate).
// Initialize necessary variables.
- if (rightHashSet == null) {
- hashFunc = new PointableBinaryHashFunctionFactory(UTF8StringLowercaseTokenPointable.FACTORY)
- .createBinaryHashFunction();
- keyEntry = new BinaryEntry();
- // Parameter: number of bucket, frame size, hashFunction, Comparator, byte
- // array that contains the key (this array will be set later.)
- rightHashSet = new BinaryHashSet(HASH_SET_SLOT_SIZE, HASH_SET_FRAME_SIZE, hashFunc, strLowerCaseTokenCmp,
- null);
- tokenizerForLeftArray = BinaryTokenizerFactoryProvider.INSTANCE
- .getWordTokenizerFactory(ATypeTag.STRING, false, true).createTokenizer();
- }
+ hashFunc = new PointableBinaryHashFunctionFactory(UTF8StringLowercaseTokenPointable.FACTORY)
+ .createBinaryHashFunction();
+ keyEntry = new BinaryEntry();
+ // Parameter: number of bucket, frame size, hashFunction, Comparator, byte array
+ // that contains the key (this array will be set later.)
+ rightHashSet = new BinaryHashSet(HASH_SET_SLOT_SIZE, HASH_SET_FRAME_SIZE, hashFunc, strLowerCaseTokenCmp, null);
+ tokenizerForLeftArray = BinaryTokenizerFactoryProvider.INSTANCE
+ .getWordTokenizerFactory(ATypeTag.STRING, false, true).createTokenizer();
+ }
+ void resetQueryArrayAndRight(byte[] arg2Array, ATypeTag typeTag2, IPointable arg2) throws HyracksDataException {
// If the right side is an (un)ordered list, we need to apply the (un)ordered list tokenizer.
- switch (predicateTypeTag) {
+ switch (typeTag2) {
case ORDEREDLIST:
tokenizerForRightArray = BinaryTokenizerFactoryProvider.INSTANCE
.getWordTokenizerFactory(ATypeTag.ORDEREDLIST, false, true).createTokenizer();
@@ -228,11 +231,10 @@
default:
break;
}
- }
- void resetQueryArrayAndRight(byte[] arg2Array, ATypeTag typeTag2, IPointable arg2) throws HyracksDataException {
- queryArray = new byte[arg2Array.length];
- System.arraycopy(arg2Array, 0, queryArray, 0, arg2Array.length);
+ queryArray = arg2Array;
+ queryArrayStartOffset = arg2.getStartOffset();
+ queryArrayLength = arg2.getLength();
// Clear hash set for the search predicates.
rightHashSet.clear();
@@ -242,11 +244,8 @@
int queryTokenCount = 0;
int uniqueQueryTokenCount = 0;
- int startOffset = arg2.getStartOffset();
- int length = arg2.getLength();
-
// Reset the tokenizer for the given keywords in the given query
- tokenizerForRightArray.reset(queryArray, startOffset, length);
+ tokenizerForRightArray.reset(queryArray, queryArrayStartOffset, queryArrayLength);
// Create tokens from the given query predicate
while (tokenizerForRightArray.hasNext()) {
@@ -324,7 +323,8 @@
}
/**
- * Set full-text options. The odd element is an option name and the even element is the argument for that option.
+ * Sets the full-text options. The odd element is an option name and the even element is the argument
+ * for that option. (e.g., argOptions[0] = "mode", argOptions[1] = "all")
*/
private void setFullTextOption(IPointable[] argOptions, int uniqueQueryTokenCount) throws HyracksDataException {
for (int i = 0; i < optionArgsLength; i = i + 2) {
@@ -351,14 +351,14 @@
int foundCount = 0;
// The left side: field (document)
- // Reset the tokenizer for the given keywords in a document.
+ // Resets the tokenizer for the given keywords in a document.
tokenizerForLeftArray.reset(arg1.getByteArray(), arg1.getStartOffset(), arg1.getLength());
- // Create tokens from a field in the left side (document)
+ // Creates tokens from a field in the left side (document)
while (tokenizerForLeftArray.hasNext()) {
tokenizerForLeftArray.next();
- // Record the starting position and the length of the current token.
+ // Records the starting position and the length of the current token.
keyEntry.set(tokenizerForLeftArray.getToken().getStartOffset(),
tokenizerForLeftArray.getToken().getTokenLength());
@@ -386,7 +386,8 @@
}
/**
- * Check the argument types. The argument1 should be a string. The argument2 should be a string or (un)ordered list.
+ * Checks the argument types. The argument1 should be a string.
+ * The argument2 should be a string or an (un)ordered list.
*/
protected boolean checkArgTypes(ATypeTag typeTag1, ATypeTag typeTag2) throws HyracksDataException {
if ((typeTag1 != ATypeTag.STRING) || (typeTag2 != ATypeTag.ORDEREDLIST && typeTag2 != ATypeTag.UNORDEREDLIST
@@ -396,4 +397,31 @@
return true;
}
+ /**
+ * Checks whether the content of the given two arrays are equal.
+ * The code is utilizing the Arrays.equals() code. The difference is that
+ * this method only compares the certain portion of each array.
+ */
+ private static boolean partOfArrayEquals(byte[] array1, int start1, int length1, byte[] array2, int start2,
+ int length2) {
+ // Sanity check
+ if (length1 != length2 || array1 == null || array2 == null) {
+ return false;
+ }
+
+ if (array1 == array2 && start1 == start2 && length1 == length2) {
+ return true;
+ }
+
+ int offset = 0;
+ while (offset < length1) {
+ if (array1[start1 + offset] != array2[start2 + offset]) {
+ return false;
+ }
+ offset++;
+ }
+
+ return true;
+ }
+
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/FullTextContainsWithoutOptionDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/FullTextContainsWithoutOptionDescriptor.java
new file mode 100644
index 0000000..7cfaa62
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/FullTextContainsWithoutOptionDescriptor.java
@@ -0,0 +1,68 @@
+/*
+ * 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.runtime.evaluators.functions;
+
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.common.FullTextContainsEvaluator;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class FullTextContainsWithoutOptionDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+
+ public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new FullTextContainsWithoutOptionDescriptor();
+ }
+ };
+
+ /**
+ * Creates full-text search evaluator. There are two arguments:
+ * arg0: Expression1 - search field
+ * arg1: Expression2 - search predicate
+ */
+ @Override
+ public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args)
+ throws AlgebricksException {
+ return new IScalarEvaluatorFactory() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IScalarEvaluator createScalarEvaluator(IHyracksTaskContext ctx) throws HyracksDataException {
+ return new FullTextContainsEvaluator(args, ctx);
+ }
+ };
+ }
+
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION;
+ }
+
+
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
index 80bb662..352f912 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
@@ -338,11 +338,17 @@
return new FileReference(deviceComputer.compute(path), path);
}
+ // Temp:
@Override
public FileReference resolveAbsolutePath(String path) throws HyracksDataException {
IODeviceHandle devHandle = getDevice(path);
if (devHandle == null) {
- throw new HyracksDataException("The file with absolute path: " + path + " is outside all io devices");
+ String errorMessage = "The file with absolute path: " + path
+ + " is outside all IO devices. IO devices in this node are \n";
+ for (IODeviceHandle d : ioDevices) {
+ errorMessage = errorMessage.concat(d.toString() + '\n');
+ }
+ throw new HyracksDataException(errorMessage);
}
String relativePath = devHandle.getRelativePath(path);
return new FileReference(devHandle, relativePath);
diff --git a/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/BinaryHashSet.java b/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/BinaryHashSet.java
index c3e36da..1996b4e 100644
--- a/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/BinaryHashSet.java
+++ b/hyracks-fullstack/hyracks/hyracks-data/hyracks-data-std/src/main/java/org/apache/hyracks/data/std/util/BinaryHashSet.java
@@ -258,20 +258,19 @@
}
/**
- * Iterate all key entries and reset the foundCount of each key to zero.
+ * Iterates all key entries and resets the foundCount of each key to zero.
*/
public void clearFoundCount() {
- int currentListHeadIndex = 0;
ByteBuffer frame;
int frameNum;
int frameOff;
int headPtr;
- int checkedListHeadIndex = -1;
+ final int resetCount = 0;
- while (true) {
+ for (int currentListHeadIndex = 0; currentListHeadIndex < listHeads.length; currentListHeadIndex++) {
// Position to first non-null list-head pointer.
- while (currentListHeadIndex < listHeads.length && listHeads[currentListHeadIndex] == NULL_PTR) {
- currentListHeadIndex++;
+ if (listHeads[currentListHeadIndex] == NULL_PTR) {
+ continue;
}
headPtr = listHeads[currentListHeadIndex];
do {
@@ -281,18 +280,11 @@
frame = frames.get(frameNum);
// Set the count as zero
- frame.put(frameOff + 2 * SLOT_SIZE, (byte) 0);
+ frame.put(frameOff + 2 * SLOT_SIZE, (byte) resetCount);
// Get next key position
headPtr = frame.getInt(frameOff + 2 * SLOT_SIZE + COUNT_SIZE);
} while (headPtr != NULL_PTR);
-
- if (checkedListHeadIndex == currentListHeadIndex) {
- // no more slots to read - we stop here.
- break;
- }
-
- checkedListHeadIndex = currentListHeadIndex;
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexDataflowHelper.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexDataflowHelper.java
index fd57414..237b567 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexDataflowHelper.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexDataflowHelper.java
@@ -88,7 +88,7 @@
diskFileMapProvider, invIndexOpDesc.getInvListsTypeTraits(),
invIndexOpDesc.getInvListsComparatorFactories(), invIndexOpDesc.getTokenTypeTraits(),
invIndexOpDesc.getTokenComparatorFactories(), invIndexOpDesc.getTokenizerFactory(),
- diskBufferCache, fileRef.getFile().getPath(), bloomFilterFalsePositiveRate, mergePolicy,
+ diskBufferCache, fileRef.getFile().getAbsolutePath(), bloomFilterFalsePositiveRate, mergePolicy,
opTrackerFactory.getOperationTracker(ctx), ioScheduler,
ioOpCallbackFactory.createIOOperationCallback(), invertedIndexFields, filterTypeTraits,
filterCmpFactories, filterFields, filterFieldsForNonBulkLoadOps,
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorDescriptor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorDescriptor.java
index 82a8dc4..7c21c38 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorDescriptor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorDescriptor.java
@@ -47,6 +47,7 @@
private final IInvertedIndexSearchModifierFactory searchModifierFactory;
private final int[] minFilterFieldIndexes;
private final int[] maxFilterFieldIndexes;
+ private final boolean isFullTextSearchQuery;
public LSMInvertedIndexSearchOperatorDescriptor(IOperatorDescriptorRegistry spec, int queryField,
IStorageManagerInterface storageManager, IFileSplitProvider fileSplitProvider,
@@ -57,7 +58,7 @@
IInvertedIndexSearchModifierFactory searchModifierFactory, RecordDescriptor recDesc, boolean retainInput,
boolean retainNull, IMissingWriterFactory nullWriterFactory,
ISearchOperationCallbackFactory searchOpCallbackProvider, int[] minFilterFieldIndexes,
- int[] maxFilterFieldIndexes, IPageManagerFactory pageManagerFactory) {
+ int[] maxFilterFieldIndexes, IPageManagerFactory pageManagerFactory, boolean isFullTextSearchQuery) {
super(spec, 1, 1, recDesc, storageManager, fileSplitProvider, lifecycleManagerProvider, tokenTypeTraits,
tokenComparatorFactories, invListsTypeTraits, invListComparatorFactories, queryTokenizerFactory,
btreeDataflowHelperFactory, null, retainInput, retainNull, nullWriterFactory,
@@ -67,6 +68,7 @@
this.searchModifierFactory = searchModifierFactory;
this.minFilterFieldIndexes = minFilterFieldIndexes;
this.maxFilterFieldIndexes = maxFilterFieldIndexes;
+ this.isFullTextSearchQuery = isFullTextSearchQuery;
}
@Override
@@ -74,6 +76,6 @@
IRecordDescriptorProvider recordDescProvider, int partition, int nPartitions) throws HyracksDataException {
IInvertedIndexSearchModifier searchModifier = searchModifierFactory.createSearchModifier();
return new LSMInvertedIndexSearchOperatorNodePushable(this, ctx, partition, recordDescProvider, queryField,
- searchModifier, minFilterFieldIndexes, maxFilterFieldIndexes);
+ searchModifier, minFilterFieldIndexes, maxFilterFieldIndexes, isFullTextSearchQuery);
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorNodePushable.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorNodePushable.java
index 09893fb..4634c7f 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorNodePushable.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/dataflow/LSMInvertedIndexSearchOperatorNodePushable.java
@@ -34,14 +34,19 @@
protected final IInvertedIndexSearchModifier searchModifier;
protected final int queryFieldIndex;
protected final int invListFields;
+ // Keeps the information whether the given query is a full-text search or not.
+ // We need to have this information to stop the search process since we don't allow a phrase search yet.
+ protected final boolean isFullTextSearchQuery;
public LSMInvertedIndexSearchOperatorNodePushable(IIndexOperatorDescriptor opDesc, IHyracksTaskContext ctx,
int partition, IRecordDescriptorProvider recordDescProvider, int queryFieldIndex,
- IInvertedIndexSearchModifier searchModifier, int[] minFilterFieldIndexes, int[] maxFilterFieldIndexes)
+ IInvertedIndexSearchModifier searchModifier, int[] minFilterFieldIndexes, int[] maxFilterFieldIndexes,
+ boolean isFullTextSearchQuery)
throws HyracksDataException {
super(opDesc, ctx, partition, recordDescProvider, minFilterFieldIndexes, maxFilterFieldIndexes);
this.searchModifier = searchModifier;
this.queryFieldIndex = queryFieldIndex;
+ this.isFullTextSearchQuery = isFullTextSearchQuery;
// If retainInput is true, the frameTuple is created in IndexSearchOperatorNodePushable.open().
if (!opDesc.getRetainInput()) {
this.frameTuple = new FrameTupleReference();
@@ -54,7 +59,7 @@
protected ISearchPredicate createSearchPredicate() {
AbstractLSMInvertedIndexOperatorDescriptor invIndexOpDesc = (AbstractLSMInvertedIndexOperatorDescriptor) opDesc;
return new InvertedIndexSearchPredicate(invIndexOpDesc.getTokenizerFactory().createTokenizer(), searchModifier,
- minFilterKey, maxFilterKey);
+ minFilterKey, maxFilterKey, isFullTextSearchQuery);
}
@Override
@@ -63,6 +68,7 @@
InvertedIndexSearchPredicate invIndexSearchPred = (InvertedIndexSearchPredicate) searchPred;
invIndexSearchPred.setQueryTuple(frameTuple);
invIndexSearchPred.setQueryFieldIndex(queryFieldIndex);
+ invIndexSearchPred.setIsFullTextSearchQuery(isFullTextSearchQuery);
if (minFilterKey != null) {
minFilterKey.reset(accessor, tupleIndex);
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndexFactory.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndexFactory.java
index 7111097..14ceee8 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndexFactory.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/ondisk/OnDiskInvertedIndexFactory.java
@@ -58,7 +58,7 @@
@Override
public IInvertedIndex createIndexInstance(FileReference dictBTreeFile) throws IndexException, HyracksDataException {
- String invListsFilePath = fileNameMapper.getInvListsFilePath(dictBTreeFile.getFile().getPath());
+ String invListsFilePath = fileNameMapper.getInvListsFilePath(dictBTreeFile.getFile().getAbsolutePath());
FileReference invListsFile = ioManager.resolveAbsolutePath(invListsFilePath);
IInvertedListBuilder invListBuilder = invListBuilderFactory.create();
return new OnDiskInvertedIndex(bufferCache, fileMapProvider, invListBuilder, invListTypeTraits,
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/AbstractTOccurrenceSearcher.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/AbstractTOccurrenceSearcher.java
index 7d34198..cfc9fc6 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/AbstractTOccurrenceSearcher.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/AbstractTOccurrenceSearcher.java
@@ -44,8 +44,10 @@
import org.apache.hyracks.storage.am.lsm.invertedindex.exceptions.OccurrenceThresholdPanicException;
import org.apache.hyracks.storage.am.lsm.invertedindex.ondisk.FixedSizeFrameTupleAccessor;
import org.apache.hyracks.storage.am.lsm.invertedindex.ondisk.FixedSizeTupleReference;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.DelimitedUTF8StringBinaryTokenizer;
import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.IBinaryTokenizer;
import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.IToken;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.TokenizerInfo.TokenizerType;
import org.apache.hyracks.storage.am.lsm.invertedindex.util.ObjectCache;
public abstract class AbstractTOccurrenceSearcher implements IInvertedIndexSearcher {
@@ -96,6 +98,13 @@
ITupleReference queryTuple = searchPred.getQueryTuple();
int queryFieldIndex = searchPred.getQueryFieldIndex();
IBinaryTokenizer queryTokenizer = searchPred.getQueryTokenizer();
+ // Is this a full-text query?
+ // Then, the last argument is conjuctive or disjunctive search option, not a query text.
+ // Thus, we need to remove the last argument.
+ boolean isFullTextSearchQuery = searchPred.getIsFullTextSearchQuery();
+ // Get the type of query tokenizer.
+ TokenizerType queryTokenizerType = queryTokenizer.getTokenizerType();
+ int tokenCountInOneField = 0;
queryTokenAppender.reset(queryTokenFrame, true);
queryTokenizer.reset(queryTuple.getFieldData(queryFieldIndex), queryTuple.getFieldStart(queryFieldIndex),
@@ -104,8 +113,29 @@
while (queryTokenizer.hasNext()) {
queryTokenizer.next();
queryTokenBuilder.reset();
+ tokenCountInOneField++;
try {
IToken token = queryTokenizer.getToken();
+ // For the full-text search, we don't support a phrase search yet.
+ // So, each field should have only one token.
+ // If it's a list, it can have multiple keywords in it. But, each keyword should not be a phrase.
+ if (isFullTextSearchQuery) {
+ if (queryTokenizerType == TokenizerType.STRING && tokenCountInOneField > 1) {
+ throw new HyracksDataException(
+ "Phrase search in Full-text is not supported. "
+ + "An expression should include only one word.");
+ } else if (queryTokenizerType == TokenizerType.LIST) {
+ for (int j = 1; j < token.getTokenLength(); j++) {
+ if (DelimitedUTF8StringBinaryTokenizer
+ .isSeparator((char) token.getData()[token.getStartOffset() + j])) {
+ throw new HyracksDataException(
+ "Phrase search in Full-text is not supported. "
+ + "An expression should include only one word.");
+ }
+ }
+ }
+ }
+
token.serializeToken(queryTokenBuilder.getFieldData());
queryTokenBuilder.addFieldEndOffset();
// WARNING: assuming one frame is big enough to hold all tokens
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifier.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifier.java
new file mode 100644
index 0000000..b498411
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifier.java
@@ -0,0 +1,53 @@
+/*
+ * 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.hyracks.storage.am.lsm.invertedindex.search;
+
+import org.apache.hyracks.storage.am.lsm.invertedindex.api.IInvertedIndexSearchModifier;
+
+/**
+ * Search modifier that supports disjunctive conditions.
+ */
+public class DisjunctiveSearchModifier implements IInvertedIndexSearchModifier {
+
+ @Override
+ public int getOccurrenceThreshold(int numQueryTokens) {
+ return 1;
+ }
+
+ @Override
+ public int getNumPrefixLists(int occurrenceThreshold, int numInvLists) {
+ return numInvLists;
+ }
+
+ @Override
+ public String toString() {
+ return "Disjunctive Search Modifier";
+ }
+
+ @Override
+ public short getNumTokensLowerBound(short numQueryTokens) {
+ return -1;
+ }
+
+ @Override
+ public short getNumTokensUpperBound(short numQueryTokens) {
+ return -1;
+ }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifierFactory.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifierFactory.java
new file mode 100644
index 0000000..79976f4
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/DisjunctiveSearchModifierFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.hyracks.storage.am.lsm.invertedindex.search;
+
+import org.apache.hyracks.storage.am.lsm.invertedindex.api.IInvertedIndexSearchModifier;
+import org.apache.hyracks.storage.am.lsm.invertedindex.api.IInvertedIndexSearchModifierFactory;
+
+public class DisjunctiveSearchModifierFactory implements IInvertedIndexSearchModifierFactory {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public IInvertedIndexSearchModifier createSearchModifier() {
+ return new DisjunctiveSearchModifier();
+ }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/InvertedIndexSearchPredicate.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/InvertedIndexSearchPredicate.java
index e37f007..fe1a6d7 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/InvertedIndexSearchPredicate.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/search/InvertedIndexSearchPredicate.java
@@ -32,17 +32,22 @@
private int queryFieldIndex;
private final IBinaryTokenizer queryTokenizer;
private final IInvertedIndexSearchModifier searchModifier;
+ // Keeps the information whether the given query is a full-text search or not.
+ // We need to have this information to stop the search process since we don't allow a phrase search yet.
+ private boolean isFullTextSearchQuery;
public InvertedIndexSearchPredicate(IBinaryTokenizer queryTokenizer, IInvertedIndexSearchModifier searchModifier) {
this.queryTokenizer = queryTokenizer;
this.searchModifier = searchModifier;
+ this.isFullTextSearchQuery = false;
}
public InvertedIndexSearchPredicate(IBinaryTokenizer queryTokenizer, IInvertedIndexSearchModifier searchModifier,
- ITupleReference minFilterTuple, ITupleReference maxFilterTuple) {
+ ITupleReference minFilterTuple, ITupleReference maxFilterTuple, boolean isFullTextSearchQuery) {
super(minFilterTuple, maxFilterTuple);
this.queryTokenizer = queryTokenizer;
this.searchModifier = searchModifier;
+ this.isFullTextSearchQuery = isFullTextSearchQuery;
}
public void setQueryTuple(ITupleReference queryTuple) {
@@ -53,6 +58,14 @@
return queryTuple;
}
+ public void setIsFullTextSearchQuery(boolean isFullTextSearchQuery) {
+ this.isFullTextSearchQuery = isFullTextSearchQuery;
+ }
+
+ public boolean getIsFullTextSearchQuery() {
+ return isFullTextSearchQuery;
+ }
+
public void setQueryFieldIndex(int queryFieldIndex) {
this.queryFieldIndex = queryFieldIndex;
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/DelimitedUTF8StringBinaryTokenizer.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/DelimitedUTF8StringBinaryTokenizer.java
index 32e930d..cd37ffa 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/DelimitedUTF8StringBinaryTokenizer.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/DelimitedUTF8StringBinaryTokenizer.java
@@ -19,6 +19,7 @@
package org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.TokenizerInfo.TokenizerType;
import org.apache.hyracks.util.string.UTF8StringUtil;
public class DelimitedUTF8StringBinaryTokenizer extends AbstractUTF8StringBinaryTokenizer {
@@ -113,4 +114,9 @@
}
return tokenCount;
}
+
+ @Override
+ public TokenizerType getTokenizerType() {
+ return TokenizerType.STRING;
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/IBinaryTokenizer.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/IBinaryTokenizer.java
index ba384c0..6a7da02 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/IBinaryTokenizer.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/IBinaryTokenizer.java
@@ -19,6 +19,8 @@
package org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.TokenizerInfo.TokenizerType;
+
public interface IBinaryTokenizer {
public IToken getToken();
@@ -30,4 +32,7 @@
// Get the total number of tokens
public short getTokensCount();
+
+ // Get the tokenizer types
+ public TokenizerType getTokenizerType();
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/NGramUTF8StringBinaryTokenizer.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/NGramUTF8StringBinaryTokenizer.java
index 9161a54..4c486c5 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/NGramUTF8StringBinaryTokenizer.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/NGramUTF8StringBinaryTokenizer.java
@@ -19,6 +19,7 @@
package org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers;
+import org.apache.hyracks.storage.am.lsm.invertedindex.tokenizers.TokenizerInfo.TokenizerType;
import org.apache.hyracks.util.string.UTF8StringUtil;
public class NGramUTF8StringBinaryTokenizer extends AbstractUTF8StringBinaryTokenizer {
@@ -125,4 +126,9 @@
public short getTokensCount() {
return (short) totalGrams;
}
+
+ @Override
+ public TokenizerType getTokenizerType() {
+ return TokenizerType.STRING;
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/TokenizerInfo.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/TokenizerInfo.java
new file mode 100644
index 0000000..c980f1a
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/tokenizers/TokenizerInfo.java
@@ -0,0 +1,36 @@
+/*
+ * 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.hyracks.storage.am.lsm.invertedindex.tokenizers;
+
+public class TokenizerInfo {
+
+ // Defines the type of a tokenizer.
+ // STRING: tokenizer deals with a string - extract a partial string when next() is called.
+ // LIST: tokenizer deals with a list - extract an element when next() is called.
+ public enum TokenizerType {
+ STRING,
+ LIST
+ }
+
+ private TokenizerInfo() {
+ // No method yet
+ }
+
+}