Python 核心技术与实战
景霄
Facebook 资深工程师
114324 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 47 讲
开篇词 (1讲)
Python 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

12 | 面向对象(下):如何实现一个搜索引擎?

BOWInvertedIndexEngineWithCache
LRUCache
BOWInvertedIndexEngine
BOWEngine
SimpleEngine
SearchEngineBase
面向对象搜索引擎

该思维导图由 AI 生成,仅供参考

你好,我是景霄。这节课,我们来实现一个 Python 的搜索引擎(search engine)。
承接上文,今天这节课的主要目的是,带你模拟敏捷开发过程中的迭代开发流程,巩固面向对象的程序设计思想。
我们将从最简单最直接的搜索做起,一步步优化,这其中,我不会涉及到过多的超纲算法,但不可避免会介绍一些现代搜索引擎中的基础概念,例如语料(corpus)、倒序索引(inverted index)等。
如果你对这方面本身有些了解,自然可以轻松理解;即使你之前完全没接触过搜索引擎,也不用过分担心,我会力求简洁清晰,降低学习难度。同时,我希望你把更多的精力放在面向对象的建模思路上。

“高大上”的搜索引擎

引擎一词尤如其名,听起来非常酷炫。搜索引擎,则是新世纪初期互联网发展最重要的入口之一,依托搜索引擎,中国和美国分别诞生了百度、谷歌等巨型公司。
搜索引擎极大地方便了互联网生活,也成为上网必不可少的刚需工具。依托搜索引擎发展起来的互联网广告,则成了硅谷和中国巨头的核心商业模式;而搜索本身,也在持续进步着, Facebook 和微信也一直有意向在自家社交产品架设搜索平台。
关于搜索引擎的价值我不必多说了,今天我们主要来看一下搜索引擎的核心构成。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何使用面向对象的程序设计思想来实现一个简单的Python搜索引擎。文章首先介绍了搜索引擎的核心构成,包括搜索器、索引器、检索器和用户接口,并解释了它们的功能和作用。接着,文章展示了一个基础的搜索引擎实现,通过继承SearchEngineBase基类,实现process_corpus和search接口,以及使用SimpleEngine子类来实现搜索功能。作者还提出了对这种简单实现方式的低效性和局限性,并提出了优化思路,即对语料进行分词处理,以提升存储和搜索效率。 随后,文章介绍了词袋模型(Bag of Words)和倒序索引(Inverted Index)的搜索模型。通过代码示例展示了如何实现这两种模型,并对它们的优缺点进行了讨论。特别是倒序索引模型的实现,通过对单词建立倒序索引,大大提高了搜索效率,避免了遍历所有ID的尴尬局面。 最后,文章讨论了缓存和多重继承的内容。通过引入LRU缓存和多重继承的方式,对搜索引擎进行了性能优化,提高了重复性搜索的效率。 整体而言,本文通过清晰的代码示例和解释,帮助读者了解了搜索引擎的基本原理和面向对象的程序设计思想,并引发了对搜索引擎实现的优化思考。文章内容涵盖了搜索引擎的基本原理、优化方法以及性能提升的实现方式,对于想要深入了解搜索引擎实现和优化的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Python 核心技术与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(88)

  • 最新
  • 精选
  • Jingxiao
    置顶
    思考题答案: John Si 的评论说的很对,如果想要强行访问父类的私有类型,做法是 self._ParentClass__var,这是非常不推荐的 hacky method。以下是示范代码: class A: __a = 1 class B(A): pass b = B() print(b._A__a)
    2019-06-09
    3
    30
  • 小侠龙旋风
    和面向对象无关的关键词整理: 1.一个搜索引擎由搜索器、索引器、检索器和用户接口四个部分组成。 2.Bag of Words Model,词袋模型。 3.Inverted Index Model,倒序索引。 4.语料corpus分词,齐夫定律。 5.合并 K 个有序数组。 6.LRU缓存。 难点消化:4,5,6 思考题: Python并没有真正的私有化支持,但可用下划线得到伪私有: (1)_xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量,需通过类提供的接口进行访问; (2)__xxx 类中的私有变量/方法名,只有类对象自己能访问,连子类对象也不能访问到这个数据。 (3)__xxx__ 魔法函数,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__() 代表类的构造函数。

    作者回复: 👍

    2019-06-08
    2
    44
  • shiziwen
    第二种方法,对于多重继承,如果有多个构造函数需要调用, 我们必须用传统的方法LRUCache.__init__(self) 。 这里的两句话没有很明白,LRUCache为什么必须使用第二种方法?

    作者回复: super().__init__() 只能调用第一个父类的构造函数,但对于多重继承,如果你想调用其他父类的构造函数,则必须指定。

    2020-04-04
    5
    18
  • 及時行樂
    看到这,我发现我五十元买的课程简直血赚!!!看条评论说看不懂不睡觉,建议你善良删除,我直接被你搞的睡衣全无,感觉能战到天亮

    作者回复: 哈哈谢谢支持

    2020-04-29
    2
    8
  • 头像我老婆
    class BOWInvertedIndexEngineWithCache(BOWInvertedIndexEngine, LRUCache): def __init__(self): super(BOWInvertedIndexEngineWithCache, self).__init__() LRUCache.__init__(self) 老师,这里这2种调用父类构造方法不应该是二选一吗,如果这样写的话LRUCache的构造方法会被调用2次 class A(): def __init__(self): print('enter A') print('leave A') class B(A): def __init__(self): print('enter B') super().__init__() print('leave B') class C(A): def __init__(self): print('enter C') super().__init__() print('leave C') class D(B, C): def __init__(self): print('enter D') super(D,self).__init__() C.__init__(self) print('leave D') D() 输出结果: enter D enter B enter C enter A leave A leave C leave B enter C enter A leave A leave C leave D

    作者回复: 事实上,你的例子(菱形继承)中确实会出现这个问题,但是如果你再读仔细一些,我的代码等价于: class A(): def __init__(self): print('enter A') print('leave A') class B(A): def __init__(self): print('enter B') super().__init__() print('leave B') class C(): def __init__(self): print('enter C') # super().__init__() print('leave C') class D(B, C): def __init__(self): print('enter D') super(D, self).__init__() C.__init__(self) print('leave D') D() 输出: enter D enter B enter A leave A leave B enter C leave C leave D 不会出现重复 init

    2020-03-22
    3
    7
  • quanxyun
    Python并没有真正的私有化支持,但可用下划线得到伪私有: (1)_xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量,需通过类提供的接口进行访问; (2)__xxx 类中的私有变量/方法名,只有类对象自己能访问,连子类对象也不能访问到这个数据。 (3)__xxx__ 魔法函数,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 __init__() 代表类的构造函数。

    作者回复: 👍

    2019-11-14
    3
  • 响雨
    私有属性不可以被继承,但是可以创建一个普通的方法,在方法中操作私有属性。因为普通的方法是可以操作的。

    作者回复: 嗯嗯

    2019-06-25
    2
  • Claywoow
    老师可以拓展一下元类吗,它是面向对象编程中一个重要的类型吗?

    作者回复: metaclass 作为独立的一章会出现在进阶课程中,敬请期待

    2019-06-08
  • 益达
    看不懂不睡觉
    2019-06-05
    9
    76
  • Wing·三金
    思考题:子类继承父类私有变量的方法 - 通过定义 get/set 函数来间接操作私有变量 - 通过 实例名._父类名__私有变量名 来直接调用,所以事实上 python 并不直接私有变量 # 主要知识点 - 搜索引擎的四个组成部分 - 迭代开发的流程 - 类的继承与父类函数的强行调用 - 词袋模型 + 逆序索引 + 合并有序数组 = 优化检索速度 + 考虑单词顺序与间隔 - pylru 的基本用法 - 多重继承的初始化规则 # 搜索引擎 - 搜索器:相当于爬虫 - 索引器:为每个文件/网页建立唯一的索引 - 检索器:高效地检索并返回匹配的文件/网页 - 用户接口:输入框和结果返回界面 # 迭代开发的流程 - 构建一个通用的基本框架 - 从最简单的情况考虑起,搭建一个能运行的极简版本 - 按照实际需要不断对具体的实现过程进行优化:如在本讲的例子中,先考虑了单个搜索词 + 小搜索量的情况,构建了 ver 1;然后考虑了多个搜索词,构建了词袋的 ver 2;再考虑了大搜索量,构建了词袋 + 逆序索引的 ver 3(提了 搜索词排序与间隔 情况下的处理思路);最后考虑了负载与重复性搜索问题,构建了使用 LRU 缓存策略的 ver 4 - 如果回过头来看最初的框架,还能发现 add_corpus 的方法并不适用于文件较大的情况,结合前面第六讲的内容可以做些改进;以及 main 函数直接用了 for 循环来找所有的文件,实际使用时用的是诸如 os.walk 的方法
    2019-06-05
    1
    65
收起评论
显示
设置
留言
88
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部