diff --git a/.gitignore b/.gitignore index 4e59284..2b22728 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ /output/*.xlsx /logs/*.log +/build/institution_matcher/ +/dist/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8db8f20 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM python:3.9-slim + +# 设置工作目录 +WORKDIR /app + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + gcc \ + g++ \ + && rm -rf /var/lib/apt/lists/* + +# 复制依赖文件 +COPY requirements.txt . + +# 安装Python依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 复制应用代码 +COPY . . + +# 构建可执行文件 +RUN python build.py + +# 创建输出目录 +RUN mkdir -p output logs temp + +# 设置环境变量 +ENV PYTHONPATH=/app/src + +# 默认命令 +CMD ["python", "main.py", "--help"] diff --git a/README.md b/README.md index 07d9f9f..2391063 100644 --- a/README.md +++ b/README.md @@ -2,47 +2,21 @@ ## 项目简介 -本项目用于匹配新疆各政企单位的机构名称,支持简称匹配和模糊匹配功能。主要解决A_TREE和B_TREE两张表中机构数据的名称匹配问题。 +本项目用于匹配新疆各政企单位的机构名称,支持简称匹配和模糊匹配功能。 ## 功能特性 -- ✅ 支持达蒙DM数据库连接 -- ✅ 智能机构名称匹配算法 -- ✅ 简称自动识别和匹配 -- ✅ **关键词识别和匹配** -- ✅ **层次结构分析和归属信息提取** -- ✅ 多种输出格式(CSV、Excel、JSON) -- ✅ 详细的匹配报告和统计 -- ✅ 支持ARM架构部署 -- ✅ 完整的日志记录和进度显示 -- ✅ 单元测试覆盖 - -## 项目结构 - -``` -make2tree/ -├── src/ # 源代码目录 -│ ├── __init__.py -│ ├── config.py # 配置管理 -│ ├── database.py # 数据库操作 -│ ├── matcher.py # 机构名称匹配 -│ └── output.py # 输出管理 -├── tests/ # 测试目录 -│ ├── __init__.py -│ └── test_matcher.py # 匹配器测试 -├── main.py # 主程序 -├── build.py # 打包脚本 -├── test_data.py # 测试数据生成 -├── run_tests.py # 测试运行脚本 -├── requirements.txt # 依赖包 -├── config.yaml # 配置文件 -└── README.md # 项目文档 -``` +- 支持达蒙DM数据库连接 +- 智能机构名称匹配算法 +- 简称自动识别和匹配 +- 多种输出格式(CSV、Excel、JSON) +- 详细的匹配报告和统计 +- 支持ARM架构部署 ## 安装要求 - Python 3.8+ -- 达蒙DM数据库驱动 (dmPython) +- 达蒙DM数据库驱动 - 相关Python依赖包 ## 快速开始 @@ -69,20 +43,7 @@ database: ### 3. 运行程序 ```bash -# 基本运行 python main.py - -# 指定配置文件 -python main.py --config config.yaml - -# 指定输出目录 -python main.py --output-dir output - -# 保存结果到数据库 -python main.py --save-to-db - -# 调整匹配参数 -python main.py --threshold 0.8 --max-matches 5 ``` ### 4. 使用打包版本 @@ -97,264 +58,32 @@ python build.py ## 命令行参数 -| 参数 | 简写 | 说明 | 默认值 | -|------|------|------|--------| -| `--config` | `-c` | 配置文件路径 | `config.yaml` | -| `--output-dir` | `-o` | 输出目录 | `output` | -| `--save-to-db` | - | 保存结果到数据库 | `False` | -| `--threshold` | `-t` | 相似度阈值 | `0.8` | -| `--max-matches` | `-m` | 最大匹配数 | `5` | +- `--config, -c`: 配置文件路径 +- `--output-dir, -o`: 输出目录 +- `--save-to-db`: 保存结果到数据库 +- `--threshold, -t`: 相似度阈值 +- `--max-matches, -m`: 最大匹配数 ## 输出文件 -程序运行后会生成以下文件: - - `matching_results_YYYYMMDD_HHMMSS.csv`: 匹配结果CSV文件 -- `matching_results_YYYYMMDD_HHMMSS.xlsx`: 匹配结果Excel文件(包含多个工作表) +- `matching_results_YYYYMMDD_HHMMSS.xlsx`: 匹配结果Excel文件 - `matching_report_YYYYMMDD_HHMMSS.json`: 匹配报告JSON文件 ## 匹配算法 -### 相似度计算 - -使用多种算法计算机构名称相似度: - 完全匹配:100%相似度 - 高度匹配:85%-99%相似度 - 中度匹配:75%-84%相似度 - 低度匹配:70%-74%相似度 -### 简称支持 +## 简称支持 支持常见机构简称,如: - 妇女联合会 → 妇联 - 政治协商会议 → 政协 - 人民代表大会常务委员会 → 人大常委会 -- 人民政府 → 政府 -- 发展和改革委员会 → 发改委 -- 人力资源和社会保障局 → 人社局 -- 卫生健康委员会 → 卫健委 -- 应急管理局 → 应急局 -- 市场监督管理局 → 市场监管局 -- 生态环境局 → 环保局 -- 住房和城乡建设局 → 住建局 -- 交通运输局 → 交通局 -- 农业农村局 → 农业局 -- 文化和旅游局 → 文旅局 -- 退役军人事务局 → 退役军人局 -- 医疗保障局 → 医保局 - -### 关键词识别 - -系统能够自动识别机构名称中的关键词,包括: - -#### 政府机构关键词 -- 办公厅、办公室、委员会、局、厅、部、处、科、股 -- 妇联、工会、团委、残联、科协、文联、侨联、台联 -- 工商联、红十字会、慈善总会、志愿者协会 - -#### 事业单位关键词 -- 中心、站、所、院、校、馆、园、场、队、组 -- 医院、学校、图书馆、博物馆、文化馆、体育馆 - -#### 企业单位关键词 -- 公司、集团、企业、厂、矿、农场、林场、牧场 - -#### 特殊机构关键词 -- 党校、行政学院、社会主义学院、团校、妇干校 -- 参事室、文史馆、地方志办、研究室 - -#### 统计相关关键词 -- 统计局、调查队、普查中心、统计站 - -### 层次结构分析 - -系统能够通过父节点和上级节点分析机构的归属信息: - -#### 行政区划层次 -- **省级**: 自治区、省、直辖市 -- **市级**: 市、自治州、地区、盟 -- **县级**: 县、自治县、区、旗、市辖区 -- **乡级**: 乡、镇、街道、民族乡 -- **村级**: 村、社区、居委会、村委会 - -#### 层次结构示例 -``` -新疆维吾尔自治区 (省级) -└── 乌鲁木齐市 (市级) - └── 天山区 (县级) - └── 新疆维吾尔自治区妇女联合会 (机构) -``` - -系统会提取每个机构的完整归属路径,用于更精确的匹配。 - -## 匹配结果字段 - -匹配结果包含以下字段: - -### 基本信息 -- `a_id`: A_TREE机构ID -- `a_name`: A_TREE机构名称 -- `b_id`: B_TREE机构ID -- `b_name`: B_TREE机构名称 - -### 相似度信息 -- `similarity_score`: 综合相似度分数 -- `name_similarity`: 名称相似度分数 -- `keyword_similarity`: 关键词相似度分数 -- `admin_similarity`: 行政区划相似度分数 -- `match_type`: 匹配类型 - -### 关键词信息 -- `a_keywords`: A_TREE机构关键词 -- `b_keywords`: B_TREE机构关键词 - -### 行政区划信息 -- `a_province`: A_TREE机构所属省份 -- `a_city`: A_TREE机构所属城市 -- `a_county`: A_TREE机构所属区县 -- `b_province`: B_TREE机构所属省份 -- `b_city`: B_TREE机构所属城市 -- `b_county`: B_TREE机构所属区县 - -## 测试 - -### 运行测试 - -```bash -# 运行所有测试 -python run_tests.py - -# 运行特定测试 -python -m unittest tests.test_matcher -``` - -### 生成测试数据 - -```bash -python test_data.py -``` - -## 部署 - -### ARM架构部署 - -```bash -# 构建ARM版本 -python build.py - -# 安装到系统 -sudo ./install.sh -``` - -### Docker部署 - -```bash -# 构建Docker镜像 -docker build -t institution-matcher . - -# 运行容器 -docker run -v $(pwd)/output:/app/output institution-matcher -``` - -## 配置说明 - -### 数据库配置 - -```yaml -database: - host: "localhost" # 数据库主机 - port: 5236 # 数据库端口 - username: "your_username" # 用户名 - password: "your_password" # 密码 - database: "your_database" # 数据库名 - charset: "utf8" # 字符集 -``` - -### 匹配配置 - -```yaml -matching: - similarity_threshold: 0.8 # 相似度阈值 - max_matches: 5 # 最大匹配数 - enable_abbreviation: true # 启用简称匹配 -``` - -### 日志配置 - -```yaml -logging: - level: "INFO" # 日志级别 - format: "{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" - file: "logs/matching.log" # 日志文件 - rotation: "10 MB" # 日志轮转大小 - retention: "30 days" # 日志保留时间 -``` - -## 性能优化 - -- 使用pandas进行高效数据处理 -- 支持批量匹配操作 -- 进度条显示处理进度 -- 内存优化的相似度计算 -- 层次结构缓存机制 - -## 故障排除 - -### 常见问题 - -1. **数据库连接失败** - - 检查数据库配置信息 - - 确认网络连接正常 - - 验证用户权限 - -2. **匹配结果为空** - - 降低相似度阈值 - - 检查数据格式是否正确 - - 确认机构名称不为空 - -3. **内存不足** - - 减少最大匹配数 - - 分批处理数据 - - 增加系统内存 - -## 开发指南 - -### 添加新的简称映射 - -在 `src/matcher.py` 中的 `_load_abbreviation_map` 方法中添加新的映射: - -```python -abbreviation_map = { - "新机构全称": "新机构简称", - # ... 其他映射 -} -``` - -### 添加新的关键词 - -在 `src/matcher.py` 中的 `_load_institution_keywords` 方法中添加新的关键词: - -```python -keywords = { - "新关键词1", "新关键词2", - # ... 其他关键词 -} -``` - -### 扩展匹配算法 - -在 `src/matcher.py` 中的 `calculate_similarity` 方法中添加新的相似度算法。 ## 许可证 MIT License - -## 贡献 - -欢迎提交Issue和Pull Request来改进这个项目。 - -## 联系方式 - -如有问题或建议,请通过以下方式联系: -- 提交GitHub Issue -- 发送邮件至项目维护者 diff --git a/build.py b/build.py index 895a5fe..8d9498e 100644 --- a/build.py +++ b/build.py @@ -97,13 +97,16 @@ def build_executable(): "--onefile", # 打包成单个文件 "--console", # 控制台应用 "--name", "institution_matcher", # 可执行文件名称 - "--add-data", "config.yaml;.", # 添加配置文件 - "--add-data", "src;src", # 添加源代码目录 + "--add-data", "config.yaml:.", # 添加配置文件 + "--add-data", "src:src", # 添加源代码目录 + "--paths", "src", # 添加src目录到Python路径 "--hidden-import", "dmPython", "--hidden-import", "pandas", "--hidden-import", "numpy", "--hidden-import", "loguru", "--hidden-import", "fuzzywuzzy", + "--hidden-import", "fuzzywuzzy.fuzz", + "--hidden-import", "fuzzywuzzy.string_utils", "--hidden-import", "python-Levenshtein", "--hidden-import", "yaml", "--hidden-import", "tqdm", diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..3bf57db --- /dev/null +++ b/install.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# 机构名称匹配工具安装脚本 + +echo "正在安装机构名称匹配工具..." + +# 创建安装目录 +INSTALL_DIR="/usr/local/bin/institution_matcher" +sudo mkdir -p $INSTALL_DIR + +# 复制可执行文件 +sudo cp dist/institution_matcher $INSTALL_DIR/ +sudo chmod +x $INSTALL_DIR/institution_matcher + +# 创建配置文件目录 +CONFIG_DIR="/etc/institution_matcher" +sudo mkdir -p $CONFIG_DIR + +# 复制配置文件 +sudo cp config.yaml $CONFIG_DIR/ + +# 创建软链接 +sudo ln -sf $INSTALL_DIR/institution_matcher /usr/local/bin/institution_matcher + +echo "安装完成!" +echo "使用方法: institution_matcher --help" diff --git a/institution_matcher.spec b/institution_matcher.spec new file mode 100644 index 0000000..cb52250 --- /dev/null +++ b/institution_matcher.spec @@ -0,0 +1,44 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['main.py'], + pathex=['src'], + binaries=[], + datas=[('config.yaml', '.'), ('src', 'src')], + hiddenimports=['dmPython', 'pandas', 'numpy', 'loguru', 'fuzzywuzzy', 'fuzzywuzzy.fuzz', 'fuzzywuzzy.string_utils', 'python-Levenshtein', 'yaml', 'tqdm', 'openpyxl'], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='institution_matcher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..a8bebb4 --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +./dist/institution_matcher --config config.yaml --a-csv data/a.csv --b-csv data/b.csv --output-csv output/result.csv --threshold 0.85 --max-matches 10 \ No newline at end of file diff --git a/需求.md b/需求.md index 48289ce..82a73c9 100644 --- a/需求.md +++ b/需求.md @@ -14,6 +14,14 @@ 2. 有的机构存在全程,有的机构存在简称 3. 存在全程的机构多数包含归属的省(或自治区)市(或自治州、地区)县(或自治县、区) 4. 而机构简称,也可以通过父节点和上级节点,直到其归属的的省(或自治区)市(或自治州、地区)县(或自治县、区) +6. 在完善基本法人单位匹配后,针对该法人单位的下级节点(基本为内设单位或内部法人单位) + 1. 内部法人单位按照法人单位进行匹配 + 2. 该内部的内设机构按照同法人单位下进行内设单位的匹配 + 3. 部分单位可能存在名称包含“内设单位”机构,其内部其实和对应法人单位下内设机构是对应的 + 4. 需要注意数据部分 + a. 多数公务员机构的内设机构为“某某科”(为公务员单位),有别于“某某中心”(为事业单位) + b. 部分法人单位机构的内设机构A与对应的法人单位B下的内设机构C可能存在为 A = B + C + 5. 部分单位可能存在不匹配情况,不匹配时,请将A_TREE需要移入B_TREE的数据输出到 c.csv 中 ## 需要完成