Repository navigation
[FLINK-40940][connector-http] Decide lookup row emission independently of applyReadableMetadata - #56
Conversation
81d678b to
5eb322e
Compare
|
@AHeise thanks for the contribution. So we are issuing a lookup join, we only expect a row if there is a match - there is no a match, no response or there is an error we cannot tell the difference so we treat that as a non match. In this way we only get enrichment rows for the API table when there is something there. It would be unexpected for our user to see rows if there were errors. This is our main use case. If our user wants to see the complete rows then they can use a LEFT join. The left join allows the user to get rows back in all error cases. The Null enrichment rows are provided by the Flink framework. The copy change looks good. |
5eb322e to
ca1bdd4
Compare
|
@davidradl fair, that is the cleaner contract, and it is planner-independent as well: a response without data yields a row exactly when metadata columns are declared, so an inner join drops failed lookups and a LEFT JOIN pads them with nulls. I reworked the main commit that way, added inner/LEFT JOIN IT specs, and made the docs say it explicitly; the old "lookup join will complete without content in the expected enrichment columns" read as if inner joins kept the row. Description has a before/after table. |
| // If field is null and it's a join key, populate from keyRow | ||
| if (value == null && !joinKeyValues.isEmpty() && pos < physicalFieldNames.size()) { | ||
| if (joinKeyValues.containsKey(fieldName)) { | ||
| value = joinKeyValues.get(fieldName); |
There was a problem hiding this comment.
@AHeise I am not convinced with should override the id column with the probe column value if we get a null back.
So the table to be enriched has id column an event with id=1 comes in, we issue a lookup using id=1, but the response gives us a null value in id, since the id here is a response field. In this case I think we should honour the null. In the same way we would honour values that were no null and did not match the request join key value. Or is there some side effect with this approach?
We could add to the docs to say something like: if the user wants to process field names that are the same and the same type and exist in the the API request and response, it is possible to define one column; in this case the response value will be populated after the API call. If the user would like to keep the request and response values separate then the response column should be defined with the name in the response, the path, query param or body field should be mapped from a differently named column name. In this way you can keep both the request and the response values in SQL columns. This is the pattern we use.
There was a problem hiding this comment.
The fill-in predates this PR (it came with #39); I dropped the commit that applied it to metadata rows without response data, so those keep the join key columns null, and the docs say so. For rows with response data the behavior stays as is: honoring the null there is a behavior change that, as you said above, needs an option defaulting to today's behavior. No planner side effect as far as I can tell: with the fill-in disabled entirely, all 121 HttpLookupTableSourceITCaseTest cases pass, only HttpTableLookupFunctionPopulateJoinKeysTest pins it. Happy to open a follow-up for the option plus your docs note on separate request/response columns.
…y of applyReadableMetadata HttpTableLookupFunction decides whether a response without data yields a row based on whether producedDataType is set, which only happens when the planner calls applyReadableMetadata. For tables without metadata columns the planner calls it only when it pushes a projection, so a failed call with http.source.lookup.continue-on-error or an ignored status code drops the row for queries without a pushed projection but emits an all-null row for queries with one. A response without data yields a row exactly when metadata columns are declared, sized from the physical row type. Without metadata columns a failed call is a lookup miss, so an inner lookup join drops the row and a LEFT JOIN pads it with nulls; the docs state this explicitly. The unused producedDataType is removed. Generated-by: Claude Code (Opus 5.5)
…ableSource#copy HttpLookupTableSource#copy creates a source from the constructor arguments only, so a copy taken after applyReadableMetadata drops the metadata keys. The lookup function of such a copy emits rows without the metadata columns the planner expects. The copy carries the metadata keys over, and the source defines equality over its physical type, lookup config, decoding format, cache and metadata keys. Generated-by: Claude Code (Opus 5.5)
ca1bdd4 to
798d9ef
Compare

What is the purpose of the change
HttpTableLookupFunctiondecided whether a response without data yields a row based on whetherproducedDataTypewas set.HttpLookupTableSourcesets it only inapplyReadableMetadata, and for a table without metadata columns the planner calls that only when it pushes a projection. So the same failed call (withhttp.source.lookup.continue-on-error) or ignored status code behaved differently depending on the query:FLINK-38569 stops the planner from recording the empty
ReadingMetadataability, which would have made the planner-dependent path the only one.Without metadata columns, a response without data is a lookup miss: an inner lookup join drops the row, and a
LEFT JOINpads it with nulls. To see failed calls, declare metadata columns.Brief change log
applyReadableMetadata: a response without data yields a row exactly when metadata columns are declared, and the row is sized from the physical row type. The unusedproducedDataTypeis removed from the source and the lookup function. The docs (en + zh) state the inner join /LEFT JOINbehavior explicitly, and that the join key columns of such a metadata row stay null.HttpLookupTableSource#copy:copy()droppedmetadataKeys. The source also definesequals/hashCode.Verifying this change
HttpTableLookupFunctionTest(new): for everyHttpCompletionState, a response without data emits no row without metadata columns, and a row with metadata (all physical columns null) otherwise.HttpLookupTableSourceTest#copyRetainsReadableMetadata:copy()equals the source afterapplyProjectionandapplyReadableMetadata.HttpLookupTableSourceITCaseTest#testHttpLookupJoinParameterized: new bad-status specs without metadata columns for GET/POST/PUT, sync/async, continue-on-error on/off and inner/LEFT JOIN. With continue-on-error, the inner join yields no rows and theLEFT JOINyields the four probe rows with null enrichment.mvn verify -pl flink-connector-httppasses on each commit (JDK 17, Flink 2.2.0).Does this pull request potentially affect one of the following parts:
@Public(Evolving): no (theHttpTableLookupFunctionconstructor loses itsproducedDataTypeparameter; the class is not annotated)Documentation
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5.5)