Skip to content

Core: Add id tracking to MetricsConfig#17022

Merged
rdblue merged 13 commits into
apache:mainfrom
rdblue:update-metrics-config
Jul 7, 2026
Merged

Core: Add id tracking to MetricsConfig#17022
rdblue merged 13 commits into
apache:mainfrom
rdblue:update-metrics-config

Conversation

@rdblue

@rdblue rdblue commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Metrics modes are configured in table properties based on column names, but content stats needs to look up MetricsMode based on column ID. This adds support to look up metrics mode by ID, columnMode(int), and adds an accessor for the IDs for which there is a metrics mode. This is needed to build a table's current content stats struct for writing.

This also cleans up a couple of issues with MetricsConfig:

  • Removes the deprecated forPositionDelete(Table) instead of modifying its behavior. Also removes uses of this deprecated method, using forPositionDelete() instead.
  • Updates the deprecation of fromProperties to 1.13.0 instead of 2.0.0 because this is in core. Also removes uses of this deprecated method, which should be done when it is deprecated.
  • Adds validate(Map<String, String>,Schema) to replace uses of fromProperties

@rdblue rdblue force-pushed the update-metrics-config branch from 3a5cd12 to 173594a Compare June 30, 2026 18:03
}

@Test
public void testColumnModeAndFieldIdsFromColumnConfig() {

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.

These are the tests for new behavior.

}
}

public void validateReferencedColumns(Schema schema) {

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.

These were moved above the private and static methods. It was hard to find them before.

Comment thread core/src/main/java/org/apache/iceberg/MetricsConfig.java
Comment thread core/src/main/java/org/apache/iceberg/MetricsConfig.java
public static MetricsConfig forPositionDelete(Table table) {
ImmutableMap.Builder<String, MetricsMode> columnModes = ImmutableMap.builder();
public Iterable<Integer> metricsFieldIds() {
return idToName.keySet();

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.

Should this return an empty list if idToName is null?

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.

No, I think it should fail if idToName is null because there could be a configuration, but the config wasn't initialized the right way. If idToName is null, then it was initialized without a schema, which we want to stop doing.

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.

I've updated this (and columnMode(int)) to check that idToName is present and throw an exception if not. That way, when we get rid of fromProperties, we can get rid of the check.

Map<Integer, String> idToName) {
this.columnModes = SerializableMap.copyOf(columnModes).immutableMap();
this.defaultMode = defaultMode;
if (idToName != null) {

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.

Ok it's a bit confusing because there are accessor APIs below which assume that idToName is not null. Currently, we pass it in, but I'm not sure I understand the intent of if (idToName != null) check is. It's a private constructor, can't we force every where else to pass in the idToName and then work off that assumption that it's always defined?

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.

Right now, I don't think that we can force every code path to provide a schema, which is how this is derived. That would be more changes and those code paths don't need to use IDs, so I left it out. For instance, fromProperties is still defined (until next release) and we can't fake a schema for that call. We could cause it to fail, but that would defeat the purpose of deprecating it.

The approach I took here was to use idToName if it is present. I thought this was a better option than causing external calls to fromProperties to fail. We can tighten this up after the next release when we can guarantee all code paths pass a schema.

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.

Got it, okay I missed the original fromProperties, yeah in that case we can just keep it as is.

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.

I added assertions to ensure we don't get NPEs. We can remove them once idToName is always present.

Comment thread core/src/main/java/org/apache/iceberg/MetricsConfig.java
table == null
? MetricsConfig.forPositionDelete()
: MetricsConfig.forPositionDelete(table);
MetricsConfig metricsConfig = MetricsConfig.forPositionDelete();

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.

Since we're just calling MetricsConfig.forPositionDelete(), now we're falling through to the default truncate(16) and changing what we collect bounds on (and it looks like Spark CI is failing). It is a behavior change for the position deletes where rows are stored but iirc nobody really even writes those and that was on a deprecation path anyways.

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.

Agreed, I have a separate PR aimed to remove deprecated method for 1.12 which include the MetricsConfig.forPositionDelete(table) in #16449

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.

I updated this to use None by default and fixed the tests so they are passing.

@amogh-jahagirdar amogh-jahagirdar 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.

Looks correct to me, we'll just need to fixup the wong preconditions import before we merge!

Comment thread core/src/main/java/org/apache/iceberg/MetricsConfig.java Outdated
Comment thread core/src/main/java/org/apache/iceberg/MetricsConfig.java Outdated
schema);

ValidationException.check(
null == idToName || column.equals(idToName.get(field.fieldId())),

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.

was thinking about the field rename and preserve the field id but I believe it's already covered in schema update https://github.com/apache/iceberg/blob/main/core/src/main/java/org/apache/iceberg/SchemaUpdate.java#L517-L524

assertThat(bounds).hasSize(4);
assertThat((int) Conversions.fromByteBuffer(Types.IntegerType.get(), bounds.get(1)))
.isEqualTo(3);
assertThat(bounds).hasSize(2);

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.

nit: we should be able to make a one-liner out of this entire check: assertThat(bounds).hasSize(2).doesNotContainKeys(1, 2, 3, 4, 5);

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.

also maybe we can just inline this check into the test that uses it and remove checkRowStatistics(), since it's really only used in a single test

*/
public interface MetricsMode extends Serializable {}
public interface MetricsMode extends Serializable {
default boolean hasBounds() {

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.

is this used anywhere? it's not clear from the PR description why this is being added

@rdblue rdblue merged commit 773907d into apache:main Jul 7, 2026
55 checks passed
@rdblue

rdblue commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@nastra, sorry I missed your comments, I should have reloaded. I just saw tests passing and merged.

The hasBounds method is for stats struct generation and it was part of my branch when I separated the metrics changes out.

Kurtiscwright pushed a commit to Kurtiscwright/iceberg that referenced this pull request Jul 7, 2026
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.

4 participants