基于Python与SQL Server的分层规则分类存储及实现方案咨询
分层规则分类方案设计
一、SQL Server 2018 规则存储优化方案
直接放弃单字段存整段JSON的方案,改用关联表结构存储,兼顾可管理性、可读性和层级支持:
- 表1:规则层级主表,存储规则的层级关系、优先级、基础信息
字段名 类型 说明 rule_idINT 主键自增 规则唯一标识 parent_rule_idINT 父规则ID,根层级规则填0,支持无限层级 priorityINT 同层级匹配优先级,数值越小越先被匹配 rule_nameVARCHAR(100) 规则名称,方便业务人员识别 rule_descVARCHAR(500) 规则逻辑的自然语言描述,解决可读性问题 is_activeBIT 规则生效状态,可直接用SQL筛选生效规则 - 表2:规则原子表达式表,存储最小规则单元
字段名 类型 说明 expr_idINT 主键自增 表达式唯一标识 rule_idINT 外键 关联所属规则的ID fieldVARCHAR(50) 待匹配的员工属性名,如 position、remaining_annual_leaveoperatorVARCHAR(20) 运算符,支持 ==、>=、contains、regexMatch等所有你需要的类型valueVARCHAR(200) 匹配值,不同类型统一转字符串存储,Python侧匹配前做类型转换 logic_relVARCHAR(10) 和同规则下其他表达式的逻辑关系,可选 and/or/not,单表达式留空group_idINT 可选,复杂布尔组合时用,同组表达式先运算再和其他组做逻辑拼接
该方案的优势:
- 完全支持层级结构,可通过递归SQL直接拉取完整规则树,按
priority排序保证匹配顺序 - 可读性极强,无需解析JSON,直接查表就能看到所有规则的逻辑,也可直接通过SQL做规则的增删改查
- 支持部分规则更新,无需修改整段JSON,减少出错概率
二、Python侧高效匹配方案
核心优化点
- 规则预编译:服务启动时一次性拉取所有生效规则,按层级+优先级拼接成可执行的规则对象,存在内存中,避免每次匹配重复解析
- 数据预处理:将所有员工数据(字典/数据类)统一转成带类型校验的结构,提前把字符串转日期、enum转对应值,避免匹配时重复做类型转换
- 短路匹配:按优先级从高到低匹配,员工命中第一个规则后直接返回结果,不做后续冗余校验
- 批量加速:数据量大于10万条时,用向量化运算替代逐行校验,性能提升10倍以上
推荐可直接使用的Python库(无需自行实现底层逻辑)
- pydantic:统一处理员工数据的类型转换和校验,不管输入是字典还是数据类,都可以转成标准化的模型,自动处理字符串、浮点数、整数、日期、enum的类型适配,避免匹配时类型错误
- rule-engine:轻量级开箱即用的规则引擎,原生支持你需要的所有运算符(比较运算符、字符串的
contains/startswith/endswith/regexMatch,以及and/or/not布尔组合),可以直接将SQL中拉取的原子表达式拼接成规则语句,预编译为规则对象后,调用matches()方法即可完成匹配,性能远高于Cerberus,且规则语句可读性极强 - pandas(可选,大数据量场景):如果员工数据量极大,可以将数据转成DataFrame,把规则转成pandas的查询条件,用
df.query()或者布尔掩码批量计算命中情况,避免逐行循环的性能损耗 - networkx(可选,规则层级极深场景):如果你的规则层级超过3层,可用该库构建规则决策树,快速遍历节点完成匹配,减少层级遍历的代码量
最简实现示例
import rule_engine from pydantic import BaseModel from datetime import date from enum import Enum # 1. 定义员工数据模型,统一类型 class GenderEnum(str, Enum): MALE = "male" FEMALE = "female" class Employee(BaseModel): name: str position: str hourly_wage: float remaining_annual_leave: int hire_date: date gender: GenderEnum # 2. 模拟从SQL拉取规则后拼接预编译 # 示例规则:岗位是经理 且 剩余年假大于等于5天 且 入职时间早于2020年1月1日 rule_obj = rule_engine.Rule( "position == 'manager' and remaining_annual_leave >=5 and hire_date < dt('2020-01-01')" ) # 3. 批量匹配 employees = [ Employee(name="张三", position="manager", hourly_wage=80.5, remaining_annual_leave=6, hire_date=date(2019,5,1), gender=GenderEnum.MALE).dict(), Employee(name="李四", position="developer", hourly_wage=60.2, remaining_annual_leave=10, hire_date=date(2021,3,1), gender=GenderEnum.FEMALE).dict() ] # 匹配结果:只有张三命中该规则 matched = [emp for emp in employees if rule_obj.matches(emp)]
内容的提问来源于stack exchange,提问作者gt6989b
相关产品推荐
相关产品推荐

