Files
server/app/utils/fulltext_search.go
2026-01-16 15:49:34 +08:00

84 lines
2.6 KiB
Go

package utils
import (
"strings"
"github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/facades"
)
// ApplyFulltextSearch 应用全文索引搜索条件
// column: 要搜索的字段名(如 "request", "content" 等)
// keyword: 搜索关键词
// query: ORM 查询对象
// 返回: 应用了搜索条件的查询对象
func ApplyFulltextSearch(query orm.Query, column, keyword string) orm.Query {
if keyword == "" {
return query
}
// 获取数据库类型
dbConnection := facades.Config().GetString("database.default", "sqlite")
isPostgreSQL := dbConnection == "postgres"
// 判断是否应该使用全文索引
// 对于短词(少于3个字符)或包含特殊字符的搜索,使用 LIKE/ILIKE
// 对于长词,使用全文索引
useFulltext := len(keyword) >= 3
// 检查是否包含特殊字符(逗号、引号、括号等)
specialChars := []string{",", "\"", "'", "(", ")", "[", "]", "{", "}", ":", ";", "=", "+", "-", "*", "/", "\\", "|", "&", "%", "$", "#", "@", "!", "?", "<", ">", "~", "`"}
for _, char := range specialChars {
if strings.Contains(keyword, char) {
useFulltext = false
break
}
}
if useFulltext {
if isPostgreSQL {
// PostgreSQL: 使用 pg_trgm 相似度搜索(需要已创建 GIN 索引)
// 使用 % 操作符进行相似度匹配,阈值默认 0.3
return query.Where(column+" % ?", keyword)
} else {
// MySQL: 使用 ngram 全文索引
// 注意:需要确保字段已创建全文索引,索引名格式为 ft_{column}
return query.Where("MATCH("+column+") AGAINST(? IN BOOLEAN MODE)", keyword)
}
} else {
// 短词或包含特殊字符:使用 LIKE/ILIKE
if isPostgreSQL {
// PostgreSQL: 使用 ILIKE(不区分大小写)
return query.Where(column+" ILIKE ?", "%"+keyword+"%")
} else {
// MySQL: 使用 LIKE
return query.Where(column+" LIKE ?", "%"+keyword+"%")
}
}
}
// ShouldUseFulltextIndex 判断是否应该使用全文索引
// keyword: 搜索关键词
// 返回: true 表示应该使用全文索引,false 表示使用 LIKE/ILIKE
func ShouldUseFulltextIndex(keyword string) bool {
if len(keyword) < 3 {
return false
}
// 检查是否包含特殊字符
specialChars := []string{",", "\"", "'", "(", ")", "[", "]", "{", "}", ":", ";", "=", "+", "-", "*", "/", "\\", "|", "&", "%", "$", "#", "@", "!", "?", "<", ">", "~", "`"}
for _, char := range specialChars {
if strings.Contains(keyword, char) {
return false
}
}
return true
}
// IsPostgreSQL 判断当前数据库是否为 PostgreSQL
func IsPostgreSQL() bool {
dbConnection := facades.Config().GetString("database.default", "sqlite")
return dbConnection == "postgres"
}