规则分配脚本

需求:

1.根据用户编写的要报规则,去mysql库里SysManage_Rule表获取已经启用的规则作为条件(例如[{"field": "关键词", "logic": "AND", "value": "阿尔法", "operator": "=",, "assign_user": "user222"}])条件即为:关键词=阿尔法

2.根据此条件去lxdb的all_report表进行查询,查询逻辑是每10min获取最新数据,满足条件的对all_report表的report_handler字段打上分配人名以及yb_importanceid填上要报规则的id

要报规则页面:

SysManage_Rule表

解决办法

规则分配脚本(supervisor运行):

python 复制代码
import argparse
import os
import django
import time
from datetime import datetime, timedelta
import sys
import json

# 添加项目路径,确保 Django 配置正确
sys.path.append('/home/rpadmin/web/yb-backend')

# 初始化 Django 环境
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "yb.settings")
django.setup()

# 导入自定义模块和参数
from DBreport.functions.get_table_mapping import get_gather_table
from wrapper.Params import TOREPORT, GATHER_TABLE
from DBconn.DBfunctions.dynamicQueryBase import DynamicQueryBaseEngine
from SysManage.models import SysmanageRule

# 字段名映射:中文字段名 -> 英文字段名
field_mapping = {
    "报文要素": "text_content",
    "语种": "audio_languagename",
    "关键词": "keyword",
    "文种": "text_lang",
    "实体": "text_entity",
    "来源手段": "hj_means"
}

# 初始记录时间,第一次运行查很早之前的数据
last_run_time = datetime.now() - timedelta(minutes=1600000)

def replace_field_names(data, mapping):
    new_data = {}
    for user, rules in data.items():
        new_rules = []
        for rule in rules:
            new_rule = rule.copy()
            if new_rule.get('field') in mapping:
                new_rule['field'] = mapping[new_rule['field']]
            new_rules.append(new_rule)
        new_data[user] = new_rules
    return new_data

