利用面向对象思想实现搜索引擎

要想实现一个搜索引擎,首先要了解什么是搜索引擎。简单地理解,搜索引擎是一个系统,它可以帮助用户去互联网上搜集与其检索内容相关的信息。

通常,一个搜索引擎由搜索器、索引器、检索器以及用户接口组成,其中各个部分的含义如下:

1、搜索器:其实就是我们常说的爬虫、它能够从互联网中搜集大量的信息,并将之传递给索引器;

2、索引器:理解搜索器搜索到的信息,并从中抽取出索引项,存储到内部的数据库中,等待检索;

3、检索器:根据用户查询的内容,在已经建立好的索引库中快速检索出与之相关的信息,并做相关度评价,以此进行排序。

4、用户接口:其作用就是提供给用户输入查询内容的窗口(例如百度、谷歌的搜索框),并将检索好的内容反馈给用户。


由于爬虫知识不是本节学习的重点,这里不再做深入介绍,我们假设搜索样本就存在于本地磁盘中。为了方便,这里只提供五个用于检索的文件,各文件存放的内容分别如下:

# 1.txt
游民部落
# 2.txt
http://www.gamecolg.com
# 3.txt
「游民部落」是一个在线学习编程的网站,我们发布了多套文字教程,它们都通俗易懂,深入浅出。
# 4.txt
游民部落成立于 2012 年初,目前已经运营了将近 7 年,我们致力于分享精品教程,帮助对编程感兴趣的读者。
# 5.txt
坚持做好一件事情,做到极致,让自己感动,让用户心动,这就是足以传世的作品!

下面,根据以上知识,我们先实现一个最基本的搜索引擎:

class SearchEngineBase:
    def __init__(self):
        pass
    #搜索器
    def add_corpus(self, file_path):  
        with open(file_path, 'rb') as fin:
            text = fin.read().decode('utf-8')
        self.process_corpus(file_path, text)
    #索引器
    def process_corpus(self, id, text):
        raise Exception('process_corpus not implemented.')
    #检索器
    def search(self, query):
        raise Exception('search not implemented.')
#用户接口
def main(search_engine):
    for file_path in ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt']:
        search_engine.add_corpus(file_path)
    while True:
        query = input()
        results = search_engine.search(query)
        print('found {} result(s):'.format(len(results)))
        for result in results:
            print(result)

以上代码仅是建立了搜索引擎的一个基本框架,它可以作为基类被其他类继承,那么继承自此类的类将分别代表不同的搜索引擎,它们应该各自实现基类中的 process_corpus() 和 search() 方法。

整个代码的运行过程是这样的,首先将各个检索文件中包含的内容连同该文件所在的路径一起传递给索引器,索引器会以该文件的路径建立索引,等待用户检索。

在 SearchEngineBase 类的基础上,下面实现了一个基本可以工作的搜索引擎:

#继承SearchEngineBase类,并重写了 process_corpus 和 search 方法
class SimpleEngine(SearchEngineBase):
    def __init__(self):
        super(SimpleEngine, self).__init__()
        #建立索引时使用
        self.__id_to_texts = {}

    def process_corpus(self, id, text):
        #以文件路径为键,文件内容为值,形成键值对,存储在字典中,由此建立索引
        self.__id_to_texts[id] = text

    def search(self, query):
        results = []
        #依次检索字典中的键值对,如果文件内容中包含用户要搜索的信息,则将此文件的文件路径存储在 results 列表中
        for id, text in self.__id_to_texts.items():
            if query in text:
                results.append(id)
        return results

search_engine = SimpleEngine()
main(search_engine)

运行结果为:

游民部落
found 3 result(s):
1.txt
3.txt
4.txt

可以看到,用户搜索与“游民部落”有关的内容,最终检索到了 1.txt、3.txt和 4.txt 文件中包含与之相关的内容。由此,只需要短短十来行代码就可以实现一个基础的搜索引擎。