Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simple_query_string implementation. #66

Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

package org.opensearch.sql.analysis;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
Expand All @@ -32,6 +34,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.RelevanceFieldList;
import org.opensearch.sql.ast.expression.Span;
import org.opensearch.sql.ast.expression.UnresolvedArgument;
import org.opensearch.sql.ast.expression.UnresolvedAttribute;
Expand All @@ -40,11 +43,13 @@
import org.opensearch.sql.ast.expression.WindowFunction;
import org.opensearch.sql.ast.expression.Xor;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.data.model.ExprTupleValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.data.type.ExprType;
import org.opensearch.sql.exception.SemanticCheckException;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.LiteralExpression;
import org.opensearch.sql.expression.NamedArgumentExpression;
import org.opensearch.sql.expression.NamedExpression;
import org.opensearch.sql.expression.ParseExpression;
Expand Down Expand Up @@ -158,6 +163,18 @@ public Expression visitAggregateFunction(AggregateFunction node, AnalysisContext
}
}

@Override
public Expression visitRelevanceFieldList(RelevanceFieldList node, AnalysisContext context) {
return new LiteralExpression(new ExprTupleValue(new LinkedHashMap<>(node
.getFieldList()
.entrySet()
.stream()
.collect(ImmutableMap.toImmutableMap(
n -> n.getKey().toString(),
n -> ExprValueUtils.floatValue((Float) ((Literal) n.getValue()).getValue())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without simplified RelevanceFieldList, this will fail if RelevanceFieldList is anything other than string-float map.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 015aa06.

)))));
}

