Should I Segment Big PDF Before Document Analysis#
Keywords: AWS, Amazon, Textract
Overview#
在使用 Textract 的 Document Analysis 功能时, 如果输入的 PDF 的页数很多, 这时候我们会面临两种选择:
将整个 PDF 作为一个整体发给 Textract.
将 PDF 分拆成单页 PDF, 然后依次发给 Textract.
这是因为根据 Set Quotas, Textract 有单个 PDF 不能超过 500 MB / 3000 页 的限制. 根据 Default Quotas, 默认情况下最多支持 5 个并发的 Async Document Analysis Job. 而根据 Pricing Textract 是按照 Page 收费 (跟运行时长无关). 所以我们需要合理利用 Quota 和 API, 使得总处理速度最快.
下面我们通过一个实验来测试到底应该用哪个方法.
Experiment#
请阅读下列测试代码. 我们用的是一个 6 页的 W2 税表文件做测试. 分别是一次性提交, 和分拆成 6 页依次提交. 请阅读代码中的结论部分.
test_should_i_segment_big_pdf_before_document_analysis.py
1# -*- coding: utf-8 -*-
2
3"""
4Conclusion:
5
61. 对于同一个文件 Textract 处理的速度在不同时间可能不同. 这可能是因为异步 API 涉及到 AWS 服务端的调度, 导致不同时间的处理速度不同.
72. 对于同一个文件, 一次性处理比分页后依次处理要快. 但是你要确保一次性处理的文件的大小不要太大.
83. 你可以将同一个文件分拆成小文件, 然后并行调用 API 进行处理.
9"""
10
11from datetime import datetime
12from pathlib_mate import Path
13from s3pathlib import S3Path, context
14from boto_session_manager import BotoSesManager
15import aws_textract.api as aws_textract
16
17dir_here = Path.dir_here(__file__)
18path_fw2 = dir_here / "fw2.pdf"
19path_page_list = [dir_here / f"fw2-{i}.pdf" for i in range(1, 6 + 1)]
20
21bsm = BotoSesManager(profile_name="bmt_app_dev_us_east_1")
22context.attach_boto_session(bsm.boto_ses)
23s3dir_root = S3Path(
24 f"s3://{bsm.aws_account_alias}-{bsm.aws_region}-data/projects/tmp/"
25).to_dir()
26s3dir_input = s3dir_root.joinpath("input").to_dir()
27s3dir_output = s3dir_root.joinpath("output").to_dir()
28s3dir_root.delete()
29
30
31def try_one_file():
32 print(f"working on {path_fw2.basename} ...")
33 s3path = s3dir_root.joinpath(path_fw2.basename)
34 s3path.write_bytes(path_fw2.read_bytes())
35 document_location, output_config = (
36 aws_textract.better_boto.preprocess_input_output_config(
37 input_bucket=s3path.bucket,
38 input_key=s3path.key,
39 input_version=None,
40 output_bucket=s3dir_output.bucket,
41 output_prefix=s3dir_output.key,
42 )
43 )
44 start_time = datetime.now()
45 res = bsm.textract_client.start_document_analysis(
46 DocumentLocation=document_location,
47 FeatureTypes=["FORMS"],
48 OutputConfig=output_config,
49 )
50 job_id = res["JobId"]
51 aws_textract.better_boto.wait_document_analysis_job_to_succeed(
52 textract_client=bsm.textract_client,
53 job_id=job_id,
54 delays=1,
55 timeout=300,
56 )
57 print("")
58 end_time = datetime.now()
59 elapsed = (end_time - start_time).total_seconds()
60 print(f"One file elapsed: {elapsed:.6f}")
61
62
63def try_many_file():
64 for path in path_page_list:
65 s3path = s3dir_root.joinpath(path.basename)
66 s3path.write_bytes(path.read_bytes())
67
68 start_time = datetime.now()
69 for path in path_page_list:
70 print(f"working on {path.basename} ...")
71 s3path = s3dir_root.joinpath(path.basename)
72 document_location, output_config = (
73 aws_textract.better_boto.preprocess_input_output_config(
74 input_bucket=s3path.bucket,
75 input_key=s3path.key,
76 input_version=None,
77 output_bucket=s3dir_output.bucket,
78 output_prefix=s3dir_output.key,
79 )
80 )
81 res = bsm.textract_client.start_document_analysis(
82 DocumentLocation=document_location,
83 FeatureTypes=["FORMS"],
84 OutputConfig=output_config,
85 )
86 job_id = res["JobId"]
87 aws_textract.better_boto.wait_document_analysis_job_to_succeed(
88 textract_client=bsm.textract_client,
89 job_id=job_id,
90 delays=1,
91 timeout=300,
92 )
93 print("")
94
95 end_time = datetime.now()
96 elapsed = (end_time - start_time).total_seconds()
97 print(f"Many file elapsed: {elapsed:.6f}")
98
99
100if __name__ == "__main__":
101 try_one_file()
102 try_many_file()
103 pass