def run_rule_dispatch():
    global last_run_time

    # 获取数据库连接和数据表对象
    db_conn = get_gather_table()
    gather_table = db_conn.load_table(GATHER_TABLE)

    print("[调试] all_report 字段列表:", [col.name for col in gather_table.columns])

    # 查询所有启用状态的规则
    rules = SysmanageRule.objects.filter(rule_status=1)

    for rule in rules:
        rule_id = rule.id
        rule_name = rule.rule_name
        rule_content = rule.rule_content

        # 检查规则内容格式是否为列表
        if isinstance(rule_content, list):
            conditions = rule_content
        else:
            print(f"[跳过] 规则《{rule_name}》内容应为列表格式")
            continue

        # 替换条件中的字段名
        conditions = replace_field_names({rule_name: conditions}, field_mapping)[rule_name]

        filters = []
        keyword_value = None  # 保存关键词值(如果存在)

        for cond in conditions:
            field = cond.get("field")
            operator = cond.get("operator")
            value = cond.get("value")
            if cond.get("assign_user"):
                assign_user = cond["assign_user"]
            if not field or not operator or value is None:
                continue

            # 如果字段为 keyword 且是等于操作,延迟处理
            if field == "keyword" and operator == "=":
                keyword_value = value
            else:
                filters.append((field, operator, value))

        # 增加时间过滤:只查上次运行之后新增的数据
        filters.append(('hj_createtime', '>=', last_run_time))

        # 关键词特殊处理:模糊匹配 audio_asr 或 trans_sidebyside 的 original_content/ translat_content 字段
        if keyword_value is not None:
            # audio_asr 模糊匹配
            filters_audio = filters + [('audio_asr', 'like', f"%{keyword_value}%")]

            # 执行原始查询(不带关键词)用于后续文本内容筛选
            raw_trans_records = db_conn.execute_dynamic_query(
                gather_table,
                filters,
                limit=5,  # 仅预览前5条,必要时可调整或移除
                ignore_fields=[]
            )

            matched_trans_data = []
            for row in raw_trans_records['data']:
                try:
                    trans_data = row.get('trans_sidebyside')
                    if isinstance(trans_data, str):
                        trans_data = json.loads(trans_data)  # JSON 反序列化
                    if isinstance(trans_data, dict):
                        original = trans_data.get("original_content", "")
                        translated = trans_data.get("translat_content", "")
                        if keyword_value in original or keyword_value in translated:
                            matched_trans_data.append(row)
                except Exception:
                    continue

            # 执行 audio_asr 匹配查询
            result1 = db_conn.execute_dynamic_query(gather_table, filters_audio, ignore_fields=[])

            # 合并两类结果(根据 lxid 去重)
            combined_data = {row['lxid']: row for row in result1['data']}
            for row in matched_trans_data:
                combined_data.setdefault(row['lxid'], row)

            total_count = len(combined_data)
            print(f"[调试] 条件命中记录数:{total_count}")
            if total_count:
                first_row = list(combined_data.values())[0]
                print("[调试] 命中示例记录:", first_row)

            # 构造更新内容
            updates = {
                'report_handler': assign_user,
                'yb_importanceid': str(rule_id),
                'yb_importancename': rule_name,
                'assign_rule_type': TOREPORT
            }

            # 遍历命中记录逐条更新
            affected = 0
            for row in combined_data.values():
                row_filter = [('lxid', '=', row['lxid'])]
                try:
                    count = DynamicQueryBaseEngine.update_record(db_conn, gather_table, updates, row_filter)
                    affected += count
                except Exception as e:
                    print(f"[×] 更新失败:{str(e)}")

            print(f"[✓] 规则《{rule_name}》执行成功,分配人:{assign_user},更新{affected}条")
            continue

        # 正常流程处理:无关键词匹配逻辑
        print(f"[调试] 规则《{rule_name}》筛选条件:{filters}")

        result_data = db_conn.execute_dynamic_query(
            gather_table,
            filters,
            limit=5,
            ignore_fields=[]
        )
        print(f"[调试] 条件命中记录数:{result_data['total_count']}")
        if result_data['data']:
            print("[调试] 命中示例记录:", result_data['data'][0])

        updates = {
            'report_handler': assign_user,
            'yb_importanceid': str(rule_id),
            'yb_importancename': rule_name,
            'assign_rule_type': TOREPORT
        }

        try:
            affected = DynamicQueryBaseEngine.update_record(db_conn, gather_table, updates, filters)
            print(f"[✓] 规则《{rule_name}》执行成功,分配人:{assign_user},更新{affected}条")
        except Exception as e:
            print(f"[×] 规则《{rule_name}》执行失败:{str(e)}")

    # 关闭连接,记录当前时间用于下轮过滤
    db_conn.close()
    last_run_time = datetime.now()


if __name__ == "__main__":
    while True:
        print(f"\n[调试] 开始执行调度任务,当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        run_rule_dispatch()
        print(f"[调试] 任务执行完成,等待10分钟...\n")
        time.sleep(600)  # 每10分钟运行一次

指定分配人接口(即向rule_content字段里添加assign_user):

python 复制代码
@class_operation_logger(operation_name="/指定要报规则分配人")
class RuleAssignUserUpdateAPIView(APIView):
    """
    接收 assign_user 和 规则id,指定规则的 rule_content 中每一项的 assign_user
    POST /api/sys/update-assign-user/
    Body:
    {
        "id": 2,
        "assign_user": "user002"
    }
    """
    def post(self, request, *args, **kwargs):
        rule_id = request.data.get("id")
        assign_user = request.data.get("assign_user")

        if not rule_id or not assign_user:
            return ErrorResponse(data=False, msg="参数id 和 assign_user 都是必填的")
            # 获取要更新的规则
        rule = get_object_or_404(SysmanageRule, pk=rule_id)
        try:
            content_list = rule.rule_content or []
            if not isinstance(content_list, list):
                raise ValueError("rule_content 必须是列表")
        except Exception as e:
            return ErrorResponse(data=False, msg=f"读取 rule_content 失败:{str(e)}")
        # 创建或更新每一项的 assign_user
        for cond in content_list:
            cond['assign_user'] = assign_user
        # 保存回库
        rule.rule_content = content_list
        rule.save(update_fields=['rule_content'])
        return SuccessResponse(msg=f"id为 {rule_id} 的规则的分配人已更新为 {assign_user}")

Supervisor 工具详见文章Supervisor进程管理