Laravel敏感词用Trie树吗

wen PHP项目 17

本文目录导读:

Laravel敏感词用Trie树吗

  1. 为什么推荐 Trie 树?
  2. Laravel 中实现 Trie 树敏感词过滤
  3. 最佳实践建议
  4. 注意事项

在 Laravel 中实现敏感词过滤,使用 Trie 树(前缀树)是非常合适且推荐的做法,尤其适合需要高效检测大量敏感词的场景。

为什么推荐 Trie 树?

优势

  1. 时间复杂度低:O(n) 级别的匹配速度,n 为文本长度
  2. 内存占用合理:共享前缀节点,适合大量敏感词
  3. 支持最长匹配:避免误判(如“共产党”和“共产党宣言”)

常见方案对比

方案 时间复杂度 内存占用 实现复杂度
正则表达式 O(n*m) 简单
Trie树 O(n) 中等 中等
Aho-Corasick O(n) 复杂
布隆过滤器 O(n) 需配合

Laravel 中实现 Trie 树敏感词过滤

安装包(推荐)

composer require sensortree/sensitive
use SensorTree\Sensitive;
$sensitive = new Sensitive();
$sensitive->addWords(['敏感词1', '敏感词2']);
$sensitive->filter('需要过滤的文本'); // 返回替换后的文本

自定义实现

namespace App\Services;
class TrieFilter
{
    private $tree = [];
    public function addWord($word)
    {
        $node = &$this->tree;
        $len = mb_strlen($word);
        for ($i = 0; $i < $len; $i++) {
            $char = mb_substr($word, $i, 1);
            if (!isset($node[$char])) {
                $node[$char] = [];
            }
            $node = &$node[$char];
        }
        $node['end'] = true; // 标记结束
    }
    public function filter($text, $replace = '*')
    {
        $len = mb_strlen($text);
        $result = '';
        $positions = []; // 需要替换的字符位置
        for ($i = 0; $i < $len; $i++) {
            $node = $this->tree;
            if (isset($node[mb_substr($text, $i, 1)])) {
                $this->checkWord($text, $i, $node, $positions);
            }
        }
        // 替换处理
        for ($i = 0; $i < $len; $i++) {
            $result .= isset($positions[$i]) ? $replace : mb_substr($text, $i, 1);
        }
        return $result;
    }
    private function checkWord($text, $start, $node, &$positions)
    {
        $len = mb_strlen($text);
        for ($i = $start; $i < $len; $i++) {
            $char = mb_substr($text, $i, 1);
            if (!isset($node[$char])) break;
            $node = $node[$char];
            if (isset($node['end'])) {
                // 标记要替换的字符
                for ($j = $start; $j <= $i; $j++) {
                    $positions[$j] = true;
                }
            }
        }
    }
}

加载敏感词列表

class SensitiveService
{
    protected $trie;
    public function __construct()
    {
        $this->trie = new TrieFilter();
        $words = config('sensitive.words'); // 从配置文件加载
        foreach ($words as $word) {
            $this->trie->addWord($word);
        }
    }
    public function filter($text)
    {
        return $this->trie->filter($text);
    }
}

在控制器中使用

use App\Services\SensitiveService;
class CommentController extends Controller
{
    public function store(Request $request, SensitiveService $sensitive)
    {
        $content = $sensitive->filter($request->input('content'));
        Comment::create([
            'content' => $content,
            'has_sensitive' => $content !== $request->input('content')
        ]);
        return redirect()->back();
    }
}

最佳实践建议

缓存 Trie 树

// 使用 Laravel 的缓存机制
Cache::rememberForever('sensitive_trie', function() {
    $trie = new TrieFilter();
    // 加载敏感词
    return $trie;
});

分库存储敏感词

// 按等级分类
$sensitive->addWord('作弊', 1);  // 1级:替换
$sensitive->addWord('赌博', 2);  // 2级:直接拒绝

性能优化

  • 使用 mb_* 函数处理多字节字符
  • 预编译 Trie 树,避免每次请求都重建
  • 考虑使用 Swoole 扩展在内存中常驻

中文特殊处理

  • 注意繁简体转换
  • 支持拼音模糊匹配
  • 处理好词语间的空格、符号

注意事项

  1. 内存占用:敏感词越多,Trie 树内存越大,建议控制在 10 万以内
  2. 并发安全:Trie 树是只读数据,不需要加锁
  3. 更新策略:支持热更新,但不建议频繁重建
  4. 误判处理:建议配合人工审核

如果对性能要求特别高(如实时聊天过滤),可以考虑使用 Aho-Corasick 算法,但实现复杂度会更高,对于大多数 Laravel 项目,Trie 树已经足够。

抱歉,评论功能暂时关闭!