Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Support LIKE operator #534

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ public FunctionExpression gte(
repository.compile(BuiltinFunctionName.GTE.getName(), Arrays.asList(expressions), env);
}

public FunctionExpression like(
Environment<Expression, ExprType> env, Expression... expressions) {
return (FunctionExpression)
repository.compile(BuiltinFunctionName.LIKE.getName(), Arrays.asList(expressions), env);
}

public Aggregator avg(Environment<Expression, ExprType> env, Expression... expressions) {
return (Aggregator)
repository.compile(BuiltinFunctionName.AVG.getName(), Arrays.asList(expressions), env);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.experimental.UtilityClass;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_MISSING;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_NULL;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.LITERAL_TRUE;
import static com.amazon.opendistroforelasticsearch.sql.expression.operator.OperatorUtils.binaryOperator;
import static com.amazon.opendistroforelasticsearch.sql.utils.OperatorUtils.matches;

import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValue;
Expand Down Expand Up @@ -66,6 +68,7 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(lte());
repository.register(greater());
repository.register(gte());
repository.register(like());
}

/**
Expand Down Expand Up @@ -184,7 +187,6 @@ public static void register(BuiltinFunctionRepository repository) {
.put(LITERAL_MISSING, LITERAL_MISSING, LITERAL_FALSE)
.build();


private static FunctionResolver and() {
FunctionName functionName = BuiltinFunctionName.AND.getName();
return FunctionResolver.builder()
Expand Down Expand Up @@ -309,6 +311,21 @@ private static FunctionResolver gte() {
);
}

private static FunctionResolver like() {
return new FunctionResolver(
BuiltinFunctionName.LIKE.getName(),
predicate(
BuiltinFunctionName.LIKE.getName(),
(v1, v2) -> matches(v2, v1)
)
);
}

/**
* Util method to generate EQUAL/NOT EQUAL operation bundles.
* Applicable for integer, long, float, double, string types of operands
* {@param defaultValue} Default value for one missing/null operand
*/
private static Map<FunctionSignature, FunctionBuilder> predicate(
FunctionName functionName,
Table<ExprValue, ExprValue, ExprValue> table,
Expand Down Expand Up @@ -350,6 +367,11 @@ private static Map<FunctionSignature, FunctionBuilder> predicate(
.build();
}

/**
* Util method to generate binary predicate bundles.
* Applicable for integer, long, float, double, string types of operands
* Missing/Null value operands follow as {@param table} lists
*/
private static Map<FunctionSignature, FunctionBuilder> predicate(
FunctionName functionName,
BiFunction<Integer, Integer, Boolean> integerFunc,
Expand All @@ -359,24 +381,50 @@ private static Map<FunctionSignature, FunctionBuilder> predicate(
BiFunction<String, String, Boolean> stringFunc) {
ImmutableMap.Builder<FunctionSignature, FunctionBuilder> builder = new ImmutableMap.Builder<>();
return builder
.put(new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)),
compareValue(functionName, integerFunc, ExprValueUtils::getIntegerValue,
ExprType.BOOLEAN))
.put(new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)),
compareValue(functionName, longFunc, ExprValueUtils::getLongValue,
ExprType.BOOLEAN))
.put(new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)),
compareValue(functionName, floatFunc, ExprValueUtils::getFloatValue,
ExprType.BOOLEAN))
.put(new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)),
compareValue(functionName, doubleFunc, ExprValueUtils::getDoubleValue,
ExprType.BOOLEAN))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprType.INTEGER, ExprType.INTEGER)),
binaryOperator(
functionName, integerFunc, ExprValueUtils::getIntegerValue, ExprType.BOOLEAN))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprType.LONG, ExprType.LONG)),
binaryOperator(
functionName, longFunc, ExprValueUtils::getLongValue, ExprType.BOOLEAN))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprType.FLOAT, ExprType.FLOAT)),
binaryOperator(
functionName, floatFunc, ExprValueUtils::getFloatValue, ExprType.BOOLEAN))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprType.DOUBLE, ExprType.DOUBLE)),
binaryOperator(
functionName, doubleFunc, ExprValueUtils::getDoubleValue, ExprType.BOOLEAN))
.put(
new FunctionSignature(functionName, Arrays.asList(ExprType.STRING, ExprType.STRING)),
binaryOperator(
functionName, stringFunc, ExprValueUtils::getStringValue, ExprType.BOOLEAN))
.build();
}

/**
* Util method to generate LIKE predicate bundles.
* Applicable for string operands.
*/
private static Map<FunctionSignature, FunctionBuilder> predicate(
FunctionName functionName,
BiFunction<String, String, Boolean> stringFunc) {
ImmutableMap.Builder<FunctionSignature, FunctionBuilder> builder = new ImmutableMap.Builder<>();
return builder
.put(new FunctionSignature(functionName, Arrays.asList(ExprType.STRING, ExprType.STRING)),
compareValue(functionName, stringFunc, ExprValueUtils::getStringValue,
binaryOperator(functionName, stringFunc, ExprValueUtils::getStringValue,
ExprType.BOOLEAN))
.build();
}


/**
* Building method to construct binary logical predicates AND OR XOR
* Where operands order does not matter.
* Special cases for missing/null operands refer to {@param table}.
*/
private static FunctionBuilder binaryPredicate(FunctionName functionName,
Table<ExprValue, ExprValue, ExprValue> table,
ExprType returnType) {
Expand Down Expand Up @@ -442,37 +490,4 @@ public String toString() {
}
};
}

