Skip to content

[python] Serialize high-precision decimals with Java's minimal bytes - #10872

Closed
plusplusjiajia wants to merge 1 commit into
apache:masterfrom
plusplusjiajia:fix/python-decimal-minimal-bytes
Closed

plusplusjiajia wants to merge 1 commit into
apache:masterfrom
plusplusjiajia:fix/python-decimal-minimal-bytes

Conversation

@plusplusjiajia

Copy link
Copy Markdown
Member

Purpose

Decimals with precision above 18 store their unscaled value as two's complement bytes. PyPaimon computed the length as (bit_length() + 8) // 8, which adds an extra byte for negative values that are exactly -2^(8k-1). For example, -1.28 in DECIMAL(20, 2) was written as ff80, while Java writes 80 (BigInteger.toByteArray). Such primary keys hashed to a different bucket than in Java (bucket 2 instead of 7 with 10 buckets), and such partition values had different bytes than Java's.

BinaryRow serialization and the row format writer now use the minimal encoding, like Java, through one shared helper. The global index key serializer also uses this helper instead of its own copy.

Tests

  • DecimalTest#test_decimal_not_compact_java_bytes and #test_decimal_fixed_bucket_matches_java in decimal_test.py: BinaryRow bytes and the fixed bucket match Java, and longer encodings are still read.
  • TestFormatRowReaderWriter#test_decimal_minimal_bytes: the row format writer writes Java's bytes.
  • DecimalKeySerializerTest#test_java_decimal_bytes and test_decimal.py: the global index key serializer and Decimal keep Java's bytes.
  • 7 of the new test cases fail on master; the key serializer and Decimal cases guard existing behavior. The related tests pass locally: 104 tests. flake8 is clean.

Decimals with precision above 18 store their unscaled value as two's
complement bytes. PyPaimon computed the length as
(bit_length() + 8) // 8, which adds a byte for negative values that are
exactly -2^(8k-1), so -1.28 in DECIMAL(20,2) was written as ff80 while
Java writes 80 (BigInteger.toByteArray). Such keys hashed to a different
bucket than in Java (bucket 2 instead of 7 with 10 buckets), and such
partition values had different bytes than Java's.

BinaryRow serialization and the row format writer now use the minimal
encoding through one shared helper, which the global index key
serializer also uses instead of its own copy.
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.

1 participant