apache/druid · error · UnsupportedOperationException

Bloom filter aggregators are query-time only

Error message

Bloom filter aggregators are query-time only

What it means

BloomFilterAggregatorFactory.makeAggregateCombiner() deliberately throws UnsupportedOperationException because bloom filter aggregators can only run within a single query; they cannot be used to build/combine persistent (index-time or stream-ingested) aggregates. The AggregateCombiner API exists for column-based merging that this query-time-only aggregator does not support.

Source

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

    if (rhs == null) {
      return lhs;
    }
    if (lhs == null) {
      return rhs;
    }
    BloomKFilter.mergeBloomFilterByteBuffers(
        (ByteBuffer) lhs,
        ((ByteBuffer) lhs).position(),
        (ByteBuffer) rhs,
        ((ByteBuffer) rhs).position()
    );
    return lhs;
  }

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

  @Override
  public AggregatorFactory getCombiningFactory()
  {
    return new BloomFilterMergeAggregatorFactory(name, name, maxNumEntries);
  }

  @Override
  public Object deserialize(Object object)
  {
    if (object instanceof String) {
      return ByteBuffer.wrap(StringUtils.decodeBase64String((String) object));
    } else if (object instanceof byte[]) {
      return ByteBuffer.wrap((byte[]) object);
    } else {
      return object;
    }

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Move the bloom filter aggregation to query time (post-aggregation/query-level aggregator), not the ingestion spec
  2. If a merge is needed across segments, use BloomFilterMergeAggregatorFactory / the merge aggregator via getCombiningFactory() in query-merge contexts only
  3. Compute filters in the query layer and persist only the filter bytes in application code if needed

Example fix

// before (ingestion spec)
"aggregators": [{"type": "bloom", "name": "bf", "field": {"type": "default", "dimension": "user_id"}}]
// after
// omit from ingestion spec; add at query time:
{"queryType": "groupBy", "aggregations": [{"type": "bloom", "name": "bf", "field": {"type": "default", "dimension": "user_id"}}]}
Defensive patterns

Strategy: validation

Validate before calling

// Before using an AggregatorFactory in an ingestion spec:
if (factory instanceof BloomFilterAggregatorFactory) {
  throw new IllegalArgumentException("Bloom filter aggregators are query-time only; do not add to ingestion spec");
}

Type guard

boolean isQueryTimeOnly = factory instanceof BloomFilterAggregatorFactory;

Try / catch

try {
  combiner = factory.makeAggregateCombiner();
} catch (UnsupportedOperationException e) {
  // fall back to query-time aggregation path
  throw new IllegalStateException("Configure bloom aggregation in the query, not ingestion", e);
}

Prevention

When it happens

Trigger: Any code path calling makeAggregateCombiner() on a bloom filter aggregator factory, e.g. using 'bloom' aggregators during ingestion (spec's aggregators list), or query engines/combining machinery that pre-combines segments via AggregateCombiner instead of the query-time combiner.

Common situations: Developers adding a BloomFilterAggregator to an ingestion spec (Kafka/Kinesis/index_parallel) trying to pre-aggregate bloom filters into segments; custom extensions or test harnesses invoking AggregateCombiner on this factory.

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/4a2169afff3b22a1. Report an issue: GitHub.