零门槛搭建信托数字档案馆系统全流程实录

技术架构选型与环境说明

信托业务涉及大量非结构化数据,如合同扫描件、法律意见书、尽职调查报告等。为了实现这些档案的高效存储与全文检索,本指南采用轻量级且高可用的技术栈:MinIO负责对象存储,Elasticsearch负责全文检索,Python FastAPI作为业务网关。这种组合无需依赖昂贵的商业数据库,且在Linux环境下即可一键部署。以下操作均在CentOS 7.9环境下验证通过,假设你已拥有root权限。

第一步:基于Docker Compose编排底层服务

为了避免繁琐的手动安装依赖,我们使用Docker Compose一次性启动MinIO和Elasticsearch。请确保服务器已安装Docker和Docker Compose。创建目录/data/trust_archive,并在该目录下新建docker-compose.yml文件,直接复制以下内容:

docker-compose.yml 完整配置:

```yaml version: '3.8' services: 对象存储服务 minio: image: minio/minio:latest container_name: trust_minio ports: - "9000:9000" - "9001:9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin123 command: server /data --console-address ":9001" volumes: - ./minio_data:/data 搜索引擎服务 elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0 container_name: trust_es ports: - "9200:9200" environment: - discovery.type=single-node - xpack.security.enabled=false - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - ./es_data:/usr/share/elasticsearch/data ```

保存文件后,执行docker-compose up -d。等待约30秒,执行docker ps确认两个容器均处于Up状态。此时,MinIO控制台访问地址为http://服务器IP:9001,Elasticsearch接口地址为http://服务器IP:9200

第二步:初始化存储桶与索引结构

服务启动后,必须预先创建资源。我们需要在MinIO中创建一个专门存储信托档案的Bucket,并在Elasticsearch中建立索引以支持中文分词检索。

执行以下命令创建名为trust-docs的存储桶:

```bash curl http://服务器IP:9000/trust-docs/ -X PUT \ --user minioadmin:minioadmin123 ```

接着,配置Elasticsearch索引。信托档案检索通常需要精准匹配合同编号,同时对全文进行模糊搜索。执行以下命令创建索引trust_index

```bash curl -X PUT "http://服务器IP:9200/trust_index?pretty" -H 'Content-Type: application/json' -d' { "settings": { "analysis": { "analyzer": { "ik_smart_analyzer": { "type": "custom", "tokenizer": "ik_smart" } } } }, "mappings": { "properties": { "file_name": { "type": "keyword" }, "contract_id": { "type": "keyword" }, "project_name": { "type": "text", "analyzer": "ik_smart_analyzer" }, "content": { "type": "text", "analyzer": "ik_smart_analyzer" }, "upload_time": { "type": "date" }, "file_path": { "type": "keyword" } } } }' ```

注意:上述配置使用了ik_smart分词器,这是处理中文信托合同文本的标准配置。如果Elasticsearch报错提示缺少IK分词插件,请进入ES容器执行elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.11.0/elasticsearch-analysis-ik-8.11.0.zip并重启容器。

第三步:开发核心业务逻辑代码

现在开始编写核心系统代码。我们需要实现文件上传、文本提取、元数据入库及检索接口。在/data/trust_archive目录下创建app.py。首先安装必要的Python依赖库:

```bash pip install fastapi uvicorn minio elasticsearch pypdf python-multipart ```

零门槛搭建信托数字档案馆系统全流程实录

以下是完整的app.py代码,包含了所有必要的逻辑,无需任何修改即可运行:

```python import os import uuid from datetime import datetime from fastapi import FastAPI, UploadFile, Form, HTTPException from minio import Minio from elasticsearch import Elasticsearch from pypdf import PdfReader app = FastAPI() 初始化MinIO客户端 minio_client = Minio( "服务器IP:9000", access_key="minioadmin", secret_key="minioadmin123", secure=False ) 初始化Elasticsearch客户端 es_client = Elasticsearch("http://服务器IP:9200") BUCKET_NAME = "trust-docs" def extract_text_from_pdf(file_path: str) -> str: """本地提取PDF文本用于检索""" try: reader = PdfReader(file_path) text = "" for page in reader.pages: text += page.extract_text() + "\n" return text[:5000] 限制入库文本长度,避免过大 except Exception as e: print(f"PDF解析失败: {e}") return "" @app.post("/upload") async def upload_archive( file: UploadFile, contract_id: str = Form(...), project_name: str = Form(...) ): 1. 生成唯一文件名 file_ext = file.filename.split(".")[-1] unique_name = f"{uuid.uuid4().hex}.{file_ext}" object_name = f"{datetime.now().strftime('%Y%m%d')}/{unique_name}" 2. 上传文件到MinIO try: 先将上传的流保存到本地临时文件以便解析文本 temp_path = f"/tmp/{unique_name}" with open(temp_path, "wb") as buffer: buffer.write(await file.read()) minio_client.fput_object(BUCKET_NAME, object_name, temp_path) except Exception as e: raise HTTPException(status_code=500, detail=f"存储上传失败: {str(e)}") 3. 提取文本并写入ES content_text = extract_text_from_pdf(temp_path) doc_body = { "file_name": file.filename, "contract_id": contract_id, "project_name": project_name, "content": content_text, "upload_time": datetime.now(), "file_path": object_name } try: es_client.index(index="trust_index", document=doc_body) except Exception as e: 如果ES写入失败,建议删除已上传文件或记录日志,此处简化处理 raise HTTPException(status_code=500, detail=f"索引写入失败: {str(e)}") finally: if os.path.exists(temp_path): os.remove(temp_path) return {"code": 200, "msg": "档案归档成功", "file_id": unique_name} @app.get("/search") async def search_archive(keyword: str): """基于关键词检索档案""" query = { "query": { "multi_match": { "query": keyword, "fields": ["project_name", "content", "contract_id"] } } } try: resp = es_client.search(index="trust_index", body=query) results = [] for hit in resp['hits']['hits']: source = hit['_source'] results.append({ "project_name": source.get("project_name"), "contract_id": source.get("contract_id"), "file_name": source.get("file_name"), "highlight": source.get("content", "")[:100] + "..." }) return {"code": 200, "data": results} except Exception as e: raise HTTPException(status_code=500, detail=f"检索服务异常: {str(e)}") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) ```

代码逻辑解析:上传接口首先将文件存入MinIO的特定日期目录下,确保文件不重名。随后利用pypdf库在本地临时解析PDF内容,截取前5000字符。最后将元数据(合同号、项目名)和文本内容合并存入Elasticsearch。检索接口使用multi_match同时查询项目名、合同号和正文内容。

第四步:系统启动与功能验证

代码编写完成后,启动API服务:

```bash python3 app.py ```

服务默认运行在8000端口。我们使用curl命令模拟前端进行一次完整的归档和检索流程。

1. 模拟上传一份信托合同:

准备一个测试用的PDF文件test_contract.pdf,内容包含“集合资金信托计划”。执行:

```bash curl -X POST "http://服务器IP:8000/upload" \ -F "file=@test_contract.pdf" \ -F "contract_id=XT20231001" \ -F "project_name=某基建集合资金信托计划" ```

如果返回{"code": 200, "msg": "档案归档成功"...},说明文件已成功存入MinIO且索引已建立。

2. 验证全文检索功能:

执行搜索命令,查找关键词“基建”:

```bash curl "http://服务器IP:8000/search?keyword=基建" ```

系统应返回JSON格式的结果,包含刚才上传的项目名称、合同号以及内容预览。如果检索“XT20231001”,也应能精准定位到该文档,证明了元数据索引的有效性。

AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统