Skip to content

Fix: Long IN-lists causes crash #3660

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

Merged
merged 4 commits into from
May 30, 2025

Conversation

Swiddis
Copy link
Collaborator

@Swiddis Swiddis commented May 23, 2025

Description

Per #1469, very large lists of expressions in IN clauses cause StackOverflowErrors. Avoiding all recursion here is nontrivial because DSL.or can only take two arguments (and is internally implemented as a LUT for performance). This PR instead rewrites the method to have the recursion amount grow logarithmically, by building the or tree as a balanced tree. This avoids hitting any recursion limits unless there's well over 2⁵¹² items in the list.

Implementing something like DSL.any is on the table for future work if we need to optimize further, but it's more complex than this fix and it's not clear that this is a hot path.

Related Issues

Resolves #1469

Check List

  • New functionality includes testing.
  • New functionality has been documented.
  • New functionality has javadoc added.
  • New functionality has a user manual doc added.
  • API changes companion pull request created.
  • Commits are signed per the DCO using --signoff.
  • Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

The "end - start < 1" case shouldn't ever be reached, but we can still code defensively if the case is hit. The result might not be well-defined but it at least won't crash the whole JVM.

Signed-off-by: Simeon Widdis <[email protected]>
@Swiddis Swiddis force-pushed the bugfix/long-in-crash branch from 878b31a to da3e941 Compare May 23, 2025 19:21
Signed-off-by: Simeon Widdis <[email protected]>
@Swiddis Swiddis enabled auto-merge (squash) May 23, 2025 20:45
Copy link
Collaborator

@dai-chen dai-chen left a comment

Choose a reason for hiding this comment

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

Thanks for the fix. In original issue, one of the possible solution is

"Compile IN expression to field = ANY(ARRAY(values)) which maybe optimal at both compile and runtime"

Could you compare it with current approach?

@Swiddis
Copy link
Collaborator Author

Swiddis commented May 28, 2025

I wrote it in the description

Implementing something like DSL.any is on the table for future work if we need to optimize further, but it's more complex than this fix and it's not clear that this is a hot path.

It would probably be better than this, but it looks like we don't already have a DSL.any method available so I'd need to implement one. If you can give pointers on where to start, I can look into it?

I know from the or LUT that we pretty much just need to traverse the hierarchy of False -> Missing -> Null -> True when implementing it, just not sure where I'd register the function exactly...

@LantaoJin
Copy link
Member

LantaoJin commented May 29, 2025

Will this improving be a throw away work in future? This issue only happens in v2. And with calcite, the query | where age in (10, 40.0, 100) will pushdown as

  "query": {
    "terms": {
      "age": [
        10,
        40,
        100
      ],
      "boost": 1
    }
  }

instead of following in v2:

  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "age": {
              "value": 10,
              "boost": 1
            }
          }
        },
        {
          "bool": {
            "should": [
              {
                "term": {
                  "age": {
                    "value": 40,
                    "boost": 1
                  }
                }
              },
              {
                "term": {
                  "age": {
                    "value": 100,
                    "boost": 1
                  }
                }
              }
            ],
            "adjust_pure_negative": true,
            "boost": 1
          }
        }
      ],
      "adjust_pure_negative": true,
      "boost": 1
    }
  }

+1 for Compile IN expression to field = ANY(ARRAY(values)) if we really want to fix it in v2. But performance improving in v2 could be a low priority task since from 3.1.0+, the calcite engine may be enabled by default.

@Swiddis Swiddis merged commit 3d2c261 into opensearch-project:main May 30, 2025
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Long IN value list cause stack overflow error
4 participants