/**
* Building method for operators including.
* less than (<) operator
* less than or equal to (<=) operator
* greater than (>) operator
* greater than or equal to (>=) operator
*/
private static <T, R> FunctionBuilder compareValue(FunctionName functionName,
BiFunction<T, T, R> function,
Function<ExprValue, T> observer,
ExprType returnType) {
return arguments -> new FunctionExpression(functionName, arguments) {
@Override
public ExprValue valueOf(Environment<Expression, ExprValue> env) {
ExprValue arg1 = arguments.get(0).valueOf(env);
ExprValue arg2 = arguments.get(1).valueOf(env);
return ExprValueUtils.fromObjectValue(
function.apply(observer.apply(arg1), observer.apply(arg2)));
}

@Override
public ExprType type(Environment<Expression, ExprType> env) {
return returnType;
}

@Override
public String toString() {
return String.format("%s %s %s", arguments.get(0).toString(), functionName, arguments
.get(1).toString());
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazon.opendistroforelasticsearch.sql.utils;

import java.util.regex.Pattern;
import lombok.experimental.UtilityClass;

@UtilityClass
public class OperatorUtils {
/**
* Wildcard pattern matcher util.
* Percent (%) character for wildcard,
* Underscore (_) character for a single character match.
* @param pattern string pattern to match.
* @return if text matches pattern returns true; else return false.
*/
public static boolean matches(String pattern, String text) {
return Pattern.compile(patternToRegex(pattern)).matcher(text).matches();
}

private static final char DEFAULT_ESCAPE = '\\';

private static String patternToRegex(String patternString) {
StringBuilder regex = new StringBuilder(patternString.length() * 2);
regex.append('^');
boolean escaped = false;
for (char currentChar : patternString.toCharArray()) {
if (!escaped && currentChar == DEFAULT_ESCAPE) {
escaped = true;
} else {
switch (currentChar) {
case '%':
if (escaped) {
regex.append("%");
} else {
regex.append(".*");
}
escaped = false;
break;
case '_':
if (escaped) {
regex.append("_");
} else {
regex.append('.');
}
escaped = false;
break;
default:
switch (currentChar) {
case '\\':
case '^':
case '$':
case '.':
case '*':
case '[':
case ']':
case '(':
case ')':
case '|':
case '+':
regex.append('\\');
break;
default:
}

regex.append(currentChar);
escaped = false;
}
}
}
regex.append('$');
return regex.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class TestConfig {
public static final String INT_TYPE_MISSING_VALUE_FIELD = "int_missing_value";
public static final String BOOL_TYPE_NULL_VALUE_FIELD = "null_value_boolean";
public static final String BOOL_TYPE_MISSING_VALUE_FIELD = "missing_value_boolean";
public static final String STRING_TYPE_NULL_VALUE_FILED = "string_null_value";
public static final String STRING_TYPE_MISSING_VALUE_FILED = "string_missing_value";

private static Map<String, ExprType> typeMapping = new ImmutableMap.Builder<String, ExprType>()
.put("integer_value", ExprType.INTEGER)
Expand All @@ -53,6 +55,8 @@ public class TestConfig {
.put(BOOL_TYPE_NULL_VALUE_FIELD, ExprType.BOOLEAN)
.put(BOOL_TYPE_MISSING_VALUE_FIELD, ExprType.BOOLEAN)
.put("string_value", ExprType.STRING)
.put(STRING_TYPE_NULL_VALUE_FILED, ExprType.STRING)
.put(STRING_TYPE_MISSING_VALUE_FILED, ExprType.STRING)
.put("struct_value", ExprType.STRUCT)
.put("array_value", ExprType.ARRAY)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.BOOL_TYPE_NULL_VALUE_FIELD;
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_MISSING_VALUE_FIELD;
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.INT_TYPE_NULL_VALUE_FIELD;
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.STRING_TYPE_MISSING_VALUE_FILED;
import static com.amazon.opendistroforelasticsearch.sql.config.TestConfig.STRING_TYPE_NULL_VALUE_FILED;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.booleanValue;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.collectionValue;
import static com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils.doubleValue;
Expand Down Expand Up @@ -82,9 +84,11 @@ protected Environment<Expression, ExprValue> valueEnv() {
return collectionValue(ImmutableList.of(1));
case BOOL_TYPE_NULL_VALUE_FIELD:
case INT_TYPE_NULL_VALUE_FIELD:
case STRING_TYPE_NULL_VALUE_FILED:
return nullValue();
case INT_TYPE_MISSING_VALUE_FIELD:
case BOOL_TYPE_MISSING_VALUE_FIELD:
case STRING_TYPE_MISSING_VALUE_FILED:
return missingValue();
default:
throw new IllegalArgumentException("undefined reference");
Expand Down
Loading