feat: 完善知识库批量导入与公共 API

- 新增批量异步导入、状态查询、失败重试与中断恢复链路

- 拆分知识库读取、导入、维护权限并完善 Public API 契约

- 补充数据库迁移、管理端交互、接口说明与相关测试
This commit is contained in:
2026-08-03 11:13:48 +08:00
parent 6df3dd9981
commit 51dbfd41b6
99 changed files with 16274 additions and 480 deletions

View File

@@ -47,7 +47,7 @@ easyflow:
max-retry: 16
consumer-executor:
core-size: 4
max-size: 12
max-size: 32
queue-capacity: 64
keep-alive-seconds: 60
pool:

View File

@@ -10,6 +10,9 @@ server:
enabled: true
charset: UTF-8 # 必须设置 UTF-8避免 WebFlux 流式返回AI 场景)会乱码问题
force: true
tomcat:
# Public API 单次最多 200 个文件,额外为 metadata 与表单边界预留 Part。
max-part-count: 205
spring:
profiles:
@@ -44,8 +47,8 @@ spring:
servlet:
multipart:
max-file-size: 100MB
# 为 multipart 边界和请求头预留空间,文件本身仍由 M18 的 100 MiB 硬上限约束
max-request-size: 105MB
# Public API 业务上限为 200 MiB为 metadata 与 multipart 边界预留空间
max-request-size: 220MB
web:
resources:
# 示例windows【file: C:\easyflow\attachment】 linux【file: /www/easyflow/attachment】
@@ -127,7 +130,7 @@ easyflow:
max-retry: 16
consumer-executor:
core-size: 16
max-size: 24
max-size: 32
queue-capacity: 64
keep-alive-seconds: 60
pool:
@@ -198,6 +201,22 @@ easyflow:
health:
cache-ttl: 5s
document-import:
bulk:
max-file-count: 2000
max-total-size: 1GB
max-file-size: 100MB
upload-concurrency: 3
parse-max-running: 2
split-max-running: 2
index-max-running: 2
per-batch-parse-max-running: 2
pending-dispatch-batch-size: 100
pending-dispatch-interval: 2s
pending-redispatch-delay: 5s
pending-timeout: 24h
parse-submit-timeout: 120s
interruption-timeout: 10m
max-task-attempts: 3
status-broadcast-channel: easyflow:document-import:status
parse-monitor:
fixed-delay: 10000
@@ -249,7 +268,8 @@ easy-agents:
provider: mineru
mineru:
# 统一文档解析桥接层直接复用 easy-agents 的 provider 配置,不在 easyflow 再复制一套配置体系
base-url: https://hub.wust.edu.cn/modelServer/mineru-api
base-url: https://ontoweb.wust.edu.cn/mineru-api
submit-timeout-ms: 120000
default-lang-list:
- ch

View File

