opensearch-project / opensearch-project/sql

[BUG] plugins.ppl.values.max.limit cannot be honored on the Analytics Engine route (no binding for array_agg(DISTINCT x, limit))

Open
#5,736 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

analytic-engine bug PPL
Dominant language
Java
Stars
176
Forks
229
Avg merge
2d 21h
Merged PRs (30d)
43

Description

What is the bug?

plugins.ppl.values.max.limit cannot currently be honored on the Analytics Engine (composite/parquet) route. The cap is silently ignored today, and simply making the setting reach the planner is not enough — the resulting plan fails to bind on the DataFusion backend and the query returns HTTP 500.

Root cause

The cap is applied at AST-build time by attaching a limit argument to the aggregate:

ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.javavisitValuesAggFunctionCall:

int limit = 0; // Default to unlimited
if (astBuilder.getSettings() != null) {
  Integer settingValue = astBuilder.getSettings().getSettingValue(Key.PPL_VALUES_MAX_LIMIT);
  if (settingValue != null) { limit = settingValue; }
}
if (limit > 0) {
  builder.add(new UnresolvedArgument("limit", AstDSL.intLiteral(limit)));
}

That extra argument lowers values(x) to array_agg(DISTINCT x, limit). The analytics-engine backend has no binding for the two-argument form.

Two things stack here:

  1. On the AE route the setting never reaches the planner at all (it is not seeded into UnifiedQueryContext.Builder and was not forwarded by RestUnifiedQueryAction), so limit stays 0 and no argument is attached — the cap is silently ignored.
  2. Even once the setting does reach the planner, the backend cannot execute the result.

So the cause recorded in Capability.VALUES_LIMIT_NOT_HONORED ("the aggregate rewriter emits no limit") is accurate in effect, and (2) is the blocking half.

How can one reproduce the bug?

Verified against a live single-node cluster with composite-engine, parquet-data-format, analytics-engine, analytics-backend-datafusion, analytics-backend-lucene and the SQL plugin.

# parquet-backed composite index, auto-generated doc ids
curl -XPUT localhost:9200/ae_probe -H 'Content-Type: application/json' -d '{
 "settings":{"index":{"number_of_shards":1,"pluggable.dataformat.enabled":true,
 "pluggable.dataformat":"composite","composite.primary_data_format":"parquet",
 "composite.secondary_data_formats":["lucene"]}},
 "mappings":{"properties":{"name":{"type":"keyword"},"age":{"type":"integer"}}}}'
# bulk-load 6 docs name=n1..n6, then:
curl -XPUT localhost:9200/_cluster/settings -H 'Content-Type: application/json' \
  -d '{"transient":{"plugins.ppl.values.max.limit":3}}'
curl -XPOST localhost:9200/_plugins/_ppl -H 'Content-Type: application/json' \
  -d '{"query":"source=ae_probe | stats values(name) as v"}'

Current behavior — the cap is ignored, all 6 values returned:

6 values: ['n1','n2','n3','n4','n5','n6']

With the setting forwarded into the unified query context (i.e. the naive fix), the same query fails:

{"error":{"reason":"There was internal problem at backend",
          "details":"Internal error [task_id=63]","type":"RuntimeException"},"status":500}

with, in the node log:

[ERROR][o.o.a.e.DefaultPlanExecutor] [analytics-engine] internal error [task_id=63]
java.lang.UnsupportedOperationException: Unable to find binding for call array_agg(DISTINCT $0, $1)
What is the expected behavior?

values() / list() should honor plugins.ppl.values.max.limit on the analytics-engine route, as they do on the default engine.

Fixing this requires backend support for the limited aggregate form (a binding for array_agg(DISTINCT x, n), or an equivalent sort+limit rewrite in PplAggregateCallRewriter) — it cannot be fixed by settings plumbing alone. Once that lands, Key.PPL_VALUES_MAX_LIMIT can be added to RestUnifiedQueryAction.FORWARDED_CLUSTER_SETTINGS and Capability.VALUES_LIMIT_NOT_HONORED (with the @RequiresCapability on CalciteMultiValueStatsIT.testValuesFunctionRespectsConfiguredLimit) removed.

Do you have any additional context?

Found while fixing settings-forwarding gaps on the AE path in #5611. That PR deliberately excludes this key for the reason above — forwarding it would convert a silently-ignored cap into a hard 500 — and documents the exclusion in code so it is not "helpfully" added later.

Related: #5734, #5735.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with visitValuesAggFunctionCall in ppl/src/main/java/org/opensearch/sql/ppl/parser/AstExpressionBuilder.java and the setting forwarding in RestUnifiedQueryAction. Then inspect the limited aggregate handling in PplAggregateCallRewriter and the Analytics Engine backend binding for array_agg(DISTINCT x, n). Run CalciteMultiValueStatsIT.testValuesFunctionRespectsConfiguredLimit; done means values() and list() honor the configured limit on the Analytics Engine route without an HTTP 500.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.