You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Apex触发器中优化多规则字符串匹配性能?

Apex规则匹配性能优化方案

1. 按匹配类型分类预处理规则

把规则按Match Type拆分,针对不同类型设计高效匹配逻辑,避免全量遍历:

  • Exact (Case Insensitive):将所有匹配条件转成小写,存入Map<String, List<String>> exactRuleMap(key为小写的匹配条件,value为对应的Category列表)。匹配时只需将用户字符串转小写,直接查询Map是否存在对应key,时间复杂度O(1)。
  • Contains (Case Insensitive):将所有匹配条件转义后合并为一个正则表达式(如(Thing a|Thing b)),预编译成Pattern实例。通过一次正则匹配即可找出所有命中的子串,再反向映射到对应的Category(提前建立子串到Category的映射Map)。
  • Regular Expression:预编译所有正则规则为Pattern实例,存入列表,避免每次匹配重复编译。

2. 批量处理时复用预处理结果

在触发器事务内,先一次性加载所有规则并完成预处理(利用静态变量缓存,确保事务内仅处理一次规则),再批量处理所有记录:

public class RuleMatcher {
    // 静态缓存预处理后的规则,事务内仅初始化一次
    private static Map<String, List<String>> exactRuleMap;
    private static Pattern containsPattern;
    private static Map<String, String> containsKeyToCategory;
    private static List<PatternWithCategory> regexPatterns;

    // 内部类存储正则表达式和对应的Category
    private class PatternWithCategory {
        public Pattern pattern;
        public String category;
        public PatternWithCategory(Pattern p, String c) {
            pattern = p;
            category = c;
        }
    }

    // 初始化规则缓存
    private static void initRules() {
        if (exactRuleMap != null) return; // 已初始化则跳过

        exactRuleMap = new Map<String, List<String>>();
        containsKeyToCategory = new Map<String, String>();
        regexPatterns = new List<PatternWithCategory>();
        List<String> containsCriteria = new List<String>();

        // 假设规则存储在自定义对象Rule__c中
        for (Rule__c rule : [SELECT Match_Criteria__c, Match_Type__c, Category__c FROM Rule__c]) {
            String criteria = rule.Match_Criteria__c?.trim();
            if (String.isBlank(criteria)) continue;

            switch on rule.Match_Type__c {
                when 'Exact (Case Insensitive)' {
                    String lowerCriteria = criteria.toLowerCase();
                    if (!exactRuleMap.containsKey(lowerCriteria)) {
                        exactRuleMap.put(lowerCriteria, new List<String>());
                    }
                    exactRuleMap.get(lowerCriteria).add(rule.Category__c);
                }
                when 'Contains (Case Insensitive)' {
                    // 转义正则特殊字符,避免匹配异常
                    String escapedCriteria = Pattern.quote(criteria);
                    containsCriteria.add(escapedCriteria);
                    containsKeyToCategory.put(criteria.toLowerCase(), rule.Category__c);
                }
                when 'Regular Expression' {
                    regexPatterns.add(new PatternWithCategory(Pattern.compile(criteria), rule.Category__c));
                }
            }
        }

        // 构建Contains类型的合并正则
        if (!containsCriteria.isEmpty()) {
            String regexStr = '(' + String.join(containsCriteria, '|') + ')';
            containsPattern = Pattern.compile(regexStr, Pattern.CASE_INSENSITIVE);
        }
    }

    // 单条字符串匹配方法
    public static List<String> matchString(String input) {
        initRules();
        List<String> results = new List<String>();
        if (String.isBlank(input)) return results;
        String lowerInput = input.toLowerCase();

        // 匹配Exact规则
        if (exactRuleMap.containsKey(lowerInput)) {
            results.addAll(exactRuleMap.get(lowerInput));
        }

        // 匹配Contains规则
        if (containsPattern != null) {
            Matcher matcher = containsPattern.matcher(input);
            while (matcher.find()) {
                String matchedStr = matcher.group().toLowerCase();
                if (containsKeyToCategory.containsKey(matchedStr)) {
                    results.add(containsKeyToCategory.get(matchedStr));
                }
            }
        }

        // 匹配正则规则
        for (PatternWithCategory pwc : regexPatterns) {
            Matcher matcher = pwc.pattern.matcher(input);
            if (matcher.find()) {
                results.add(pwc.category);
            }
        }

        return results;
    }

    // 批量匹配方法
    public static Map<Id, List<String>> matchRecords(Map<Id, SObject> records, String fieldApiName) {
        initRules();
        Map<Id, List<String>> recordMatches = new Map<Id, List<String>>();

        for (Id recordId : records.keySet()) {
            String input = (String)records.get(recordId).get(fieldApiName);
            recordMatches.put(recordId, matchString(input));
        }

        return recordMatches;
    }
}

3. 触发器中调用示例

trigger MyObjectTrigger on MyObject__c (before insert, before update) {
    Map<Id, List<String>> matches = RuleMatcher.matchRecords(Trigger.newMap, 'Input_String__c');

    for (MyObject__c obj : Trigger.new) {
        List<String> categories = matches.get(obj.Id);
        if (!categories.isEmpty()) {
            // 将匹配结果赋值到对应字段,比如用分号分隔
            obj.Matched_Categories__c = String.join(categories, '; ');
        }
    }
}

关键优化点说明

  • 避免嵌套循环:原方案是记录数×规则数的O(n*m)复杂度,优化后变为规则预处理O(m) + 每条记录匹配O(k)(k为匹配类型的固定开销),性能随规则数量增长的衰减大幅降低。
  • 静态缓存:规则预处理在事务内仅执行一次,避免重复查询和编译。
  • 正则复用:Contains类型合并为单个正则,减少匹配次数;正则类型预编译,避免重复编译开销。

内容的提问来源于stack exchange,提问作者Trevor Gibson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 14:03:20