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

Map BadQueryRequestException to QueryException.QUERY_VALIDATION_ERROR #14917

Merged
merged 19 commits into from
Jan 29, 2025

Conversation

real-mj-song
Copy link
Contributor

@real-mj-song real-mj-song commented Jan 24, 2025

Description

Expand the usage of BadQueryRequestException when error cause is clear. Map it to QUERY_VALIDATION_ERROR (700) instead of QUERY_EXECUTION_ERROR (200)

Now BadQueryRequestException is thrown in the following cases:

  • when aggregation functions fail to extract numeric type from given value
  • when IllegalArgumentException is thrown in BaseCombineOperator.java

Detailed reasoning

Related to #14916

For some aggregation functions (sum/min/max), throws BadQueryRequestException instead of IllegalStateException because a non-numeric type is passed by client. An example of this is when the query is

SELECT SUM/MIN/MAX(Origin) FROM mytable WHERE AirlineID > 3000

This fails with IllegalStateException and is classified as QueryException.QUERY_EXECUTION_ERROR by default by constructor of ExceptionResultsBlock

@codecov-commenter
Copy link

codecov-commenter commented Jan 24, 2025

Codecov Report

Attention: Patch coverage is 48.93617% with 24 lines in your changes missing coverage. Please review.

Project coverage is 63.70%. Comparing base (59551e4) to head (c3b0b48).
Report is 1643 commits behind head on master.

Files with missing lines Patch % Lines
...requesthandler/MultiStageBrokerRequestHandler.java 0.00% 8 Missing ⚠️
...che/pinot/common/exception/QueryInfoException.java 44.44% 5 Missing ⚠️
...sthandler/BaseSingleStageBrokerRequestHandler.java 0.00% 3 Missing ⚠️
.../core/operator/combine/GroupByCombineOperator.java 0.00% 2 Missing and 1 partial ⚠️
...not/core/operator/combine/BaseCombineOperator.java 85.71% 0 Missing and 1 partial ⚠️
...y/aggregation/function/MaxAggregationFunction.java 0.00% 1 Missing ⚠️
...y/aggregation/function/MinAggregationFunction.java 0.00% 1 Missing ⚠️
...y/aggregation/function/SumAggregationFunction.java 0.00% 1 Missing ⚠️
...core/query/executor/ServerQueryExecutorV1Impl.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #14917      +/-   ##
============================================
+ Coverage     61.75%   63.70%   +1.95%     
- Complexity      207     1471    +1264     
============================================
  Files          2436     2710     +274     
  Lines        133233   151911   +18678     
  Branches      20636    23459    +2823     
