Skip to content

[SPARK-58096][SQL] Fix approx_top_k wrong counts/items for UNICODE-collated non-ASCII strings#57272

Open
jiwen624 wants to merge 2 commits into
apache:masterfrom
jiwen624:SPARK-58096
Open

[SPARK-58096][SQL] Fix approx_top_k wrong counts/items for UNICODE-collated non-ASCII strings#57272
jiwen624 wants to merge 2 commits into
apache:masterfrom
jiwen624:SPARK-58096

Conversation

@jiwen624

@jiwen624 jiwen624 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Follow-up to #57177.
approx_top_k on a non-binary collated string keyed its DataSketches item on getCollationKey(...).toString(). ICU sort keys are arbitrary bytes, not valid UTF-8, so .toString() lossily maps them to U+FFFD and merges collation-distinct values into one item with an inflated count. This changes CollatedString to key on the raw sort-key byte[] (via CollationFactory.getCollationKeyBytes), so key and original round-trip losslessly with no Java String intermediary. The on-wire serde format is unchanged (only original is persisted).

Why are the changes needed?

Wrong counts for any UNICODE/UNICODE_CI/locale collation over non-ASCII data (e.g. 且/丕/世 collapse to one item). UTF8_BINARY and UTF8_LCASE are unaffected.

SELECT approx_top_k(c, 10)
FROM (SELECT CAST(col AS STRING COLLATE UNICODE_CI) AS c
      FROM VALUES (''),(''),(''),(''),(''),('') AS t(col));
-- returns a SINGLE item with count 6, instead of 3 items with counts 3, 2, 1

Does this PR introduce any user-facing change?

Yes — fixes incorrect approx_top_k counts/items for ICU-collated non-ASCII strings.

How was this patch tested?

Added UT case.

Was this patch authored or co-authored using generative AI tooling?

Yes

@jiwen624
jiwen624 marked this pull request as ready for review July 15, 2026 21:56
this.original = original;
}

public String key() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Dropped the unused key() accessor: nothing reads it, and exposing the raw sort-key byte[] leads to a risk of it being mutated externally.

@jiwen624 jiwen624 changed the title [SPARK-58096][SQL] approx_top_k over-merges ICU-collation-distinct values via lossy sort-key decode [SPARK-58096][SQL] Fix approx_top_k wrong counts/items for UNICODE-collated non-ASCII strings Jul 15, 2026
@jiwen624

Copy link
Copy Markdown
Contributor Author

Hi @cloud-fan this patch fixes the approx_top_k wrong count/result issue which is the follow-up to #57177 Thank you.

@cloud-fan cloud-fan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

0 blocking, 1 non-blocking, 0 nits.
Clean, well-scoped fix — keying on raw sort-key bytes matches the Mode analogue and correctly avoids the lossy-toString over-merge at both key-producing sites. One optional test-coverage note.

Suggestions (1)

  • ApproxTopKSuite.scala:314: non-ASCII regression coverage is missing for the accumulate/estimate/combine (serde deserialize) path — see inline

}

// scalastyle:off nonascii
test("SPARK-58096: approx_top_k keys on raw sort-key bytes, not a lossy-decoded String, " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The same lossy-toString bug also lived in ArrayOfCollatedStringsSerDe.wrap (the deserialize path), and the fix corrects it there too — but this new test only exercises the direct approx_top_k update path. The existing SPARK-58069 accumulate/combine tests above use ASCII-only fixtures ('HELLO'/'world'), which can't observe the over-merge, so the serde path currently has no non-ASCII regression guard. Consider mirroring this case through approx_top_k_estimate(approx_top_k_accumulate(...)) (and/or combine) to cover that second key-producing site. Non-blocking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Added test coverage 👍

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants