Skip to content

Commit

Permalink
Support match function as filter in SQL and PPL (#204)
Browse files Browse the repository at this point in the history
* supported match in sql and ppl where

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* added legacy syntax in new parser

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* added integration test

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* updated user manual

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* updated user manual

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* update

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* added ppl integ test, updated ppl manual

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* update

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* update

Signed-off-by: chloe-zh <chloezh1102@gmail.com>

* update

Signed-off-by: chloe-zh <chloezh1102@gmail.com>
  • Loading branch information
chloe-zh authored Oct 6, 2021
1 parent 012cc03 commit 937c955
Show file tree
Hide file tree
Showing 29 changed files with 916 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.opensearch.sql.ast.expression.Not;
import org.opensearch.sql.ast.expression.Or;
import org.opensearch.sql.ast.expression.QualifiedName;
import org.opensearch.sql.ast.expression.UnresolvedArgument;
import org.opensearch.sql.ast.expression.UnresolvedAttribute;
import org.opensearch.sql.ast.expression.UnresolvedExpression;
import org.opensearch.sql.ast.expression.When;
Expand All @@ -62,6 +63,7 @@
import org.opensearch.sql.exception.SemanticCheckException;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.NamedArgumentExpression;
import org.opensearch.sql.expression.ReferenceExpression;
import org.opensearch.sql.expression.aggregation.AggregationState;
import org.opensearch.sql.expression.aggregation.Aggregator;
Expand Down Expand Up @@ -258,6 +260,11 @@ public Expression visitQualifiedName(QualifiedName node, AnalysisContext context
return visitIdentifier(qualifierAnalyzer.unqualified(node), context);
}

@Override
public Expression visitUnresolvedArgument(UnresolvedArgument node, AnalysisContext context) {
return new NamedArgumentExpression(node.getArgName(), node.getValue().accept(this, context));
}

private Expression visitIdentifier(String ident, AnalysisContext context) {
TypeEnvironment typeEnv = context.peek();
ReferenceExpression ref = DSL.ref(ident,
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

package org.opensearch.sql.expression;

import com.sun.tools.javac.util.List;
import java.util.Arrays;
import java.util.Collections;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -128,6 +129,10 @@ public static NamedAggregator named(String name, Aggregator aggregator) {
return new NamedAggregator(name, aggregator);
}

public NamedArgumentExpression namedArgument(String argName, Expression value) {
return new NamedArgumentExpression(argName, value);
}

public FunctionExpression abs(Expression... expressions) {
return function(BuiltinFunctionName.ABS, expressions);
}
Expand Down Expand Up @@ -650,4 +655,9 @@ public FunctionExpression castDatetime(Expression value) {
return (FunctionExpression) repository
.compile(BuiltinFunctionName.CAST_TO_DATETIME.getName(), Arrays.asList(value));
}

public FunctionExpression match(Expression... args) {
return (FunctionExpression) repository
.compile(BuiltinFunctionName.MATCH.getName(), Arrays.asList(args.clone()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,8 @@ public T visitWhen(WhenClause node, C context) {
return visitFunction(node, context);
}

public T visitNamedArgument(NamedArgumentExpression node, C context) {
return visitNode(node, context);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*
*/

package org.opensearch.sql.expression;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.type.ExprType;
import org.opensearch.sql.expression.env.Environment;

/**
* Named argument expression that represents function argument with name.
*/
@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
public class NamedArgumentExpression implements Expression {
private final String argName;
private final Expression value;

@Override
public ExprValue valueOf(Environment<Expression, ExprValue> valueEnv) {
return value.valueOf(valueEnv);
}

@Override
public ExprType type() {
return value.type();
}

@Override
public <T, C> T accept(ExpressionNodeVisitor<T, C> visitor, C context) {
return visitor.visitNamedArgument(this, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.opensearch.sql.expression.datetime.DateTimeFunction;
import org.opensearch.sql.expression.datetime.IntervalClause;
import org.opensearch.sql.expression.function.BuiltinFunctionRepository;
import org.opensearch.sql.expression.function.OpenSearchFunctions;
import org.opensearch.sql.expression.operator.arthmetic.ArithmeticFunction;
import org.opensearch.sql.expression.operator.arthmetic.MathematicalFunction;
import org.opensearch.sql.expression.operator.convert.TypeCastOperator;
Expand Down Expand Up @@ -64,6 +65,7 @@ public BuiltinFunctionRepository functionRepository() {
WindowFunctions.register(builtinFunctionRepository);
TextFunction.register(builtinFunctionRepository);
TypeCastOperator.register(builtinFunctionRepository);
OpenSearchFunctions.register(builtinFunctionRepository);
return builtinFunctionRepository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,19 @@ public enum BuiltinFunctionName {
CAST_TO_DATE(FunctionName.of("cast_to_date")),
CAST_TO_TIME(FunctionName.of("cast_to_time")),
CAST_TO_TIMESTAMP(FunctionName.of("cast_to_timestamp")),
CAST_TO_DATETIME(FunctionName.of("cast_to_datetime"));
CAST_TO_DATETIME(FunctionName.of("cast_to_datetime")),

/**
* Relevance Function.
*/
MATCH(FunctionName.of("match")),

/**
* Legacy Relevance Function.
*/
QUERY(FunctionName.of("query")),
MATCH_QUERY(FunctionName.of("match_query")),
MATCHQUERY(FunctionName.of("matchquery"));

private final FunctionName name;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*
*/

package org.opensearch.sql.expression.function;

import static org.opensearch.sql.data.type.ExprCoreType.STRING;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.stream.Collectors;
import lombok.ToString;
import lombok.experimental.UtilityClass;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.type.ExprCoreType;
import org.opensearch.sql.data.type.ExprType;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.FunctionExpression;
import org.opensearch.sql.expression.NamedArgumentExpression;
import org.opensearch.sql.expression.env.Environment;

@UtilityClass
public class OpenSearchFunctions {
public void register(BuiltinFunctionRepository repository) {
repository.register(match());
}

private static FunctionResolver match() {
FunctionName funcName = BuiltinFunctionName.MATCH.getName();
return new FunctionResolver(funcName,
ImmutableMap.<FunctionSignature, FunctionBuilder>builder()
.put(new FunctionSignature(funcName, ImmutableList.of(STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList.of(STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList.of(STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING,
STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING,
STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING,
STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING,
STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.put(new FunctionSignature(funcName, ImmutableList
.of(STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING, STRING,
STRING, STRING, STRING, STRING, STRING)),
args -> new OpenSearchFunction(funcName, args))
.build());
}

private static class OpenSearchFunction extends FunctionExpression {
private final FunctionName functionName;
private final List<Expression> arguments;

public OpenSearchFunction(FunctionName functionName, List<Expression> arguments) {
super(functionName, arguments);
this.functionName = functionName;
this.arguments = arguments;
}

@Override
public ExprValue valueOf(Environment<Expression, ExprValue> valueEnv) {
throw new UnsupportedOperationException(String.format(
"OpenSearch defined function [%s] is only supported in WHERE and HAVING clause.",
functionName));
}

@Override
public ExprType type() {
return ExprCoreType.BOOLEAN;
}

@Override
public String toString() {
List<String> args = arguments.stream()
.map(arg -> String.format("%s=%s", ((NamedArgumentExpression) arg)
.getArgName(), ((NamedArgumentExpression) arg).getValue().toString()))
.collect(Collectors.toList());
return String.format("%s(%s)", functionName, String.join(", ", args));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
import static org.opensearch.sql.ast.dsl.AstDSL.function;
import static org.opensearch.sql.ast.dsl.AstDSL.intLiteral;
import static org.opensearch.sql.ast.dsl.AstDSL.qualifiedName;
import static org.opensearch.sql.ast.dsl.AstDSL.stringLiteral;
import static org.opensearch.sql.data.model.ExprValueUtils.LITERAL_TRUE;
import static org.opensearch.sql.data.model.ExprValueUtils.integerValue;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
import static org.opensearch.sql.data.type.ExprCoreType.STRUCT;

import org.junit.jupiter.api.Test;
Expand All @@ -46,6 +48,7 @@
import org.opensearch.sql.ast.dsl.AstDSL;
import org.opensearch.sql.ast.expression.AllFields;
import org.opensearch.sql.ast.expression.DataType;
import org.opensearch.sql.ast.expression.Literal;
import org.opensearch.sql.ast.expression.UnresolvedExpression;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.data.model.ExprValueUtils;
Expand Down Expand Up @@ -318,6 +321,14 @@ public void filtered_distinct_count() {
);
}

@Test
public void named_argument() {
assertAnalyzeEqual(
dsl.namedArgument("arg_name", DSL.literal("query")),
AstDSL.unresolvedArg("arg_name", stringLiteral("query"))
);
}

protected Expression analyze(UnresolvedExpression unresolvedExpression) {
return expressionAnalyzer.analyze(unresolvedExpression, analysisContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void should_return_null_by_default() {
INTEGER)).accept(visitor, null));
assertNull(new CaseClause(ImmutableList.of(), null).accept(visitor, null));
assertNull(new WhenClause(literal("test"), literal(10)).accept(visitor, null));
assertNull(dsl.namedArgument("field", literal("message")).accept(visitor, null));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*
*/

package org.opensearch.sql.expression;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class NamedArgumentExpressionTest extends ExpressionTestBase {
@Test
void name_an_argument() {
LiteralExpression value = DSL.literal("search");
NamedArgumentExpression namedArgument = dsl.namedArgument("query", value);

assertEquals("query", namedArgument.getArgName());
assertEquals(value.type(), namedArgument.type());
assertEquals(value.valueOf(valueEnv()), namedArgument.valueOf(valueEnv()));
}
}
Loading

0 comments on commit 937c955

Please sign in to comment.