strings.index 是多数场景的默认解,它零预处理、零内存占用、无构建延迟,对 5kb 以内文本查固定关键词平均仅 ~30ns;硬套 suffixarray 或倒排索引反而拖慢 700 倍。

别急着选框架——95% 的搜索需求,strings.Index 或 bytes.IndexByte 就够了;真要上索引结构,必须先确认文本是否静态、查询是否高频、长度是否超 10KB,否则反而拖慢 700 倍。
strings.Index 是多数场景的默认解,不是备选方案
它零预处理、零内存占用、无构建延迟,对 5KB 以内文本查固定关键词,平均耗时仅 ~30ns。硬套 suffixarray 或倒排索引,等于给自行车装涡轮增压。
- 含中文时,
strings.Index返回的是字节偏移,若需按字符切分,得用utf8.RuneCountInString(s[:pos])转换,否则s[pos:pos+len(keyword)]可能 panic - 拼接字段再查比两次
strings.Contains快:比如text := a.Title + "\n" + a.Content,然后单次strings.Contains(text, keyword) - 关键词带空格想实现 AND?用
strings.Fields(keyword)拆词,再循环检查每个词是否都strings.Contains,比正则轻量可控
suffixarray 只在极窄条件下值得用
它不是“更快的字符串搜索”,而是“长文本 + 百次以上随机子串查找”的专用加速器。误用典型是每次用户输入就调一次 suffixarray.New(data),构建耗时 20μs 起,比 strings.Index 慢 700 倍。
- 必须满足三个条件:文本长度 >10KB、内容稳定不变、总搜索次数 ≥200
-
suffixarray.New内存占用约 4×原文本长度,输入超 2GB 会 panic:runtime error: makeslice: len out of range,上线前务必加if len(data) > 2<sup>31</sup>校验 - 返回值是
[]int,不是bool或单个int:取第一个匹配要先判if len(result) == 0,限制前 5 个得手动 break
多关键词、前缀、模糊匹配,别硬塞 suffixarray
suffixarray.Search 只做精确子串匹配,不支持 .、*、? 等任何正则元字符。强行模拟前缀匹配,不如直接用 strings.HasPrefix(O(m) 且零分配)。
- 多个固定关键词同时查找(如敏感词过滤):用
github.com/BurntSushi/aho-corasick,建树 O(∑len(patterns)),搜索 O(n + m) - 需要正则逻辑(如邮箱、URL 提取):直接
regexp.Compile,现代引擎已高度优化,简单模式甚至比手写状态机还快 - 纯前缀场景(如路由匹配):用
sort.Strings+sort.SearchStrings做二分查找,或用g(具体库名需查证)
倒排索引不是“存词+存文档ID”那么简单
手写倒排索引本质是 map[string][]int,但错一个边界,性能就崩:文档 ID 必须是连续整数(0,1,2…),不能是 UUID 或路径;词项列表必须严格递增无重复;AND 搜索必须用双指针归并,嵌套 for 会让比较次数爆炸。
- 切词别用
strings.Split或正则:用strings.FieldsFunc(text, func(r rune) bool { return !unicode.IsLetter(r) && !unicode.IsNumber(r) }) - 插入前用
sort.SearchInts查重+插入,保证[]int递增无重复,否则双指针会漏匹配 - AND 搜索时,对两个词的结果列表做双指针归并,1000 篇文档、各命中 200 篇时,嵌套遍历比较次数超 4 万次,双指针只需 ~400 次
真正卡住性能的,从来不是“没用高级索引”,而是没想清楚:这文本变不变?查几次?要不要支持通配?中文怎么切?这些判断错了,后面所有优化都是在错误前提上堆砌。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











