无法正常退出,但也能用

This commit is contained in:
2026-04-08 21:14:13 +08:00
parent 6c6a94c043
commit 7844495c98
2 changed files with 50 additions and 27 deletions
+17 -21
View File
@@ -7,12 +7,11 @@ package analyzer
import (
"encoding/json" // JSON 反序列化(加载屏蔽词列表)
"log" // 日志(gojieba panic 恢复时输出
"math" // 数学运算(最小值、开方
"os" // 文件系统操作(读取屏蔽词文件)
"strings" // 字符串操作
"sync" // 互斥锁(保护 jieba 的非线程安全调用)
"unicode" // Unicode 字符判断
"math" // 数学运算(最小值、开方
"os" // 文件系统操作(读取屏蔽词文件
"strings" // 字符串操作
"sync" // 互斥锁(保护 jieba 的非线程安全调用)
"unicode" // Unicode 字符判断
"github.com/pemistahl/lingua-go" // 纯 Go 语言检测库(支持 75 种语言)
"github.com/yanyiwu/gojieba" // GojiebaC++ 结巴分词的 Go 封装
@@ -26,9 +25,9 @@ type Keyword struct {
// Analyzer 封装结巴分词和语言检测器,提供线程安全的分析流水线。
type Analyzer struct {
jieba *gojieba.Jieba // 结巴分词句柄(C++ 实现,非线程安全)
jieba *gojieba.Jieba // 结巴分词句柄(C++ 实现,非线程安全)
detector lingua.LanguageDetector // 语言检测器(lingua-go
stopWords map[string]bool // 屏蔽词集合(标点符号、停用词等)
stopWords map[string]bool // 屏蔽词集合(标点符号、停用词等)
mu sync.Mutex // 保护 jieba 调用的互斥锁
}
@@ -87,35 +86,32 @@ func loadStopWords(path string) map[string]bool {
// searchMode=true:搜索模式分词(更细粒度,适合搜索查询);
// searchMode=false:精确模式分词(适合页面内容分析)。
// 策略:纯 ASCII 字母数字按空格切分;含中文/其他字符的片段交给结巴处理。
func (a *Analyzer) Tokenize(s string, searchMode bool) (result []string) {
func (a *Analyzer) Tokenize(s string, searchMode bool) []string {
// 超长文本截断(jieba 对极长文本处理效率下降)
if len(s) > 10000 {
s = s[:10000]
}
// 清洗非 UTF-8 字节,防止 gojieba 的 C++ 层报 "decode failed" 错误
s = strings.ToValidUTF8(s, "")
var result []string
for _, part := range strings.Fields(s) {
if isASCIIAlnum(part) {
// 纯 ASCII 片段直接保留,不走 jieba
result = append(result, part)
} else {
// 非 ASCII(含中文/日文等):加锁后调用 jieba 分词
// defer recover 防止 gojieba C++ 崩溃(如 Ctrl+C 时 SIGSEGV)导致锁泄漏
a.mu.Lock()
defer func() {
if r := recover(); r != nil {
log.Printf("[analyzer] gojieba panic recovered: %v", r)
}
a.mu.Unlock()
}()
var tokens []string
if searchMode {
result = append(result, a.jieba.CutForSearch(part, true)...)
tokens = a.jieba.CutForSearch(part, true)
} else {
result = append(result, a.jieba.Cut(part, true)...)
tokens = a.jieba.Cut(part, true)
}
a.mu.Unlock()
result = append(result, tokens...)
}
}
return
return result
}
// Normalize 标准化字符串:去除非字母数字非 CJK 字符,并转为小写。
@@ -165,9 +161,9 @@ func (a *Analyzer) weightedTokens(text string, w float32) map[string]float32 {
func (a *Analyzer) Analyze(title, description, text string) []Keyword {
// 分别计算三段的词权重
maps := []map[string]float32{
a.weightedTokens(title, 1.0), // 标题权重最高
a.weightedTokens(title, 1.0), // 标题权重最高
a.weightedTokens(description, 0.5), // 描述权重中等
a.weightedTokens(text, 1.0), // 正文权重同标题
a.weightedTokens(text, 1.0), // 正文权重同标题
}
// 合并三段权重:先去重建立 key 集合