============================================
+ Hits          82274    96775   +14501     
- Misses        44911    47867    +2956     
- Partials       6048     7269    +1221     
Flag Coverage Δ
custom-integration1 100.00% <ø> (+99.99%) ⬆️
integration 100.00% <ø> (+99.99%) ⬆️
integration1 100.00% <ø> (+99.99%) ⬆️
integration2 0.00% <ø> (ø)
java-11 63.66% <48.93%> (+1.95%) ⬆️
java-21 63.59% <48.93%> (+1.97%) ⬆️
skip-bytebuffers-false 63.70% <48.93%> (+1.95%) ⬆️
skip-bytebuffers-true 63.55% <48.93%> (+35.82%) ⬆️
temurin 63.70% <48.93%> (+1.95%) ⬆️
unittests 63.70% <48.93%> (+1.95%) ⬆️
unittests1 56.24% <63.88%> (+9.35%) ⬆️
unittests2 34.01% <0.00%> (+6.28%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -111,7 +112,11 @@ protected void processSegments() {
@Override
protected void onProcessSegmentsException(Throwable t) {
_processingException.compareAndSet(null, t);
_blockingQueue.offer(new ExceptionResultsBlock(t));
if (t instanceof BadQueryRequestException) {
Copy link
Contributor

Choose a reason for hiding this comment

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

In ServerQueryExecutorV1Impl, we are setting QUERY_VALIDATION_ERROR for BadQueryRequestException. Do we require the same changes here?

Either way I see this change only being made in BaseSingleBlockCombineOperator. What about GroupByCombineOperator and BaseStreamingCombineOperator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In ServerQueryExecutorV1Impl, we are setting QUERY_VALIDATION_ERROR for BadQueryRequestException. Do we require the same changes here?

It does. Without this change, generic RuntimeException is thrown to QueryDispatcher.java which will bypass that check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Either way I see this change only being made in BaseSingleBlockCombineOperator. What about GroupByCombineOperator and BaseStreamingCombineOperator?

Yeah just noticed these implement the same interface. Will update them as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All patched.

ProcessingException queryException = QueryException.QUERY_EXECUTION_ERROR;
if (t instanceof BadQueryRequestException) {
// provide more specific error code if available
queryException = QueryException.QUERY_VALIDATION_ERROR;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should update broker metrics - BrokerMeter.QUERY_VALIDATION_EXCEPTIONS ?

We should also update this in SingleStageBrokerRequestHandler?

Copy link
Contributor Author

@real-mj-song real-mj-song Jan 27, 2025

Choose a reason for hiding this comment

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

For SingleStageBrokerRequestHandler, this is not needed because BadQueryRequestException thrown by ServerQueryExecutorV1Impl is stored in BrokerResponseNative object. It's directly parsed in PinotClientRequest::getPinotQueryResponse.

For this MultiStageBrokerRequestHandler, this was needed because query was handled by _queryDispatcher.submitAndReduce which may throw an exception. The Java exception needs to be caught on the broker request handler level.

Copy link
Contributor Author

@real-mj-song real-mj-song Jan 27, 2025

Choose a reason for hiding this comment

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

Diagrams for these two error reporting scenarios. Many middle steps are omitted and only relevant steps are shown 👇🏼

PinotClientRequest::processSqlQueryPost
  - BaseSingleStageBrokerRequestHandler::handleRequest
    - SingleConnectionBrokerRequestHandler::processBrokerRequest // broker metric is updated here
      - ServerQueryExecutorV1Impl::executeInternal // BadQueryRequestException is caught. InstanceResponseBlock is updated here
    - SingleConnectionBrokerRequestHandler::processBrokerRequest // No exception is caught here. Error code is embedded inside brokerResponse
PinotClientRequest::getPinotQueryResponse // 700 error code is parsed

MultiStage query

PinotClientRequest::processSqlQueryPost
  - MultiStageBrokerRequestHandler::handleRequest
    - QueryDispatcher::submitAndReduce // exception is thrown if ANY block errors. I re-throw BadQueryRequestException here
  - MultiStageBrokerRequestHandler::handleRequest // catch BadQueryRequestException. Exceptions in requestContext are added to brokerResponse via augmentStatistics
PinotClientRequest::getPinotQueryResponse // 700 error code is parsed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Metric incremented now. Resolved

* Exception to contain info about QueryException errors.
* Throwable version of {@link org.apache.pinot.common.response.broker.QueryProcessingException}
*/
public class QueryInfoException extends RuntimeException {
Copy link
Contributor Author

@real-mj-song real-mj-song Jan 29, 2025

Choose a reason for hiding this comment

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

Why this class?

QueryException is more of QueryExceptionUtil. It isn't throwable and rather a collection of static ProcessingException extends org.apache.thrift.TException. We need a throwable class that also contains information about ProcessingException.

Can't you use static QueryException.QUERY_VALIDATION_ERROR (or other from that family) directly?

Because they are basically org.apache.thrift.TException, they aren't suitable for general purpose exception. For instance, the message of QueryException.QUERY_VALIDATION_ERROR is statically set when defined/initialized.

Can't you use QueryProcessingException instead?

QueryProcessingException isn't throwable. It's named exception but it's really a QueryExceptionContainer used on broker side.

@vvivekiyer vvivekiyer merged commit bfe5728 into apache:master Jan 29, 2025
21 checks passed
@gortiz
Copy link
Contributor

gortiz commented Jan 30, 2025

Hi there! I'm working on improving query error management. I've created #14950 to try to keep track of it and also started to create some exception hierarchies we can use. That is probably collision with changes made here. Are you planning to continue working on error management?

@real-mj-song
Copy link
Contributor Author

real-mj-song commented Jan 30, 2025

@gortiz
Oh nice! Your PinotRuntimeException and QException were exactly what I was looking for 💯 I was not planning to make more changes, but once your PR is merged, I can make a quick PR to replace/remove QueryInfoException.java with your new exception class and slightly change exception catch logic. Or feel free to just include part of your PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants