发布

  • [OPIK-5659] [BE] fix: delete experiment aggregates when an experiment is deleted (#6428)

    frostbyte_neo 发布于 2026-04-22 13:33:05 +00:00

    • [OPIK-5659] [BE] fix: delete experiment aggregates when an experiment is deleted

    Wire ExperimentAggregateEventListener to ExperimentsDeleted so rows in
    experiment_aggregates and experiment_item_aggregates are removed when an
    experiment is deleted. Previously the denormalized aggregate rows were
    orphaned forever, causing unbounded growth and stale reads via the FINAL
    scans used by the hybrid query path.

    • ExperimentsDeleted now carries the deleted experiment ids; ExperimentService.delete forwards them to the event.
    • ExperimentAggregatesDAO.deleteByExperimentIds issues workspace-scoped DELETE FROM against experiment_aggregates (by id) and experiment_item_aggregates (by experiment_id).
    • ExperimentAggregatesService exposes the DAO call with logging.
    • ExperimentAggregateEventListener.onExperimentsDeleted restores the workspace context from the event and calls the service.
    • New integration tests verify direct deletion and end-to-end cleanup via the async event bus.

    Implements OPIK-5659: fix experiment aggregation query overload.

    • fix(aggregation): clean up item aggregates on experiment item deletion

    Wire ExperimentItemsDeleted to also remove orphan rows from
    experiment_item_aggregates for each deleted item. Previously the
    listener only re-triggered aggregation, leaving stale per-item
    aggregate rows that the has_aggregated query branch kept returning.

    • New ExperimentItemRef(experimentId, itemId) record preserves the
      per-item -> experiment association.
    • ExperimentItemsDeleted now carries Set with
      derived experimentIds()/itemIds() accessors.
    • ExperimentItemService.delete selects refs, buffers them in chunks
      of 1000, groups each chunk by experimentId, and for each group
      deletes items + publishes the event so listeners receive refs
      scoped to a single experiment.
    • ExperimentItemDAO.delete now scoped by experiment_id and :ids.
    • ExperimentAggregatesDAO/Service add deleteItemAggregatesByItemIds
      for per-experiment item-aggregate cleanup.
    • Listener groups event.itemRefs() by experiment, deletes item
      aggregates for each, then re-triggers aggregation via the
      existing path.
    • Integration test deleteExperimentItemsCleansUpItemAggregatesViaEvent
      covers the partial-delete flow by comparing the aggregated query
      against beforeAggregation minus the deleted ids.
    • style: remove trailing whitespace (spotless)
    下载附件