@@ -0,0 +1,52 @@
CREATE TABLE `tb_document_import_batch`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`knowledge_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`import_mode` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '导入模式',
`status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '批次状态',
`total_count` int NOT NULL DEFAULT 0 COMMENT '文件总数',
`total_bytes` bigint NOT NULL DEFAULT 0 COMMENT '文件总字节数',
`completed_count` int NOT NULL DEFAULT 0 COMMENT '完成数',
`processing_count` int NOT NULL DEFAULT 0 COMMENT '处理中数量',
`failed_count` int NOT NULL DEFAULT 0 COMMENT '失败数',
`pending_count` int NOT NULL DEFAULT 0 COMMENT '等待数',
`started_at` datetime NULL DEFAULT NULL COMMENT '开始时间',
`finished_at` datetime NULL DEFAULT NULL COMMENT '结束时间',
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
`created_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '创建人',
`modified` datetime NULL DEFAULT NULL COMMENT '修改时间',
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_document_import_batch_knowledge_status` (`knowledge_id`, `status`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库文档批量导入批次' ROW_FORMAT = DYNAMIC;
CREATE TABLE `tb_document_import_batch_item`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`batch_id` bigint UNSIGNED NOT NULL COMMENT '批次ID',
`knowledge_id` bigint UNSIGNED NOT NULL COMMENT '知识库ID',
`document_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '文档ID',
`client_file_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '客户端文件键',
`file_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件名',
`relative_path` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件夹相对路径',
`file_size` bigint NOT NULL DEFAULT 0 COMMENT '文件大小',
`file_path` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '存储路径',
`stage` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '当前阶段',
`status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '当前状态',
`error_summary` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '错误摘要',
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
`created_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '创建人',
`modified` datetime NULL DEFAULT NULL COMMENT '修改时间',
`modified_by` bigint UNSIGNED NULL DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_document_import_batch_item_key` (`batch_id`, `client_file_key`) USING BTREE,
INDEX `idx_document_import_batch_item_batch_status` (`batch_id`, `status`) USING BTREE,
INDEX `idx_document_import_batch_item_knowledge_key` (`knowledge_id`, `client_file_key`) USING BTREE,
INDEX `idx_document_import_batch_item_document` (`document_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库文档批量导入文件项' ROW_FORMAT = DYNAMIC;
ALTER TABLE `tb_document_import_task`
ADD COLUMN `batch_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '批次ID' AFTER `knowledge_id`,
ADD COLUMN `batch_item_id` bigint UNSIGNED NULL DEFAULT NULL COMMENT '批次文件项ID' AFTER `batch_id`,
ADD INDEX `idx_document_import_task_batch_phase_status` (`batch_id`, `phase`, `status`) USING BTREE,
ADD INDEX `idx_document_import_task_batch_item` (`batch_item_id`) USING BTREE;

View File

@@ -0,0 +1,42 @@
ALTER TABLE `tb_document_import_batch`
ADD COLUMN `uploaded_count` int NOT NULL DEFAULT 0 COMMENT '已上传数' AFTER `pending_count`,
ADD COLUMN `skipped_count` int NOT NULL DEFAULT 0 COMMENT '跳过数' AFTER `uploaded_count`,
ADD COLUMN `cancelled_count` int NOT NULL DEFAULT 0 COMMENT '取消数' AFTER `skipped_count`,
ADD COLUMN `retryable_failed_count` int NOT NULL DEFAULT 0 COMMENT '可重试失败数' AFTER `cancelled_count`;
ALTER TABLE `tb_document_import_batch_item`
ADD COLUMN `retryable` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否允许批量重试' AFTER `error_summary`,
ADD COLUMN `attempt_count` int NOT NULL DEFAULT 0 COMMENT '重试次数' AFTER `retryable`,
DROP INDEX `idx_document_import_batch_item_batch_status`,
ADD INDEX `idx_document_import_batch_item_batch_status` (`batch_id`, `status`, `modified`) USING BTREE;
ALTER TABLE `tb_document_import_task`
ADD INDEX `idx_document_import_task_phase_status_modified`
(`phase`, `status`, `modified`, `batch_id`, `created`) USING BTREE;
UPDATE `tb_document_import_batch` batch
SET batch.`uploaded_count` = (
SELECT COUNT(*)
FROM `tb_document_import_batch_item` item
WHERE item.`batch_id` = batch.`id`
AND item.`status` = 'UPLOADED'
),
batch.`skipped_count` = (
SELECT COUNT(*)
FROM `tb_document_import_batch_item` item
WHERE item.`batch_id` = batch.`id`
AND item.`status` = 'SKIPPED'
),
batch.`cancelled_count` = (
SELECT COUNT(*)
FROM `tb_document_import_batch_item` item
WHERE item.`batch_id` = batch.`id`
AND item.`status` = 'CANCELLED'
),
batch.`retryable_failed_count` = (
SELECT COUNT(*)
FROM `tb_document_import_batch_item` item
WHERE item.`batch_id` = batch.`id`
AND item.`status` = 'FAILED'
AND item.`retryable` = 1
);

View File

@@ -0,0 +1,5 @@
ALTER TABLE `tb_document_import_batch_item`
ADD COLUMN `replaced_document_id` bigint UNSIGNED NULL DEFAULT NULL
COMMENT '待覆盖的历史文档ID' AFTER `document_id`,
ADD INDEX `idx_document_import_batch_item_replacement`
(`replaced_document_id`, `status`, `modified`) USING BTREE;

View File

@@ -0,0 +1,15 @@
UPDATE `tb_document_import_batch_item`
SET `retryable` = 1
WHERE `status` = 'FAILED'
AND `stage` IN ('PARSE', 'SPLIT', 'INDEX')
AND `document_id` IS NOT NULL
AND `retryable` = 0;
UPDATE `tb_document_import_batch` batch
SET batch.`retryable_failed_count` = (
SELECT COUNT(*)
FROM `tb_document_import_batch_item` item
WHERE item.`batch_id` = batch.`id`
AND item.`status` = 'FAILED'
AND item.`retryable` = 1
);

View File

@@ -0,0 +1,191 @@
SET NAMES utf8mb4;
INSERT INTO `tb_sys_api_key_resource` (`id`, `request_interface`, `title`)
VALUES
(366700000000000101, '/public-api/knowledge-share/detail', '知识库读取'),
(366700000000000102, '/public-api/knowledge-share/search', '知识库读取'),
(366700000000000103, '/public-api/knowledge-share/document/page', '知识库读取'),
(366700000000000104, '/public-api/knowledge-share/document/download', '知识库读取'),
(366700000000000105, '/public-api/knowledge-share/documentChunk/page', '知识库读取'),
(366700000000000106, '/public-api/knowledge-share/faq/page', '知识库读取'),
(366700000000000107, '/public-api/knowledge-share/faq/detail', '知识库读取'),
(366700000000000108, '/public-api/knowledge-share/faq/exportExcel', '知识库读取'),
(366700000000000109, '/public-api/knowledge-share/document/import/batch', '知识导入'),
(366700000000000110, '/public-api/knowledge-share/document/import/batch/status', '知识导入'),
(366700000000000111, '/public-api/knowledge-share/document/import/batch/retry', '知识导入'),
(366700000000000112, '/public-api/knowledge-share/document/import/analyze', '知识导入'),
(366700000000000113, '/public-api/knowledge-share/document/import/preview', '知识导入'),
(366700000000000114, '/public-api/knowledge-share/document/import/commit', '知识导入'),
(366700000000000115, '/public-api/knowledge-share/document/import/task/create', '知识导入'),
(366700000000000116, '/public-api/knowledge-share/document/import/task/detail', '知识导入'),
(366700000000000117, '/public-api/knowledge-share/document/import/task/preview', '知识导入'),
(366700000000000118, '/public-api/knowledge-share/document/import/task/startIndex', '知识导入'),
(366700000000000119, '/public-api/knowledge-share/document/import/task/retryParse', '知识导入'),
(366700000000000120, '/public-api/knowledge-share/document/import/task/retryIndex', '知识导入'),
(366700000000000121, '/public-api/knowledge-share/faq/importExcel', '知识导入'),
(366700000000000122, '/public-api/knowledge-share/faq/downloadImportTemplate', '知识导入'),
(366700000000000123, '/public-api/knowledge-share/document/remove', '知识库维护'),
(366700000000000124, '/public-api/knowledge-share/documentChunk/update', '知识库维护'),
(366700000000000125, '/public-api/knowledge-share/documentChunk/remove', '知识库维护'),
(366700000000000126, '/public-api/knowledge-share/faq/save', '知识库维护'),
(366700000000000127, '/public-api/knowledge-share/faq/update', '知识库维护'),
(366700000000000128, '/public-api/knowledge-share/faq/remove', '知识库维护')
ON DUPLICATE KEY UPDATE `title` = VALUES(`title`);
SET @migrated_knowledge_api_key_count = (
SELECT COUNT(DISTINCT mapping.`api_key_id`)
FROM `tb_sys_api_key_resource_mapping` mapping
WHERE mapping.`resource_type` = 'KNOWLEDGE'
AND mapping.`resource_target_id` IS NULL
);
UPDATE `tb_sys_api_key_resource_mapping` mapping
JOIN `tb_sys_api_key_resource` resource
ON resource.`id` = mapping.`api_key_resource_id`
SET mapping.`action_scope` = CASE
WHEN resource.`request_interface` IN (
'/public-api/knowledge-share/detail',
'/public-api/knowledge-share/search',
'/public-api/knowledge-share/document/page',
'/public-api/knowledge-share/document/download',
'/public-api/knowledge-share/documentChunk/page',
'/public-api/knowledge-share/faq/page',
'/public-api/knowledge-share/faq/detail',
'/public-api/knowledge-share/faq/exportExcel'
) THEN 'KNOWLEDGE_READ'
WHEN resource.`request_interface` IN (
'/public-api/knowledge-share/document/import/analyze',
'/public-api/knowledge-share/document/import/preview',
'/public-api/knowledge-share/document/import/commit',
'/public-api/knowledge-share/document/import/task/create',
'/public-api/knowledge-share/document/import/task/detail',
'/public-api/knowledge-share/document/import/task/preview',
'/public-api/knowledge-share/document/import/task/startIndex',
'/public-api/knowledge-share/document/import/task/retryParse',
'/public-api/knowledge-share/document/import/task/retryIndex',
'/public-api/knowledge-share/faq/importExcel',
'/public-api/knowledge-share/faq/downloadImportTemplate'
) THEN 'KNOWLEDGE_IMPORT'
WHEN resource.`request_interface` IN (
'/public-api/knowledge-share/document/remove',
'/public-api/knowledge-share/documentChunk/update',
'/public-api/knowledge-share/documentChunk/remove',
'/public-api/knowledge-share/faq/save',
'/public-api/knowledge-share/faq/update',
'/public-api/knowledge-share/faq/remove'
) THEN 'KNOWLEDGE_MAINTENANCE'
ELSE mapping.`action_scope`
END
WHERE mapping.`resource_type` = 'KNOWLEDGE';
SET @revoked_maintenance_mapping_count = (
SELECT COUNT(*)
FROM `tb_sys_api_key_resource_mapping`
WHERE `resource_type` = 'KNOWLEDGE'
AND `resource_target_id` IS NULL
AND `action_scope` = 'KNOWLEDGE_MAINTENANCE'
);
DELETE FROM `tb_sys_api_key_resource_mapping`
WHERE `resource_type` = 'KNOWLEDGE'
AND `resource_target_id` IS NULL
AND `action_scope` = 'KNOWLEDGE_MAINTENANCE';
INSERT INTO `tb_sys_api_key_resource_mapping`
(`id`, `api_key_id`, `api_key_resource_id`, `resource_type`,
`resource_target_id`, `action_scope`)
SELECT
CAST(
366900000000000000
+ ROW_NUMBER() OVER (
ORDER BY token.`api_key_id`,
COALESCE(token.`resource_target_id`, 0),
resource.`id`
)
AS UNSIGNED
),
token.`api_key_id`,
resource.`id`,
'KNOWLEDGE',
token.`resource_target_id`,
'KNOWLEDGE_IMPORT'
FROM (
SELECT DISTINCT mapping.`api_key_id`, mapping.`resource_target_id`
FROM `tb_sys_api_key_resource_mapping` mapping
WHERE mapping.`resource_type` = 'KNOWLEDGE'
AND mapping.`action_scope` = 'KNOWLEDGE_IMPORT'
) token
JOIN `tb_sys_api_key_resource` resource
ON resource.`request_interface` IN (
'/public-api/knowledge-share/document/import/batch',
'/public-api/knowledge-share/document/import/batch/status',
'/public-api/knowledge-share/document/import/batch/retry'
)
LEFT JOIN `tb_sys_api_key_resource_mapping` existing
ON existing.`api_key_id` = token.`api_key_id`
AND existing.`api_key_resource_id` = resource.`id`
AND existing.`resource_type` = 'KNOWLEDGE'
AND existing.`resource_target_id` <=> token.`resource_target_id`
AND existing.`action_scope` = 'KNOWLEDGE_IMPORT'
WHERE existing.`id` IS NULL;
SELECT
@migrated_knowledge_api_key_count AS `migrated_knowledge_api_key_count`,
@revoked_maintenance_mapping_count AS `revoked_maintenance_mapping_count`;
ALTER TABLE `tb_document_import_batch`
ADD COLUMN `caller_type` varchar(16) NULL DEFAULT NULL
COMMENT '调用者类型' AFTER `knowledge_id`,
ADD COLUMN `caller_id` bigint UNSIGNED NULL DEFAULT NULL
COMMENT '调用者ID' AFTER `caller_type`,
ADD COLUMN `idempotency_key_hash` char(64) NULL DEFAULT NULL
COMMENT '提交幂等键SHA-256' AFTER `caller_id`,
ADD COLUMN `request_digest` char(64) NULL DEFAULT NULL
COMMENT '请求摘要SHA-256' AFTER `idempotency_key_hash`,
ADD COLUMN `duplicate_policy` varchar(16) NULL DEFAULT NULL
COMMENT '重复文件策略' AFTER `request_digest`,
ADD COLUMN `requested_strategy_json` text NULL
COMMENT '请求分块策略' AFTER `duplicate_policy`,
ADD COLUMN `retry_generation` int NOT NULL DEFAULT 0
COMMENT '重试代次' AFTER `requested_strategy_json`,
ADD COLUMN `last_retry_key_hash` char(64) NULL DEFAULT NULL
COMMENT '最近重试幂等键SHA-256' AFTER `retry_generation`,
ADD COLUMN `last_retry_generation` int NOT NULL DEFAULT 0
COMMENT '最近重试响应代次' AFTER `last_retry_key_hash`,
ADD COLUMN `version` int NOT NULL DEFAULT 0
COMMENT '乐观锁版本' AFTER `last_retry_generation`,
ADD UNIQUE INDEX `uk_document_import_batch_caller_idempotency`
(`caller_type`, `caller_id`, `idempotency_key_hash`) USING BTREE;
UPDATE `tb_document_import_batch`
SET `caller_type` = 'ADMIN',
`caller_id` = COALESCE(`created_by`, 0),
`duplicate_policy` = COALESCE(`duplicate_policy`, 'SKIP')
WHERE `caller_type` IS NULL;
ALTER TABLE `tb_document_import_batch_item`
ADD COLUMN `content_sha256` char(64) NULL DEFAULT NULL
COMMENT '文件内容SHA-256' AFTER `file_path`,
ADD COLUMN `failure_code` varchar(64) NULL DEFAULT NULL
COMMENT '稳定失败码' AFTER `error_summary`,
ADD COLUMN `applied_strategy_code` varchar(64) NULL DEFAULT NULL
COMMENT '实际分块策略编码' AFTER `failure_code`,
ADD COLUMN `strategy_snapshot_json` text NULL
COMMENT '分块策略快照' AFTER `applied_strategy_code`,
DROP INDEX `idx_document_import_batch_item_batch_status`,
ADD INDEX `idx_document_import_batch_item_batch_status`
(`batch_id`, `status`, `modified`, `id`) USING BTREE;
ALTER TABLE `tb_document_import_task`
ADD COLUMN `failure_code` varchar(64) NULL DEFAULT NULL
COMMENT '稳定失败码' AFTER `error_summary`,
ADD COLUMN `attempt_no` int NOT NULL DEFAULT 0
COMMENT '执行尝试次数' AFTER `failure_code`,
ADD COLUMN `execution_token` varchar(64) NULL DEFAULT NULL
COMMENT '执行令牌' AFTER `attempt_no`,
ADD COLUMN `lease_until` datetime NULL DEFAULT NULL
COMMENT '租约到期时间' AFTER `execution_token`,
ADD COLUMN `version` int NOT NULL DEFAULT 0
COMMENT '乐观锁版本' AFTER `lease_until`,
ADD INDEX `idx_document_import_task_phase_status_lease`
(`phase`, `status`, `lease_until`, `created`, `id`) USING BTREE;

View File

@@ -0,0 +1,15 @@
CREATE TABLE `tb_document_import_batch_retry_request`
(
`id` bigint UNSIGNED NOT NULL COMMENT '主键',
`batch_id` bigint UNSIGNED NOT NULL COMMENT '批次ID',
`retry_key_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL COMMENT '重试幂等键SHA-256',
`request_digest` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL COMMENT '重试请求摘要SHA-256',
`response_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '首次领取后的响应状态',
`retry_generation` int NOT NULL COMMENT '首次领取后的重试代次',
`created` datetime NULL DEFAULT NULL COMMENT '创建时间',
`modified` datetime NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_document_import_retry_batch_key` (`batch_id`, `retry_key_hash`) USING BTREE,
INDEX `idx_document_import_retry_batch_created` (`batch_id`, `created`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci
COMMENT = '知识库文档批量导入重试幂等请求' ROW_FORMAT = DYNAMIC;

View File

@@ -0,0 +1,7 @@
DROP TABLE IF EXISTS `tb_document_import_batch_retry_request`;
ALTER TABLE `tb_document_import_batch`
DROP COLUMN `last_retry_key_hash`,
DROP COLUMN `last_retry_generation`,
ADD INDEX `idx_document_import_batch_status_modified`
(`status`, `modified`, `id`) USING BTREE;

View File

@@ -0,0 +1,3 @@
ALTER TABLE `tb_document_import_batch_item`
ADD INDEX `idx_document_import_batch_item_cleanup`
(`stage`, `status`, `modified`, `id`) USING BTREE;

View File

@@ -0,0 +1,16 @@
ALTER TABLE `tb_document_import_batch_item`
ADD COLUMN `storage_locator` varchar(2048) NULL DEFAULT NULL
COMMENT '可恢复存储定位符' AFTER `file_path`,
ADD COLUMN `cleanup_pending` tinyint(1) NOT NULL DEFAULT 0
COMMENT '是否等待清理存储对象' AFTER `storage_locator`;
UPDATE `tb_document_import_batch_item`
SET `cleanup_pending` = 1
WHERE `stage` = 'UPLOAD'
AND `status` IN ('UPLOADING', 'CANCELLED')
AND `file_path` IS NOT NULL;
ALTER TABLE `tb_document_import_batch_item`
DROP INDEX `idx_document_import_batch_item_cleanup`,
ADD INDEX `idx_document_import_batch_item_cleanup_pending`
(`cleanup_pending`, `modified`, `id`) USING BTREE;