task-54: finalRowCount 改为任务内增量计数(upsert newlyInserted 累计),移除每 chunk 全表 COUNT(*)
This commit is contained in:
+6
-14
@@ -666,8 +666,12 @@ public class CollectDataService {
|
||||
requireRustfsPayload(storedDetail, "采集结果明细必须写入 RustFS");
|
||||
// 批量 upsert:先一次批量查现有行(payload_hash 相等即跳过,幂等),
|
||||
// 再按唯一键 uk_task_scope_item 分批发 INSERT ... ON DUPLICATE KEY UPDATE。
|
||||
resultItemBatchWriter.upsertAccepted(task.getId(), result.getId(), scopeKey,
|
||||
chunkIndex, accepted, storedDetail);
|
||||
// newlyInserted 是本 chunk 真实新增的行数,任务内增量累计得到 finalRowCount,
|
||||
// 替代每个 chunk 一次全表 COUNT(*),且与 chunk 乱序/重提无关。
|
||||
CollectDataResultItemBatchWriter.UpsertCounts upsertCounts =
|
||||
resultItemBatchWriter.upsertAccepted(task.getId(), result.getId(), scopeKey,
|
||||
chunkIndex, accepted, storedDetail);
|
||||
stats.finalRowCount += upsertCounts.newlyInserted();
|
||||
}
|
||||
|
||||
String payloadJson = writeJson(rows, "采集结果序列化失败");
|
||||
@@ -677,7 +681,6 @@ public class CollectDataService {
|
||||
persistChunk(taskId, scopeKey, scopeHash, chunkIndex, chunkTotal, storedPayload, payloadJson);
|
||||
persistScope(taskId, scopeKey, scopeHash, chunkTotal, request);
|
||||
|
||||
stats.finalRowCount = countFinalRows(taskId);
|
||||
// Python 在 done=true 那次回传携带关键词级聚合统计;非空时按"最后一次为准"覆盖。
|
||||
List<CollectDataSummaryRowDto> incomingSummaries = request.getSummaries();
|
||||
if (incomingSummaries != null && !incomingSummaries.isEmpty()) {
|
||||
@@ -946,16 +949,6 @@ public class CollectDataService {
|
||||
return out;
|
||||
}
|
||||
|
||||
private int countFinalRows(Long taskId) {
|
||||
if (taskId == null || taskId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
Long count = taskResultItemMapper.selectCount(new LambdaQueryWrapper<TaskResultItemEntity>()
|
||||
.eq(TaskResultItemEntity::getTaskId, taskId)
|
||||
.eq(TaskResultItemEntity::getModuleType, MODULE_TYPE));
|
||||
return count == null ? 0 : count.intValue();
|
||||
}
|
||||
|
||||
private void ensureRustfsPayloadStorageEnabled() {
|
||||
if (!transientPayloadStorageService.isSharedWriteEnabled()) {
|
||||
throw new BusinessException("RustFS 未配置,采集结果回传暂不可接收");
|
||||
@@ -1011,7 +1004,6 @@ public class CollectDataService {
|
||||
CollectDataSubmitResultRequest request,
|
||||
int currentChunkRows) {
|
||||
CollectDataStats stats = loadStats(task);
|
||||
stats.finalRowCount = countFinalRows(task == null ? null : task.getId());
|
||||
CollectDataSubmitResultVo vo = new CollectDataSubmitResultVo();
|
||||
vo.setTaskId(task == null ? null : task.getId());
|
||||
vo.setResultId(result == null ? null : result.getId());
|
||||
|
||||
+23
-4
@@ -45,15 +45,21 @@ public class CollectDataResultItemBatchWriter {
|
||||
this.batchSize = batchSize <= 0 ? DEFAULT_BATCH_SIZE : batchSize;
|
||||
}
|
||||
|
||||
/** 批量写入计数:insertedOrUpdated 实际写入行数,skipped hash 相等跳过行数。 */
|
||||
public record UpsertCounts(int insertedOrUpdated, int skipped) {
|
||||
/**
|
||||
* 批量写入计数:
|
||||
* insertedOrUpdated 由 mapper 返回的 affected 行数累加(INSERT=1、存量更新可能为 2,
|
||||
* 仅用于诊断日志);
|
||||
* newlyInserted 是本次调用真实新增的行数(仅原本不存在的行,hash 相等跳过与存量
|
||||
* 更新均不计入,批量失败扣除未写入的新行),供调用方做任务内 finalRowCount 增量累计。
|
||||
*/
|
||||
public record UpsertCounts(int insertedOrUpdated, int skipped, int newlyInserted) {
|
||||
}
|
||||
|
||||
/** 把整 chunk 的 accepted 行批量 upsert;scopeKey 与 chunk 内 offset 已知,仅计算 refJson 与 hash。 */
|
||||
public UpsertCounts upsertAccepted(Long taskId, Long resultId, String scopeKey, int chunkIndex,
|
||||
List<CollectDataResultRowVo> rows, String storedDetail) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return new UpsertCounts(0, 0);
|
||||
return new UpsertCounts(0, 0, 0);
|
||||
}
|
||||
String scopeHash = sha256(scopeKey);
|
||||
// 一次性取回本 scope 现有行,构建 item_key → 现有行 映射(hash 相等即跳过)。
|
||||
@@ -71,6 +77,9 @@ public class CollectDataResultItemBatchWriter {
|
||||
|
||||
List<TaskResultItemEntity> toUpsert = new ArrayList<>();
|
||||
int skipped = 0;
|
||||
// 仅原本不存在的行(真 INSERT)计入 newlyInserted;存量行 hash 不同触发 UPDATE
|
||||
// 时表内行数不变,不计入,避免 finalRowCount 增量虚高。
|
||||
int newlyInserted = 0;
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
// 批量生成整 chunk 的引用 JSON + hash(一次迭代),替代逐行 encodeRef + hash。
|
||||
List<CollectDataResultDetailCodec.RefWithHash> refsWithHash =
|
||||
@@ -111,6 +120,9 @@ public class CollectDataResultItemBatchWriter {
|
||||
entity.setCreatedAt(existing == null ? now : existing.getCreatedAt());
|
||||
entity.setUpdatedAt(now);
|
||||
toUpsert.add(entity);
|
||||
if (existing == null) {
|
||||
newlyInserted++;
|
||||
}
|
||||
}
|
||||
|
||||
int written = 0;
|
||||
@@ -122,9 +134,16 @@ public class CollectDataResultItemBatchWriter {
|
||||
} catch (RuntimeException ex) {
|
||||
log.warn("[collect-data] upsert result item batch failed, skip batch {}..{} taskId={}",
|
||||
from, to, taskId, ex);
|
||||
// 失败批的新行未落库,从增量计数中扣除,避免任务内累计虚高;
|
||||
// 重提该 chunk 时按存量 hash 跳过已落库行、补插未落库行,累计收敛到真实行数。
|
||||
for (TaskResultItemEntity entity : batch) {
|
||||
if (entity.getId() == null) {
|
||||
newlyInserted--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UpsertCounts(written, skipped);
|
||||
return new UpsertCounts(written, skipped, newlyInserted);
|
||||
}
|
||||
|
||||
private static String sha256(String value) {
|
||||
|
||||
Reference in New Issue
Block a user