切换视频源:

搜索的扩展

作者: 莫烦 编辑: 莫烦 2020-07-15

学习资料:

怎么了

上节我们提到了搜索的精髓,用TF-IDF来表示文档,然后可以用来做搜索和提取关键词。 可是在代码中存在一个机制,会引发内存占用大的问题。

TF-IDF是一张二维表,分别代表文章索引和单词索引。文章量是可以无限增大的,单词量的增长也是很恐怖的。那么随着这两个维度的增长, 我们的内存总有一天会扛不住。好在我们可以利用一个节约内存的技术,叫做Sparse Matrix,稀疏矩阵,它只会存储有内容的值,而忽略无内容的值。 在这张巨大的二维表中,肯定每篇文章不一定会提及到所有词汇,这些不提及的词汇,我们当然可以不用存储

用 Skearn 模块的 Sparse Matrix 功能,能更快速,有效地计算和存储海量的数据。

秀代码

还是以上节内容的 made up 文档举例,如果直接调用 sklearn 的TF-IDF 功能,会方便很多,引用下面两个功能。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

docs = [
    "it is a good day, I like to stay here",
    "I am happy to be here",
    "I am bob",
    "it is sunny today",
    "I have a party today",
    "it is a dog and that is a cat",
    "there are dog and cat on the tree",
    "I study hard this morning",
    "today is a good day",
    "tomorrow will be a good day",
    "I like coffee, I like book and I like apple",
    "I do not like it",
    "I am kitty, I like bob",
    "I do not care who like bob, but I like kitty",
    "It is coffee time, bring your cup",
]

然后就能计算文档中的TF-IDF了,并且像上节内容中 IDF的预计算模式,也可以使用下面的 vectorizer._idf 来提取,用来给新的数据使用。

vectorizer = TfidfVectorizer()
tf_idf = vectorizer.fit_transform(docs)

q = "I get a coffee cup"
qtf_idf = vectorizer.transform([q])
res = cosine_similarity(tf_idf, qtf_idf)
res = res.ravel().argsort()[-3:]
print("\ntop 3 docs for '{}':\n{}".format(q, [docs[i] for i in res[::-1]]))

最后的TF-IDF矩阵结果是这样的。

tfidf-matrix

像这样短短几行 sklearn 的代码,就已经实现了比我们上节内容更优的存储和计算,何乐而不为呢?

还能怎么玩

TF-IDF 中的 IDF 带有全局属性,这个我们无可否认。那么这个全局真的是我们所谓的万事万物的全局吗? 当然不是,这个全局也只是全世界的一部分而已,我们无法获取互联网上所有的信息,而最多只能获取到一个子集,一部分的信息而已。 所以IDF并不是完美的IDF。

不过不完美,也有它使用的方法。比如我们之前提到过,如果是专业领域搜索,我们的IDF就必须注重专业领域的词汇。举个例子, 如果我们想要医学领域的搜索,如果我们拿着IDF娱乐领域获得的IDF,那么在医学领域就不会有什么好效果。原因也很简单 1)娱乐领域没有那么多医学词汇; 2)在医学领域重要的词,娱乐领域中这些词的频率与出现位置分布肯定有很大不同。

反过来,如果你恰好要做一个领域的搜索,又恰好有这个领域的IDF分布,那么恭喜你,你省去了很多数据收集方面的烦恼。这就是IDF复用的神器之处。 回忆一下,在机器学习,神经网络模型方面,(迁移学习)不正好也是一个道理吗?

机器学习应用

我们已经明显感受到,TF-IDF就是对文档进行某种向量化的表示,而在机器学习或者现在比较流行的深度学习中,我们所有东西基本上都和向量有关。 自然而然,我们也能用 TF-IDF 作为文档的训练数据,将文档向量化表示后,当做神经网络的输入,对这篇文档进行后续处理,比如分类,回归等拟合过程。 比如像下面这个 BERT 教学中,训练的中间产物-向量,我们都可以将其作为一个中间结果,放入神经网络当做输入,然后继续后续的任务。

bert

集群版搜索引擎 ElasticSearch

我们现在学习过的,都是这些算法的本质,可是在工业级应用中,光光只知道本质和基础算法是远远不够的。 这里我想引出一个后续可以做成教程的框架 ElasticSearch。 这个框架下的本质算法就是类似于TF-IDF的搜索算法,它就是一个优秀的分布式搜索引擎后台 (单机版的叫做lucene),做到了一键化数据导入和索引构建,同时也能处理海量数据。 用到了更加丰富有效的算法, 比如BM25

在企业级的搜索引擎应用中,ElasticSearch 绝对是不二选择。后续我也可能会考虑把 莫烦Python 中的搜索后台换成 ElasticSearch,因为它也有免费版~

搜索引擎全流程

一个完善的搜索引擎不仅仅只有类似TF-IDF的算法,还有很多其他环节。从一个query(搜索问句)开始,包含了很多query预处理部分,比如分词,敏感词过滤, 纠错,拼音识别,查询改写,查询补全等等。再通过各种的召回策略,比如TF-IDF/ElasticSearch 召回,得到候选答案,最后再做一些业务层面的过滤处理, 才能到达你的搜索结果展示框里。所以看似一个小小的搜索引擎,实际上要包含很多大的工程项目。

search engine

降低知识传递的门槛

莫烦的对教育的态度是: 降低知识传递的门槛,不希望给"学习"设置金钱障碍。 这是我花大量业余时间贡献 免费 AI分享的原因。 通过 【赞助】 能及时让我看到你对 【莫烦态度】 的认同,我也更有理由坚持下去。

如果你当前目标是找工作或者转行AI,想接受更加丰富的教学资源、培训辅导体验,我想推荐我的朋友 七月在线 给你, 通过这个 【莫烦Python为你提供的注册链接】, 你将可以获得莫烦专门为你协商的课程优惠券。祝你找/换工作顺利~