短短几十行 Python 代码,实现分词功能搜索引擎(2.0版)

2022-12-06 20:47:42 浏览数 (1)

前言

前期分享的文章 仅30行代码,实现一个搜索引擎(1.0版) 中介绍了如何使用 30行 Python 代码来实现一个简易版的搜索引擎。

仔细阅读过这篇文章的小伙伴可能会产生一些疑虑,例如:

  1. 索引函数每次需要遍历所有文件,需要占用大量的时间和空间,当需被检索的文件及内容量比较大时,每次遍历检索的时间复杂度和空间复杂度就会相当高了。
  2. 检索的文本内容只支持单个单词,如果想一次检索多个词呢,且被检索的词分布在检索文件里的不同位置。

针对以上的疑虑,该如何进行优化呢?

最容易想到的就是将文件内容进行分词,也称语料分词,它的思想是将整个文件内容,按照一定规则处理后形成一个无重复单词的 set 集合,语料分词的做法可以大大提升存储和检索效率。

具体的 Python 代码实现请往下阅读。

Python 核心代码实现
代码语言:javascript复制
import re
from BaseEngine import SearchEngineBase, main


class BOWModelEngine(SearchEngineBase):
    def __init__(self):
        """
        1.super(BOWModelEngine, self).__init__()含义是指:对继承自父类的属性使用父类的初始化方法进行初始化。
        2.这里的__init__()括号里可以加上父类中初始化时定义的属性,因为此处父类初始化时没有定义任何属性,所以这里括号里为空。
        """
        super(BOWModelEngine, self).__init__()
        self.__file_path_to_content = {}  # 子类BOWModelEngine自定义的私有属性

    def process_search_contents(self, file_path, content):
        """
        该函数实现功能:重写了父类的process_search_contents方法,填充__file_path_to_content字典内容,
        key为文件名称,value为文件内容经过一定规则进行处理过的无重复的单词set。
        :param file_path: 完整路径下的文件名称,例如:/search_contents/1.txt
        :param content: 具体文件内容
        :return:填充__file_path_to_content字典内容
        """
        self.__file_path_to_content[file_path] = self.parse_text_to_words(content)

    def search(self, query_content):
        """
        该函数实现功能:重写了父类的search方法,返回检索文本中每个单词都出现在同一个文件的文件名称列表
        :param query_content:需要检索的文本
        :return:出现在哪些文件里的文件名称列表
        """
        query_words = self.parse_text_to_words(query_content)
        results = []
        for file_path, content in self.__file_path_to_content.items():
            if self.query_match(query_words, content):
                results.append(file_path)
        return results

    @staticmethod
    def query_match(query_words, content):
        """
        该函数实现功能:遍历parse_text_to_words函数返回的无重复的单词set,判断如果有一个单词不存在于当前文件中,则返回False,否则返回True
        :param query_words: 无重复的单词set
        :param content: 每个文件的具体内容
        :return: True&False
        """
        for query_word in query_words:
            if query_word not in content:
                return False
        return True

    @staticmethod
    def parse_text_to_words(content):
        """
        该函数实现功能:将检索文本内容进行一定规则处理后返回无重复的单词set(集合)
        :param content: 检索文本,例如:we will alive long
        :return: 无重复单词的集合,格式为:{'we','will','alive'}
        """
        content = re.sub(r'[^w ]', ' ', content)  # 使用正则表达式去除标点符号和换行符
        content = content.lower()  # 搜索文本全部转换为小写
        word_list = content.split(' ')  # 使用空格将文本内容进行分隔,生成所有单词的列表
        word_list = filter(None, word_list)  # 生成的单词列表再去除空白单词
        return set(word_list)  # 返回单词的set(无重复的集合), 格式为: {'we','will','alive'}


search_engine = BOWModelEngine()  # 实例化子类BOWModelEngine的对象
main(search_engine)

PS:

1.核心代码块中每个函数实现的功能都有详细的解释说明,请注意仔细阅读,这将非常有助于理解搜索引擎的执行流程和代码流的流转

2.检索文件内容和被继承的基类SearchEngineBase实现代码都是和 仅30行代码,实现一个搜索引擎(1.0版) 这篇文章中所使用的内容是一模一样的,本次只优化了继承父类的子类实现代码。

实现效果预览

至此,一个功能提升的进阶版搜索引擎就实现了,后续还会继续分享功能更加强大搜索引擎实现的高阶版,敬请关注~

0 人点赞