Oracle 19c中如何找出未被Oracle Text索引的文档
环境:Oracle 19c
我们的系统使用Oracle Text(Oracle 19c)对存储为BFILE的PDF文件建立索引。此前通过Adobe Acrobat对PDF进行OCR预处理,但约一年前发现OCR偶尔会将页面旋转90或180度,这是可复现的Adobe Bug。因此告知客户需自行OCR后再上传,并停用了自身的OCR流程。
目前正调整OCR处理流程,需要找出所有在Oracle Text索引中无任何Token(词汇)的文档以重新处理,推测这些文档可能未被客户OCR,无法通过Oracle Text检索。
问题
- 如何查询Oracle Text找出无索引Token的文档?
- 是否有方法检测PDF文档是否已被OCR?
示例表脚本
CREATE TABLE MY_SCHEMA.ORADOCS ( DOC_ID NUMBER NOT NULL GENERATED BY DEFAULT ON NULL AS IDENTITY, SUBJECT_OR_TITLE VARCHAR2(255 BYTE) NOT NULL, DOC_DT DATE NOT NULL, AUTHOR VARCHAR2(255 BYTE), CREATE_DT DATE DEFAULT sysdate NOT NULL, CREATE_USER VARCHAR2(100 BYTE) DEFAULT USER NOT NULL, ORIG_FILENAME VARCHAR2(255 BYTE), ORADOC_FILE BFILE ) TABLESPACE MY_DOC; ALTER TABLE MY_SCHEMA.ORADOCS ADD ( CONSTRAINT ORADOCS_PK1 PRIMARY KEY (DOC_ID) USING INDEX MY_SCHEMA.ORADOCS_PK1 ENABLE VALIDATE); CREATE INDEX MY_SCHEMA.AUTHOR_ORADOCS ON MY_SCHEMA.ORADOCS (AUTHOR) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS('storage meta_storage memory 4G SYNC(ON COMMIT)'); CREATE INDEX MY_SCHEMA.ORADOC_FILE ON MY_SCHEMA.ORADOCS (ORADOC_FILE) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS('storage meta_storage memory 6G SYNC(ON COMMIT)'); CREATE INDEX MY_SCHEMA.SUBJECT_ORADOCS ON MY_SCHEMA.ORADOCS (SUBJECT_OR_TITLE) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS('storage meta_storage memory 4G SYNC(ON COMMIT)');
解决方案
问题1:找出Oracle Text索引中无Token的文档
以下两种方法可直接查询无索引Token的文档:
方法1:通过系统视图对比
利用CTX_USER_DOCUMENTS视图获取已生成索引Token的文档ID,再与原表左连接筛选出无匹配的记录:
SELECT d.DOC_ID, d.ORIG_FILENAME FROM MY_SCHEMA.ORADOCS d LEFT JOIN ( SELECT DOCID FROM CTX_USER_DOCUMENTS WHERE INDEX_NAME = 'ORADOC_FILE' -- 指定BFILE字段对应的索引名 ) idx ON d.DOC_ID = idx.DOCID WHERE idx.DOCID IS NULL;
注:需确保索引创建时未指定自定义DOCID参数,否则CTX_USER_DOCUMENTS中的DOCID可能与表主键不匹配。
方法2:用CTX_DOC包验证单文档
若需逐个验证文档是否存在Token,可调用CTX_DOC.TOKEN_TYPE函数统计Token数量:
DECLARE v_token_count NUMBER; BEGIN SELECT COUNT(*) INTO v_token_count FROM TABLE(CTX_DOC.TOKEN_TYPE('MY_SCHEMA.ORADOC_FILE', :input_doc_id)); IF v_token_count = 0 THEN DBMS_OUTPUT.PUT_LINE('文档' || :input_doc_id || '无有效索引Token'); END IF; END; /
问题2:检测PDF是否已被OCR
可通过Oracle内部逻辑或外部工具两种方式检测:
方式1:Oracle内部读取PDF属性
经过OCR的PDF会包含可提取的文本流,读取BFILE的前部分内容,检查是否存在PDF文本相关标记:
DECLARE v_target_file BFILE; v_content_buffer VARCHAR2(32767); v_has_text BOOLEAN := FALSE; BEGIN SELECT ORADOC_FILE INTO v_target_file FROM MY_SCHEMA.ORADOCS WHERE DOC_ID = :input_doc_id; DBMS_LOB.OPEN(v_target_file, DBMS_LOB.LOB_READONLY); DBMS_LOB.READ(v_target_file, 32767, 1, v_content_buffer); -- 检查PDF文本相关对象标记 IF INSTR(v_content_buffer, '/Contents') > 0 OR INSTR(v_content_buffer, '/Font') > 0 THEN v_has_text := TRUE; END IF; DBMS_LOB.CLOSE(v_target_file); IF v_has_text THEN DBMS_OUTPUT.PUT_LINE('该PDF包含可提取文本,大概率已完成OCR'); ELSE DBMS_OUTPUT.PUT_LINE('该PDF无文本内容,未经过OCR'); END IF; END; /
注:部分扫描件PDF可能包含少量元数据文本,需结合实际场景调整判断逻辑。
方式2:外部工具提取验证
在服务器安装poppler-utils工具包,使用pdftotext提取PDF文本,通过判断提取内容的长度来确认:
pdftotext target_file.pdf - | wc -c
若输出为0或极小值(仅包含元数据),则文档未经过OCR处理。
内容的提问来源于stack exchange,提问作者Richard Anderson
相关产品推荐
相关产品推荐

