Skip to content

Commit cd84d74

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/main' into poc/graphlookup
# Conflicts: # core/src/main/java/org/opensearch/sql/analysis/Analyzer.java # core/src/main/java/org/opensearch/sql/ast/AbstractNodeVisitor.java # docs/user/ppl/index.md # ppl/src/main/antlr/OpenSearchPPLParser.g4
2 parents 182b50c + 26912a3 commit cd84d74

63 files changed

Lines changed: 3790 additions & 350 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

async-query-core/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ configurations {
4343
}
4444

4545
dependencies {
46-
antlr "org.antlr:antlr4:4.7.1"
46+
antlr "org.antlr:antlr4:4.13.2"
4747

4848
implementation project(':core')
4949
implementation 'org.json:json:20231013'

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
buildscript {
88
ext {
9-
opensearch_version = System.getProperty("opensearch.version", "3.5.0-SNAPSHOT")
9+
opensearch_version = System.getProperty("opensearch.version", "3.6.0-SNAPSHOT")
1010
isSnapshot = "true" == System.getProperty("build.snapshot", "true")
1111
buildVersionQualifier = System.getProperty("build.version_qualifier", "")
1212
version_tokens = opensearch_version.tokenize('-')

common/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ repositories {
3333
}
3434

3535
dependencies {
36-
api "org.antlr:antlr4-runtime:4.7.1"
36+
api "org.antlr:antlr4-runtime:4.13.2"
3737
api group: 'com.google.guava', name: 'guava', version: "${guava_version}"
3838
api group: 'org.apache.logging.log4j', name: 'log4j-core', version:"${versions.log4j}"
3939
api group: 'org.apache.commons', name: 'commons-lang3', version: "${commons_lang3_version}"

core/src/main/java/org/opensearch/sql/analysis/Analyzer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
import org.opensearch.sql.ast.tree.ML;
8383
import org.opensearch.sql.ast.tree.Multisearch;
8484
import org.opensearch.sql.ast.tree.MvCombine;
85+
import org.opensearch.sql.ast.tree.MvExpand;
86+
import org.opensearch.sql.ast.tree.NoMv;
8587
import org.opensearch.sql.ast.tree.Paginate;
8688
import org.opensearch.sql.ast.tree.Parse;
8789
import org.opensearch.sql.ast.tree.Patterns;
@@ -547,6 +549,16 @@ public LogicalPlan visitMvCombine(MvCombine node, AnalysisContext context) {
547549
throw getOnlyForCalciteException("mvcombine");
548550
}
549551

552+
@Override
553+
public LogicalPlan visitNoMv(NoMv node, AnalysisContext context) {
554+
throw getOnlyForCalciteException("nomv");
555+
}
556+
557+
@Override
558+
public LogicalPlan visitMvExpand(MvExpand node, AnalysisContext context) {
559+
throw getOnlyForCalciteException("mvexpand");
560+
}
561+
550562
@Override
551563
public LogicalPlan visitGraphLookup(GraphLookup node, AnalysisContext context) {
552564
throw getOnlyForCalciteException("graphlookup");

core/src/main/java/org/opensearch/sql/ast/AbstractNodeVisitor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
import org.opensearch.sql.ast.tree.ML;
7171
import org.opensearch.sql.ast.tree.Multisearch;
7272
import org.opensearch.sql.ast.tree.MvCombine;
73+
import org.opensearch.sql.ast.tree.MvExpand;
74+
import org.opensearch.sql.ast.tree.NoMv;
7375
import org.opensearch.sql.ast.tree.Paginate;
7476
import org.opensearch.sql.ast.tree.Parse;
7577
import org.opensearch.sql.ast.tree.Patterns;
@@ -477,6 +479,14 @@ public T visitMvCombine(MvCombine node, C context) {
477479
return visitChildren(node, context);
478480
}
479481

482+
public T visitNoMv(NoMv node, C context) {
483+
return visitChildren(node, context);
484+
}
485+
486+
public T visitMvExpand(MvExpand node, C context) {
487+
return visitChildren(node, context);
488+
}
489+
480490
public T visitGraphLookup(GraphLookup node, C context) {
481491
return visitChildren(node, context);
482492
}

core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.opensearch.sql.ast.tree.Limit;
6464
import org.opensearch.sql.ast.tree.MinSpanBin;
6565
import org.opensearch.sql.ast.tree.MvCombine;
66+
import org.opensearch.sql.ast.tree.MvExpand;
6667
import org.opensearch.sql.ast.tree.Parse;
6768
import org.opensearch.sql.ast.tree.Patterns;
6869
import org.opensearch.sql.ast.tree.Project;
@@ -477,6 +478,16 @@ public static MvCombine mvcombine(Field field, String delim) {
477478
return new MvCombine(field, delim);
478479
}
479480

481+
/**
482+
* Build an MVEXPAND plan node and attach it to the input plan.
483+
*
484+
* <p>`@param` input input plan `@param` field field to expand `@param` limit optional
485+
* per-document limit `@return` MvExpand plan attached to the input
486+
*/
487+
public static UnresolvedPlan mvexpand(UnresolvedPlan input, Field field, Integer limit) {
488+
return new MvExpand(field, limit).attach(input);
489+
}
490+
480491
public static List<Argument> sortOptions() {
481492
return exprList(argument("desc", booleanLiteral(false)));
482493
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.tree;
7+
8+
import com.google.common.collect.ImmutableList;
9+
import java.util.List;
10+
import javax.annotation.Nullable;
11+
import lombok.EqualsAndHashCode;
12+
import lombok.Getter;
13+
import lombok.ToString;
14+
import org.opensearch.sql.ast.AbstractNodeVisitor;
15+
import org.opensearch.sql.ast.expression.Field;
16+
17+
/** AST node representing the {@code mvexpand} PPL command: {@code mvexpand <field> [limit=N]}. */
18+
@ToString
19+
@EqualsAndHashCode(callSuper = false)
20+
public class MvExpand extends UnresolvedPlan {
21+
22+
private UnresolvedPlan child;
23+
@Getter private final Field field;
24+
@Getter @Nullable private final Integer limit;
25+
26+
public MvExpand(Field field, @Nullable Integer limit) {
27+
this.field = field;
28+
this.limit = limit;
29+
}
30+
31+
@Override
32+
public MvExpand attach(UnresolvedPlan child) {
33+
this.child = child;
34+
return this;
35+
}
36+
37+
@Override
38+
public List<UnresolvedPlan> getChild() {
39+
return this.child == null ? ImmutableList.of() : ImmutableList.of(this.child);
40+
}
41+
42+
@Override
43+
public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
44+
return nodeVisitor.visitMvExpand(this, context);
45+
}
46+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.tree;
7+
8+
import com.google.common.collect.ImmutableList;
9+
import java.util.List;
10+
import javax.annotation.Nullable;
11+
import lombok.EqualsAndHashCode;
12+
import lombok.Getter;
13+
import lombok.ToString;
14+
import org.opensearch.sql.ast.AbstractNodeVisitor;
15+
import org.opensearch.sql.ast.expression.DataType;
16+
import org.opensearch.sql.ast.expression.Field;
17+
import org.opensearch.sql.ast.expression.Function;
18+
import org.opensearch.sql.ast.expression.Let;
19+
import org.opensearch.sql.ast.expression.Literal;
20+
21+
/**
22+
* AST node for the NOMV command. Converts multi-value fields to single-value fields by joining
23+
* array elements with newline delimiter.
24+
*/
25+
@Getter
26+
@ToString(callSuper = true)
27+
@EqualsAndHashCode(callSuper = false)
28+
public class NoMv extends UnresolvedPlan {
29+
30+
private final Field field;
31+
@Nullable private UnresolvedPlan child;
32+
33+
public NoMv(Field field) {
34+
this.field = field;
35+
}
36+
37+
public NoMv attach(UnresolvedPlan child) {
38+
this.child = child;
39+
return this;
40+
}
41+
42+
@Override
43+
public List<UnresolvedPlan> getChild() {
44+
return child == null ? ImmutableList.of() : ImmutableList.of(child);
45+
}
46+
47+
@Override
48+
public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
49+
return nodeVisitor.visitNoMv(this, context);
50+
}
51+
52+
/**
53+
* Rewrites the nomv command as an eval command using mvjoin function with null filtering. nomv
54+
* <field> is rewritten to: eval <field> = coalesce(mvjoin(array_compact(<field>), "\n"), "")
55+
*
56+
* <p>The array_compact removes null elements from the array, and coalesce ensures empty arrays
57+
* return empty string instead of null.
58+
*
59+
* @return an Eval node representing the equivalent mvjoin operation with null filtering
60+
*/
61+
public UnresolvedPlan rewriteAsEval() {
62+
Function arrayCompactFunc = new Function("array_compact", ImmutableList.of(field));
63+
64+
Function mvjoinFunc =
65+
new Function(
66+
"mvjoin", ImmutableList.of(arrayCompactFunc, new Literal("\n", DataType.STRING)));
67+
68+
Function coalesceFunc =
69+
new Function("coalesce", ImmutableList.of(mvjoinFunc, new Literal("", DataType.STRING)));
70+
71+
Let letExpr = new Let(field, coalesceFunc);
72+
73+
Eval eval = new Eval(ImmutableList.of(letExpr));
74+
if (this.child != null) {
75+
eval.attach(this.child);
76+
}
77+
return eval;
78+
}
79+
}

core/src/main/java/org/opensearch/sql/ast/tree/SPath.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class SPath extends UnresolvedPlan {
3030

3131
@Nullable private final String outField;
3232

33-
private final String path;
33+
@Nullable private final String path;
3434

3535
@Override
3636
public UnresolvedPlan attach(UnresolvedPlan child) {
@@ -48,7 +48,20 @@ public <T, C> T accept(AbstractNodeVisitor<T, C> nodeVisitor, C context) {
4848
return nodeVisitor.visitSpath(this, context);
4949
}
5050

51+
/**
52+
* Rewrites this spath node to an equivalent {@link Eval} node.
53+
*
54+
* <p>In path mode, rewrites to {@code eval output = json_extract(input, path)}. In auto-extract
55+
* mode (path is null), rewrites to {@code eval output = json_extract_all(input)}.
56+
*/
5157
public Eval rewriteAsEval() {
58+
if (path != null) {
59+
return rewritePathMode();
60+
}
61+
return rewriteAutoExtractMode();
62+
}
63+
64+
private Eval rewritePathMode() {
5265
String outField = this.outField;
5366
String unquotedPath = unquoteText(this.path);
5467
if (outField == null) {
@@ -62,4 +75,12 @@ public Eval rewriteAsEval() {
6275
AstDSL.function(
6376
"json_extract", AstDSL.field(inField), AstDSL.stringLiteral(unquotedPath))));
6477
}
78+
79+
private Eval rewriteAutoExtractMode() {
80+
String output = (outField != null) ? outField : inField;
81+
return AstDSL.eval(
82+
child,
83+
AstDSL.let(
84+
AstDSL.field(output), AstDSL.function("json_extract_all", AstDSL.field(inField))));
85+
}
6586
}

0 commit comments

Comments
 (0)