@Override
public Expression visitFunction(Function node, AnalysisContext context) {
FunctionName functionName = FunctionName.of(node.getFuncName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,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.RelevanceFieldList;
import org.opensearch.sql.ast.expression.Span;
import org.opensearch.sql.ast.expression.UnresolvedArgument;
import org.opensearch.sql.ast.expression.UnresolvedAttribute;
Expand Down Expand Up @@ -110,6 +111,10 @@ public T visitLiteral(Literal node, C context) {
return visitChildren(node, context);
}

public T visitRelevanceFieldList(RelevanceFieldList node, C context) {
return visitChildren(node, context);
}

public T visitUnresolvedAttribute(UnresolvedAttribute node, C context) {
return visitChildren(node, context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.ast.expression;

import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.opensearch.sql.ast.AbstractNodeVisitor;

/**
* Expression node that includes a list of RelevanceField nodes.
*/
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
public class RelevanceFieldList extends UnresolvedExpression {
@Getter
private java.util.Map<UnresolvedExpression, UnresolvedExpression> fieldList;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can make this into a string-float map.
This would improve and simplify the places that use the class as well.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about using the Field class to store the string/float parameters. If that doesn't work, we should consider creating an Object to store this information.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 015aa06.


@Override
public List<UnresolvedExpression> getChild() {
return List.of();
}

@Override
public <R, C> R accept(AbstractNodeVisitor<R, C> nodeVisitor, C context) {
return nodeVisitor.visitRelevanceFieldList(this, context);
}

@Override
public String toString() {
return fieldList
.entrySet()
.stream()
.map(e -> String.format("\"%s\" ^ %s", e.getKey(), e.getValue()))
.collect(Collectors.joining(", "));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public List<ExprValue> collectionValue() {
public String toString() {
return valueList.stream()
.map(Object::toString)
.collect(Collectors.joining(",", "[", "]"));
.collect(Collectors.joining(", ", "[", "]"));
}

@Override
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -658,9 +658,11 @@ public FunctionExpression match_phrase(Expression... args) {
return compile(BuiltinFunctionName.MATCH_PHRASE, args);
}

public FunctionExpression simple_query_string(Expression... args) {
return compile(BuiltinFunctionName.SIMPLE_QUERY_STRING, args);
}

private FunctionExpression compile(BuiltinFunctionName bfn, Expression... args) {
return (FunctionExpression) repository.compile(bfn.getName(), Arrays.asList(args.clone()));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package org.opensearch.sql.expression;

import org.opensearch.sql.ast.expression.Span;
import org.opensearch.sql.expression.aggregation.Aggregator;
import org.opensearch.sql.expression.aggregation.NamedAggregator;
import org.opensearch.sql.expression.conditional.cases.CaseClause;
Expand Down Expand Up @@ -93,5 +92,4 @@ public T visitWhen(WhenClause node, C context) {
public T visitNamedArgument(NamedArgumentExpression node, C context) {
return visitNode(node, context);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ public enum BuiltinFunctionName {
* Relevance Function.
*/
MATCH(FunctionName.of("match")),
SIMPLE_QUERY_STRING(FunctionName.of("simple_query_string")),
MATCH_PHRASE(FunctionName.of("match_phrase")),
MATCHPHRASE(FunctionName.of("matchphrase")),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
package org.opensearch.sql.expression.function;

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

import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand All @@ -24,15 +26,17 @@
@UtilityClass
public class OpenSearchFunctions {

public static final int MATCH_MAX_NUM_PARAMETERS = 12;
public static final int MATCH_PHRASE_MAX_NUM_PARAMETERS = 3;
public static final int MATCH_MAX_NUM_PARAMETERS = 14;
public static final int MATCH_PHRASE_MAX_NUM_PARAMETERS = 5;
public static final int MIN_NUM_PARAMETERS = 2;
public static final int SIMPLE_QUERY_STRING_MAX_NUM_PARAMETERS = 14;

/**
* Add functions specific to OpenSearch to repository.
*/
public void register(BuiltinFunctionRepository repository) {
repository.register(match());
repository.register(simple_query_string());
// Register MATCHPHRASE as MATCH_PHRASE as well for backwards
// compatibility.
repository.register(match_phrase(BuiltinFunctionName.MATCH_PHRASE));
Expand All @@ -41,31 +45,36 @@ public void register(BuiltinFunctionRepository repository) {

private static FunctionResolver match() {
FunctionName funcName = BuiltinFunctionName.MATCH.getName();
return getRelevanceFunctionResolver(funcName, MATCH_MAX_NUM_PARAMETERS);
return getRelevanceFunctionResolver(funcName, MATCH_MAX_NUM_PARAMETERS, STRING);
}

private static FunctionResolver match_phrase(BuiltinFunctionName matchPhrase) {
FunctionName funcName = matchPhrase.getName();
return getRelevanceFunctionResolver(funcName, MATCH_PHRASE_MAX_NUM_PARAMETERS);
return getRelevanceFunctionResolver(funcName, MATCH_PHRASE_MAX_NUM_PARAMETERS, STRING);
}

private static FunctionResolver simple_query_string() {
FunctionName funcName = BuiltinFunctionName.SIMPLE_QUERY_STRING.getName();
return getRelevanceFunctionResolver(funcName, SIMPLE_QUERY_STRING_MAX_NUM_PARAMETERS, STRUCT);
}

private static FunctionResolver getRelevanceFunctionResolver(
FunctionName funcName, int maxNumParameters) {
FunctionName funcName, int maxNumParameters, ExprCoreType firstArgType) {
return new FunctionResolver(funcName,
getRelevanceFunctionSignatureMap(funcName, maxNumParameters));
getRelevanceFunctionSignatureMap(funcName, maxNumParameters, firstArgType));
}

private static Map<FunctionSignature, FunctionBuilder> getRelevanceFunctionSignatureMap(
FunctionName funcName, int numOptionalParameters) {
FunctionName funcName, int maxNumParameters, ExprCoreType firstArgType) {
FunctionBuilder buildFunction = args -> new OpenSearchFunction(funcName, args);
var signatureMapBuilder = ImmutableMap.<FunctionSignature, FunctionBuilder>builder();
for (int numParameters = MIN_NUM_PARAMETERS;
numParameters <= MIN_NUM_PARAMETERS + numOptionalParameters;
numParameters++) {
List<ExprType> args = Collections.nCopies(numParameters, STRING);
numParameters <= maxNumParameters; numParameters++) {
List<ExprType> args = new ArrayList<>(Collections.nCopies(numParameters - 1, STRING));
args.add(0, firstArgType);
signatureMapBuilder.put(new FunctionSignature(funcName, args), buildFunction);
}
return signatureMapBuilder.build();
return signatureMapBuilder.build();
}

private static class OpenSearchFunction extends FunctionExpression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.opensearch.sql.ast.dsl.AstDSL.field;
import static org.opensearch.sql.ast.dsl.AstDSL.floatLiteral;
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;
Expand All @@ -22,18 +23,23 @@
import static org.opensearch.sql.data.type.ExprCoreType.STRUCT;
import static org.opensearch.sql.expression.DSL.ref;

import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opensearch.sql.analysis.symbol.Namespace;
import org.opensearch.sql.analysis.symbol.Symbol;
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.RelevanceFieldList;
import org.opensearch.sql.ast.expression.SpanUnit;
import org.opensearch.sql.ast.expression.UnresolvedExpression;
import org.opensearch.sql.ast.tree.UnresolvedPlan;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.data.model.ExprTupleValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.exception.SemanticCheckException;
import org.opensearch.sql.expression.DSL;
Expand Down Expand Up @@ -359,6 +365,52 @@ void visit_in() {
() -> analyze(AstDSL.in(field("integer_value"), Collections.emptyList())));
}

@Test
void simple_query_string_expression() {
assertAnalyzeEqual(
dsl.simple_query_string(
dsl.namedArgument("fields", DSL.literal(
new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of(
"field", ExprValueUtils.floatValue(1.F)))))),
dsl.namedArgument("query", DSL.literal("sample query"))),
AstDSL.function("simple_query_string",
AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of(
stringLiteral("field"), floatLiteral(1.F)))),
AstDSL.unresolvedArg("query", stringLiteral("sample query"))));
}

@Test
void simple_query_string_expression_with_params() {
assertAnalyzeEqual(
dsl.simple_query_string(
dsl.namedArgument("fields", DSL.literal(
new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of(
"field", ExprValueUtils.floatValue(1.F)))))),
dsl.namedArgument("query", DSL.literal("sample query")),
dsl.namedArgument("analyzer", DSL.literal("keyword"))),
AstDSL.function("simple_query_string",
AstDSL.unresolvedArg("fields", new RelevanceFieldList(Map.of(
stringLiteral("field"), floatLiteral(1.F)))),
AstDSL.unresolvedArg("query", stringLiteral("sample query")),
AstDSL.unresolvedArg("analyzer", stringLiteral("keyword"))));
}

@Test
void simple_query_string_expression_two_fields() {
assertAnalyzeEqual(
dsl.simple_query_string(
dsl.namedArgument("fields", DSL.literal(
new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of(
"field1", ExprValueUtils.floatValue(1.F),
"field2", ExprValueUtils.floatValue(.3F)))))),
dsl.namedArgument("query", DSL.literal("sample query"))),
AstDSL.function("simple_query_string",
AstDSL.unresolvedArg("fields", new RelevanceFieldList(ImmutableMap.of(
stringLiteral("field1"), floatLiteral(1.F),
stringLiteral("field2"), floatLiteral(.3F)))),
AstDSL.unresolvedArg("query", stringLiteral("sample 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 @@ -9,18 +9,25 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;

import com.google.common.collect.ImmutableMap;
import java.util.LinkedHashMap;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.opensearch.sql.data.model.ExprTupleValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.ExpressionTestBase;
import org.opensearch.sql.expression.FunctionExpression;
import org.opensearch.sql.expression.NamedArgumentExpression;



public class OpenSearchFunctionsTest extends ExpressionTestBase {
private final NamedArgumentExpression field = new NamedArgumentExpression(
"field", DSL.literal("message"));
private final NamedArgumentExpression fields = new NamedArgumentExpression(
"fields", DSL.literal(new ExprTupleValue(new LinkedHashMap<>(ImmutableMap.of(
"title", ExprValueUtils.floatValue(1.F),
"body", ExprValueUtils.floatValue(.3F))))));
private final NamedArgumentExpression query = new NamedArgumentExpression(
"query", DSL.literal("search query"));
private final NamedArgumentExpression analyzer = new NamedArgumentExpression(
Expand All @@ -44,9 +51,9 @@ public class OpenSearchFunctionsTest extends ExpressionTestBase {
private final NamedArgumentExpression minimumShouldMatch = new NamedArgumentExpression(
"minimum_should_match", DSL.literal("1"));
private final NamedArgumentExpression zeroTermsQueryAll = new NamedArgumentExpression(
"zero_terms_query", DSL.literal("ALL"));
"zero_terms_query", DSL.literal("ALL"));
private final NamedArgumentExpression zeroTermsQueryNone = new NamedArgumentExpression(
"zero_terms_query", DSL.literal("None"));
"zero_terms_query", DSL.literal("None"));
private final NamedArgumentExpression boost = new NamedArgumentExpression(
"boost", DSL.literal("2.0"));
private final NamedArgumentExpression slop = new NamedArgumentExpression(
Expand Down Expand Up @@ -111,8 +118,8 @@ void match() {

expr = dsl.match(
field, query, analyzer, autoGenerateSynonymsPhrase, fuzziness, maxExpansions, prefixLength,
fuzzyTranspositions, fuzzyRewrite, lenient, operator, minimumShouldMatch, zeroTermsQueryAll,
boost);
fuzzyTranspositions, fuzzyRewrite, lenient, operator, minimumShouldMatch,
zeroTermsQueryNone, boost);
assertEquals(BOOLEAN, expr.type());
}

Expand Down Expand Up @@ -146,4 +153,12 @@ void match_to_string() {
FunctionExpression expr = dsl.match(field, query);
assertEquals("match(field=\"message\", query=\"search query\")", expr.toString());
}

@Test
void simple_query_string() {
FunctionExpression expr = dsl.simple_query_string(fields, query);
assertEquals(String.format("simple_query_string(fields=%s, query=%s)",
fields.getValue().toString(), query.getValue().toString()),
expr.toString());
}
}
Loading