什么是全文索引(Full-text Search):
简单来讲,全文索引就是“关键词”和“文件”的映射。
提出问题,如何检索非结构的文本:
搜索引擎面临的核心问题之一,是如何在一堆异构的文本本间中快速检索出哪些包含特定语句。给一句话,快速检索包含这句话的文本。
最直接想到的解决方案是遍历文本做字符串的匹配。这个方案对于少量文件是可行的。但是面对数以亿计的文件时,这个方案最先被淘汰的——效率太低。同样的,对于大文本使用字符串匹配的效率也很低。核心的问题都是一堆没有结构的文本中,关键词在整个查询域的分布太大,导致查询效率下降。
解决问题:
解决的办法就是对文本建立关键词(tag),通过关键词对离散的文本进行分组。把离散文本映射到关键词的过程,就是在建立全文索引。
现在问题简化成三个小问题:
- 如何提取文本中的关键词。
- 如何建立文本和关键词的映射。
- 如何查询关键词。
1、如何提取文本中的关键词——分词:
解决第一个小问题需要对文本进行分词。中文的分词因为词语之间没有间隔(空格),要比英文分词稍复杂。可以使用“结巴分词”(jieba)实现中文分词的需求。
基本使用:
pip install jieba
import jieba
file = open(“filepath”)
wordcuts = jieba.cut_for_search(file.read())
print(“,”.join(wordcuts))
jieba分词之后返回的 结果(wordcuts)是一个迭代器。
停止词过滤:
分词完成后,需要对分词的结果进行分析。结果中有许多没有实际意义的词语,比如:
中文中的语气助词:的、了、着、吧、啊。
连词:因为所有、为了、由于。
介词:从、在、把、让、才。
还有一些词,虽然有实际的意义,但是在文本中出现的频率过高,比如“web”、“网络”等。
——这些词因为出现的频率太高,用他们区别文本的意义不大,而且对这些覆盖太广的关键词建立索引的成本也很大。
因此需要过滤掉这些词。查找这些词需要一个字典,英文中称作“stopwords”,很多中文文献中直接翻译成“停止词”。搜索“停止词”可以找到不同版本的停止词列表。
过滤掉停止词,得到最终的关键词字典。
2、如何建立文本和关键词的映射——索引文件的生成。
一般文件索引的结构是B树或者B+树。这两种结构都属于比较基础的数据结构,网上的介绍资料很多,这里不过多介绍了。
针对全文建立索引,本质上就是在关键词和文件建立树状关系。我们根据关键词和文本的存储结构,简单的模拟一下B+树,可以生成一个如下结构的Json:
{“关键词1”:[文件id1,文件id2],“关键词2”:[文件id1,文件id3,文件id4..]…}
这样形成了两层的树状结构。
上面的简单情况。在数据文件较多的情况下,我们需要增加树的层级。例如:简单的对索引文件进行切片,建立以下两层索引文件:
索引1:关键词映射索引文件分区:
idx_root : {“关键词”:{索引文件1}}
索引2:文件分区内关键词的映射ID
idx_lf_1 :{“关键词1”:[文件id1,文件id2],“关键词2”:[文件id3]... }
idx_lf_2 :{“关键词3”:[文件id1,文件id2] ...}
这样整个索引被分成了两部分,一部分是关键词字典(idx_root ),另一部分是全文文件的分组(idx_lf)。
idx_root 的部分就是树状结构的Root,可以在系统装载的时候读入内存中,建立一个Hash映射,提高查询速度。
3、查询关键词
根据上面建立的简单索引文件,很容易想到,查询的输入也要进行分词(cuts)。输入cuts的分词先去Json1匹配关键词,找到对应的索引文件idxfile。这一步一般在内存的散列表中完成。
第二步,在idxfile匹配关键词,找到文本文件的id或path,加载文件。
最后,对于多个输入分词得到的关键词(cuts),可能需要区别每个关键词的权重——这个权重可能是一个字典。然后检查结果文件中关键词出现的次数、频率,根据关键词权重相加,来计算文件的权重。根据文件权重进行排序后输出。
网友评论