jieba
是一个非常流行的中文分词工具,它支持三种分词模式:精确模式、全模式和搜索引擎模式。其中,cut_for_search()
是 jieba
提供的用于搜索引擎模式的分词方法,适合用在构建搜索索引或进行文本检索时。
jieba.cut_for_search()
详解
功能:
cut_for_search()
主要用于搜索引擎分词,会对文本进行较细的切分,特别是对较长的词语进行更多的分割。这使得它更适合搜索场景,因为搜索引擎通常需要更细粒度的分词来提高匹配的可能性,特别是支持短语检索和子词匹配。
使用方法:
import jieba
text = "我来到北京清华大学"
result = jieba.lcut_for_search(text)
print(result)
输出:
['我', '来到', '北京', '清华', '华大', '大学', '清华大学']
特点:
- 子词拆分:
lcut_for_search()
不仅会分出完整的词,还会将长词进一步细分。例如,“清华大学”会被分为“清华”、“华大”、“大学”。 - 适合搜索引擎:对长词的进一步拆分非常适合构建倒排索引(inverted index),因为它能够提高子词的匹配率,进而提高检索的召回率。
- 返回列表:
lcut_for_search()
会返回一个分词后的词语列表,而不是迭代器,方便处理。
具体应用场景:
- 倒排索引构建:在搜索引擎中,常常需要对文本进行分词,以便为每个词建立倒排索引。
cut_for_search()
会切分出更多细粒度的词,有助于提高搜索结果的相关性。 - 用户查询处理:当用户输入长词或短语时,细粒度的分词可以确保用户查询中的各个部分都能参与匹配,提高检索的灵活性。
注意事项:
- 细粒度分词可能增加计算开销:由于对长词进行了更多的拆分,可能会生成比精确模式更多的词,因此在处理和匹配时可能会稍微增加一些计算负担。
- 适用场景:
cut_for_search()
在需要更高检索召回率的场景(如搜索引擎)非常合适,但在不涉及子词匹配的其他任务中,可能不如精确模式高效。
对比其他分词模式:
- 精确模式 (
cut()
):jieba.cut()
切分出来的词通常更少,只保留了精确的词语边界,适合统计或语义分析等任务。 - 全模式 (
cut_all()
):cut_all()
会把可能的词都分出来,通常会生成非常多的词,适合搜索引擎的粗分词场景,但输出结果冗余度较高,不建议直接用于检索任务。
通过使用 cut_for_search()
,可以有效地提高搜索系统的召回能力,同时保持较高的搜索精度。
def cut_for_search(self, sentence, HMM=True):
"""
Finer segmentation for search engines.
"""
words = self.cut(sentence, HMM=HMM)
for w in words:
if len(w) > 2:
for i in xrange(len(w) - 1):
gram2 = w[i:i + 2]
if self.FREQ.get(gram2):
yield gram2
if len(w) > 3:
for i in xrange(len(w) - 2):
gram3 = w[i:i + 3]
if self.FREQ.get(gram3):
yield gram3
yield w
这段代码是 jieba
库中 cut_for_search
方法的实现,它用于进行搜索引擎的细粒度分词。让我们详细分析这段代码的逻辑,解释其工作原理:
1. 函数定义
def cut_for_search(self, sentence, HMM=True):
"""
Finer segmentation for search engines.
"""
- 该函数的作用是对输入的
sentence
进行更细致的分词,主要用于搜索引擎。 HMM=True
是用于控制是否使用**隐马尔可夫模型(HMM)**来处理未登录词(即词典中没有的词)。
2. 调用 self.cut()
进行基础分词
words = self.cut(sentence, HMM=HMM)
self.cut()
是jieba
中的标准分词方法,它会根据设定的模式(是否启用 HMM)对sentence
进行初步分词。- 返回的
words
是初步分词结果,这个结果可以包含单个词语或者多个词。
3. 遍历分词结果
for w in words:
cut_for_search()
会对self.cut()
分词后的每个词w
进行进一步处理。
4. 生成 2-gram
if len(w) > 2:
for i in xrange(len(w) - 1):
gram2 = w[i:i + 2]
if self.FREQ.get(gram2):
yield gram2
- 对于长度大于 2 的词,程序会生成该词的所有 2-gram 子词。
- 2-gram 是由相邻两个字符组成的子词。例如,“清华大学” 会被分成 “清华”、“华大”。
- 在生成 2-gram 之后,程序会检查这些子词是否出现在词典 (
self.FREQ
) 中。- 如果子词存在于词典中,程序会
yield
出这个子词,意味着该子词将作为一个有效的分词结果。
- 如果子词存在于词典中,程序会
5. 生成 3-gram
if len(w) > 3:
for i in xrange(len(w) - 2):
gram3 = w[i:i + 3]
if self.FREQ.get(gram3):
yield gram3
- 对于长度大于 3 的词,程序会生成 3-gram 子词。
- 3-gram 是由三个相邻字符组成的子词。例如,“清华大学” 可以被分成 “清华大”、“华大学”。
- 同样,程序会检查这些 3-gram 是否在词典中存在,若存在,则
yield
出该子词。
6. 保留原词
yield w
- 无论该词是否生成了 2-gram 或 3-gram,原始词语都会作为一个分词结果被保留。
总结:
cut_for_search()
在标准分词结果的基础上,对长度较大的词进一步生成 2-gram 和 3-gram 子词,并检查这些子词是否存在于词典中。存在的话,就将这些子词作为额外的分词结果输出。- 这种处理方式可以在搜索引擎中提高短词和子词的匹配率,进而提高召回率。这也是搜索引擎分词通常比普通分词更细致的原因。
例如:
sentence = "清华大学"
result = list(jieba.cut_for_search(sentence))
print(result)
输出:
['清华', '华大', '大学', '清华大学']
这展示了 2-gram 的生成过程以及原词的保留。