diff --git a/docs/user/ppl/cmd/head.md b/docs/user/ppl/cmd/head.md index 885e88a71b0..9999a6d710f 100644 --- a/docs/user/ppl/cmd/head.md +++ b/docs/user/ppl/cmd/head.md @@ -10,7 +10,7 @@ The `head` command returns the first N lines from a search result. The `head` command has the following syntax: ```syntax -head [] [from ] +head [limit=][] [from ] ``` ## Parameters diff --git a/docs/user/ppl/cmd/top.md b/docs/user/ppl/cmd/top.md index 53be4ade298..678b62354a0 100644 --- a/docs/user/ppl/cmd/top.md +++ b/docs/user/ppl/cmd/top.md @@ -10,7 +10,7 @@ The `top` command finds the most common combination of values across all fields The `top` command has the following syntax: ```syntax -top [N] [top-options] [by-clause] +top [limit=][N] [top-options] [by-clause] ``` ## Parameters diff --git a/ppl/src/main/antlr/OpenSearchPPLParser.g4 b/ppl/src/main/antlr/OpenSearchPPLParser.g4 index bcaaa105774..ff46a3649a0 100644 --- a/ppl/src/main/antlr/OpenSearchPPLParser.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLParser.g4 @@ -380,7 +380,7 @@ fieldformatCommand ; headCommand - : HEAD (number = integerLiteral)? (FROM from = integerLiteral)? + : HEAD ((LIMIT EQUAL)? number = integerLiteral)? (FROM from = integerLiteral)? ; binCommand @@ -412,7 +412,7 @@ logSpanValue ; rareTopCommand - : (TOP | RARE) (number = integerLiteral)? rareTopOption* fieldList (byClause)? + : (TOP | RARE) ((LIMIT EQUAL)? number = integerLiteral)? rareTopOption* fieldList (byClause)? ; rareTopOption @@ -1656,6 +1656,7 @@ searchableKeyWord | FREQUENCY_THRESHOLD_PERCENTAGE | MAX_SAMPLE_COUNT | BUFFER_LIMIT + | LIMIT | SHOW_NUMBERED_TOKEN | WITH | REGEX diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/AstPlanningTestBase.java b/ppl/src/test/java/org/opensearch/sql/ppl/AstPlanningTestBase.java new file mode 100644 index 00000000000..5f8261d6a9a --- /dev/null +++ b/ppl/src/test/java/org/opensearch/sql/ppl/AstPlanningTestBase.java @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.sql.ppl; + +import org.mockito.Mockito; +import org.opensearch.sql.ast.Node; +import org.opensearch.sql.common.setting.Settings; +import org.opensearch.sql.ppl.antlr.PPLSyntaxParser; +import org.opensearch.sql.ppl.parser.AstBuilder; + +/** Base class for tests for the AST query planner. */ +public class AstPlanningTestBase { + protected final Settings settings = Mockito.mock(Settings.class); + protected final PPLSyntaxParser parser = new PPLSyntaxParser(); + + protected Node plan(String query) { + AstBuilder astBuilder = new AstBuilder(query, settings); + return astBuilder.visit(parser.parse(query)); + } +} diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java index e7f3f986752..c5b033bfc9f 100644 --- a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java +++ b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstBuilderTest.java @@ -65,7 +65,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.Mockito; import org.opensearch.sql.ast.Node; import org.opensearch.sql.ast.dsl.AstDSL; import org.opensearch.sql.ast.expression.AllFields; @@ -82,20 +81,15 @@ import org.opensearch.sql.ast.tree.ML; import org.opensearch.sql.ast.tree.RareTopN.CommandType; import org.opensearch.sql.common.antlr.SyntaxCheckException; -import org.opensearch.sql.common.setting.Settings; import org.opensearch.sql.common.setting.Settings.Key; import org.opensearch.sql.exception.SemanticCheckException; -import org.opensearch.sql.ppl.antlr.PPLSyntaxParser; +import org.opensearch.sql.ppl.AstPlanningTestBase; import org.opensearch.sql.utils.SystemIndexUtils; -public class AstBuilderTest { +public class AstBuilderTest extends AstPlanningTestBase { @Rule public ExpectedException exceptionRule = ExpectedException.none(); - private final Settings settings = Mockito.mock(Settings.class); - - private final PPLSyntaxParser parser = new PPLSyntaxParser(); - @Test public void testDynamicSourceClauseThrowsUnsupportedException() { String query = "source=[myindex, logs, fieldIndex=\"test\"]"; @@ -1405,11 +1399,6 @@ protected void assertEqual(String query, String expected) { assertEqual(query, expectedPlan); } - private Node plan(String query) { - AstBuilder astBuilder = new AstBuilder(query, settings); - return astBuilder.visit(parser.parse(query)); - } - private String mappingTable(String indexName) { return SystemIndexUtils.mappingTable(indexName, PPL_SPEC); } diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstEquivalenceTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstEquivalenceTest.java new file mode 100644 index 00000000000..d0eb6dec25c --- /dev/null +++ b/ppl/src/test/java/org/opensearch/sql/ppl/parser/AstEquivalenceTest.java @@ -0,0 +1,29 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.sql.ppl.parser; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.opensearch.sql.ppl.AstPlanningTestBase; + +public class AstEquivalenceTest extends AstPlanningTestBase { + @Test + public void testSpathArgumentDeshuffle() { + assertEquals(plan("source = t | spath path=a input=a"), plan("source = t | spath input=a a")); + } + + @Test + public void testHeadLimitEquivalent() { + assertEquals(plan("source = t | head limit=50"), plan("source = t | head 50")); + } + + @Test + public void testTopLimitEquivalent() { + assertEquals( + plan("source = t | top limit=50 field_name"), plan("source = t | top 50 field_name")); + } +} diff --git a/ppl/src/test/java/org/opensearch/sql/ppl/utils/SPathRewriteTest.java b/ppl/src/test/java/org/opensearch/sql/ppl/rewrite/SpathRewriteTest.java similarity index 82% rename from ppl/src/test/java/org/opensearch/sql/ppl/utils/SPathRewriteTest.java rename to ppl/src/test/java/org/opensearch/sql/ppl/rewrite/SpathRewriteTest.java index 0bc9357278d..70ea41a07e2 100644 --- a/ppl/src/test/java/org/opensearch/sql/ppl/utils/SPathRewriteTest.java +++ b/ppl/src/test/java/org/opensearch/sql/ppl/rewrite/SpathRewriteTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package org.opensearch.sql.ppl.utils; +package org.opensearch.sql.ppl.rewrite; import static org.junit.Assert.assertEquals; import static org.opensearch.sql.ast.dsl.AstDSL.eval; @@ -15,23 +15,11 @@ import static org.opensearch.sql.ast.dsl.AstDSL.stringLiteral; import org.junit.Test; -import org.mockito.Mockito; -import org.opensearch.sql.ast.Node; import org.opensearch.sql.ast.tree.Eval; import org.opensearch.sql.ast.tree.SPath; -import org.opensearch.sql.common.setting.Settings; -import org.opensearch.sql.ppl.antlr.PPLSyntaxParser; -import org.opensearch.sql.ppl.parser.AstBuilder; - -public class SPathRewriteTest { - private final Settings settings = Mockito.mock(Settings.class); - private final PPLSyntaxParser parser = new PPLSyntaxParser(); - - private Node plan(String query) { - AstBuilder astBuilder = new AstBuilder(query, settings); - return astBuilder.visit(parser.parse(query)); - } +import org.opensearch.sql.ppl.AstPlanningTestBase; +public class SpathRewriteTest extends AstPlanningTestBase { // Control test to make sure something fundamental hasn't changed about the json_extract parsing @Test public void testEvalControl() {