3、文本预处理:分词技术、停用词过滤、词干提取与词形还原

好,咱们继续往下走。上一章聊了倒排索引的结构,但有个关键问题我没细说——文档里的文本,到底怎么变成一个个可索引的词?

这就是文本预处理要干的事。说白了,就是把原始文本洗干净、切碎、去杂质,最后变成搜索引擎能理解的最小单元。我在早期做搜索项目时,就吃过没做好预处理的亏——用户搜「跑步鞋」,结果因为分词不对,愣是没召回「跑鞋」这个结果。嗯,从那以后,我对这步再也不敢马虎了。

3.1 分词技术:把句子切成词

分词,就是把连续的汉字序列切分成有意义的词语。英文天然有空格分隔,但中文没有。所以中文分词是搜索引擎的「第一道坎」。

我个人的习惯是,先理解两种最基础的算法:正向最大匹配逆向最大匹配。别看现在深度学习分词满天飞,但这两个算法是理解分词逻辑的基石。

3.1.1 正向最大匹配(FMM)

思路很简单:从左往右扫描,每次取尽可能长的词。

假设词典里有「我们」「在」「北京」「天安门」「天安」「门前」。给定句子:

我们在天安门前

算法步骤:

  1. 设定最大词长,比如4个字。
  2. 从左边取4个字「我们在天」,查词典——没有。
  3. 去掉最后一个字,取「我们在」——没有。
  4. 再去掉,取「我们」——有!切出来。
  5. 从「在」开始,取4字「在天安门」——没有。
  6. 逐步缩短,取「在天」——没有。取「在」——有!
  7. 继续处理「天安门前」……

最终结果:我们 / 在 / 天安门前

核心要点:正向最大匹配是「贪心」的,它总是优先匹配最长的词。但有个问题——它可能把「天安门前」切成一个词,而实际上用户可能期望「天安门 / 前」。

3.1.2 逆向最大匹配(RMM)

和正向相反,从右往左切。还是那句话:

我们在天安门前

步骤:

  1. 从右边取4字「安门前」——没有。
  2. 取「门前」——没有。取「前」——有!
  3. 继续处理「我们在天安门」……

最终结果:我们 / 在 / 天安门 / 前

你看,结果不一样了。逆向匹配往往比正向更准,因为汉语的「中心词」常在后面。我在项目中做过对比测试,RMM的准确率通常比FMM高3-5个百分点。

我的经验:实际工程中,我经常把FMM和RMM的结果做交集或并集。如果两者一致,基本可以信任;如果不一致,再用统计模型做消歧。这叫「双向最大匹配法」,很多开源分词工具都用了这个思路。

3.2 停用词过滤:扔掉没用的词

分词之后,你会发现一堆「的」「了」「在」「是」……这些词几乎出现在每个文档里,对检索毫无帮助。你想想看,用户搜「北京的天气」,如果索引里全是「的」,那召回结果得多乱?

停用词过滤,就是把这些高频但无意义的词扔掉。

常见的停用词分两类:

类别例子为什么去掉
功能词的、了、在、是、有、和语法作用,无实际语义
高频泛词我们、这个、那个、什么出现太频繁,区分度低

注意:停用词表不是一成不变的。我曾经在一个电商搜索项目里,把「买」加进了停用词表,结果用户搜「买手机」时,核心词「买」被过滤了,召回结果全乱套。后来我学乖了——停用词表要跟业务场景绑定。比如在新闻搜索里,「报道」「记者」可能是停用词;但在招聘搜索里,「招聘」「求职」就是核心词。

实现起来很简单,维护一个哈希集合,分词后逐个判断:

if token in stopwords_set:
    continue  # 跳过
else:
    index.add(token)  # 加入倒排索引

3.3 词干提取与词形还原:归一化处理

英文里有个经典问题:用户搜「running」,文档里写的是「ran」。如果直接匹配,就漏掉了。中文也有类似情况,但表现形式不同。

3.3.1 词干提取(Stemming)

词干提取是「暴力」的。它直接砍掉单词的后缀,比如:

  • running → runn(砍掉ing)
  • ran → ran(不规则,砍不动)
  • flies → fli(砍掉es)

你看,结果可能不是真正的单词。但没关系,搜索引擎只关心匹配,不关心拼写是否正确。我早期用Porter Stemmer算法处理英文文档,效果不错,但中文不适用——中文没有词形变化。

3.3.2 词形还原(Lemmatization)

词形还原更「聪明」。它会查词典,把单词还原成原型:

  • running → run
  • ran → run
  • better → good

这需要词库和词性标注的支持。代价是速度慢,但准确率高。

中文怎么办?中文没有词干提取的概念,但有一个类似的操作——同义词归一化。比如「电脑」和「计算机」应该映射到同一个词。我在做医疗搜索时,把「高血压」「高血压病」「hypertension」都归一化到「高血压」,召回率提升了12%。

3.4 实战建议:预处理流水线

好了,知识点讲完了。我建议你在项目中这样组织预处理流程:

  1. 原始文本 → 去除HTML标签、特殊字符
  2. 分词 → 先用RMM,再用FMM做交叉验证
  3. 停用词过滤 → 业务定制停用词表
  4. 归一化 → 同义词映射、大小写统一(英文)
  5. 输出 → 干净的词列表,送入倒排索引构建

这个流水线我用了很多年,基本没出过大问题。你想想看,如果每个环节都做到位,搜索引擎的「地基」就稳了。下一章,咱们正式进入倒排索引的构建和查询,到时候你会看到,预处理的质量直接决定了搜索效果的上限。