{"record":{"id":"4a2169afff3b22a1","repo":"apache/druid","slug":"bloom-filter-aggregators-are-query-time-only","errorCode":null,"errorMessage":"Bloom filter aggregators are query-time only","messagePattern":"Bloom filter aggregators are query-time only","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterAggregatorFactory.java","lineNumber":130,"sourceCode":"    if (rhs == null) {\n      return lhs;\n    }\n    if (lhs == null) {\n      return rhs;\n    }\n    BloomKFilter.mergeBloomFilterByteBuffers(\n        (ByteBuffer) lhs,\n        ((ByteBuffer) lhs).position(),\n        (ByteBuffer) rhs,\n        ((ByteBuffer) rhs).position()\n    );\n    return lhs;\n  }\n\n  @Override\n  public AggregateCombiner makeAggregateCombiner()\n  {\n    throw new UnsupportedOperationException(\"Bloom filter aggregators are query-time only\");\n  }\n\n  @Override\n  public AggregatorFactory getCombiningFactory()\n  {\n    return new BloomFilterMergeAggregatorFactory(name, name, maxNumEntries);\n  }\n\n  @Override\n  public Object deserialize(Object object)\n  {\n    if (object instanceof String) {\n      return ByteBuffer.wrap(StringUtils.decodeBase64String((String) object));\n    } else if (object instanceof byte[]) {\n      return ByteBuffer.wrap((byte[]) object);\n    } else {\n      return object;\n    }","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-bloom-filter/src/main/java/org/apache/druid/query/aggregation/bloom/BloomFilterAggregatorFactory.java#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Move the bloom filter aggregation to query time (post-aggregation/query-level aggregator), not the ingestion spec","If a merge is needed across segments, use BloomFilterMergeAggregatorFactory / the merge aggregator via getCombiningFactory() in query-merge contexts only","Compute filters in the query layer and persist only the filter bytes in application code if needed"],"exampleFix":"// before (ingestion spec)\n\"aggregators\": [{\"type\": \"bloom\", \"name\": \"bf\", \"field\": {\"type\": \"default\", \"dimension\": \"user_id\"}}]\n// after\n// omit from ingestion spec; add at query time:\n{\"queryType\": \"groupBy\", \"aggregations\": [{\"type\": \"bloom\", \"name\": \"bf\", \"field\": {\"type\": \"default\", \"dimension\": \"user_id\"}}]}","handlingStrategy":"validation","validationCode":"// Before using an AggregatorFactory in an ingestion spec:\nif (factory instanceof BloomFilterAggregatorFactory) {\n  throw new IllegalArgumentException(\"Bloom filter aggregators are query-time only; do not add to ingestion spec\");\n}","typeGuard":"boolean isQueryTimeOnly = factory instanceof BloomFilterAggregatorFactory;","tryCatchPattern":"try {\n  combiner = factory.makeAggregateCombiner();\n} catch (UnsupportedOperationException e) {\n  // fall back to query-time aggregation path\n  throw new IllegalStateException(\"Configure bloom aggregation in the query, not ingestion\", e);\n}","preventionTips":["Never put 'bloom' aggregators in ingestion spec aggregators lists","Use bloom filters only in native/SQL query aggregations","Read the aggregator docs to confirm query-time-only semantics before reuse"],"tags":["druid","bloom-filter","unsupported-operation","query-time-only"],"backgroundTag":"unsupported-operation","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}