apache/druid · error · UnsupportedOperationException

Bloom filter aggregators are query-time only

Error message

Bloom filter aggregators are query-time only

What it means

BloomFilterSerde.getExtractor() throws UnsupportedOperationException because bloom filters are query-time only: there is no ingestion-time extraction from raw data into a bloom filter column. The ComplexMetricExtractor API is used at ingestion to pull values into a complex column, which this serde deliberately does not support.

Source

Thrown at extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterSerde.java:52

import java.nio.ByteBuffer;

/**
 * Exists to provide an object-strategy. Bloom filters are query time only so does not fully implement this interface.
 */
public class BloomFilterSerde extends ComplexMetricSerde
{
  private static final BloomFilterObjectStrategy STRATEGY = new BloomFilterObjectStrategy();

  @Override
  public String getTypeName()
  {
    return BloomFilterSerializersModule.BLOOM_FILTER_TYPE_NAME;
  }

  @Override
  public ComplexMetricExtractor getExtractor()
  {
    throw new UnsupportedOperationException("Bloom filter aggregators are query-time only");
  }

  @Override
  public void deserializeColumn(ByteBuffer byteBuffer, ColumnBuilder columnBuilder)
  {
    throw new UnsupportedOperationException("Bloom filter aggregators are query-time only");
  }

  @Override
  public GenericColumnSerializer getSerializer(
      SegmentWriteOutMedium segmentWriteOutMedium,
      String column,
      IndexSpec indexSpec
  )
  {
    throw new UnsupportedOperationException("Bloom filter aggregators are query-time only");
  }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Remove bloom-filter metrics from ingestion specs; compute filters in queries instead
  2. For precomputed filters, store serialized filters via your own ingestion path, not this serde's extractor API
  3. Use the bloom filter SQL/native aggregation at query time over the source column

Example fix

// before (ingestion spec metrics)
{"metrics": [{"type": "bloom", "name": "bf", "fieldName": "user_id"}]}
// after
// drop the metric; aggregate at query time:
{"aggregations": [{"type": "bloom", "name": "bf", "field": {"type": "default", "dimension": "user_id"}}]}
Defensive patterns

Strategy: validation

Validate before calling

// Before declaring an ingestion metric:
boolean bloomSerde = "bloom".equalsIgnoreCase(metricSpec.getType());
if (bloomSerde) throw new IllegalArgumentException("bloom serde has no ingestion extractor");

Try / catch

try {
  extractor = serde.getExtractor();
} catch (UnsupportedOperationException e) {
  // route to query-time aggregation instead of ingestion metric
}

Prevention

When it happens

Trigger: Configuring a complex metric / ingestion spec that references the bloom filter serde as a metric expecting value extraction, or any ingestion code calling getExtractor() on BloomFilterSerde.

Common situations: Developers trying to precompute/persist bloom filters during ingestion by declaring them as complex metrics; copy-pasting ingestion specs from other complex columns (e.g. HyperUnique) and swapping in the bloom serde.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/45dde9a3a2085d7f. Report an issue: GitHub.