前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能优化大幅提升!Python 实现海量内容分词搜索引擎(3.0版)

性能优化大幅提升!Python 实现海量内容分词搜索引擎(3.0版)

作者头像
Wu_Candy
发布2022-12-06 20:57:44
7380
发布2022-12-06 20:57:44
举报
文章被收录于专栏:无量测试之道无量测试之道
1、前言

前期分享文章

仅30行代码,实现一个搜索引擎(1.0版)

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

分别介绍:

如何使用 30 行 Python 代码快速实现一个简易版搜索引擎;

通过对检索内容进行分词的升级版搜索引擎;

具体 Python 源码实现请点击上方链接阅读与获取。

缺陷:

1.0版本搜索引擎:仅支持单个词语的检索,当检索文件内容量大,文件个数多时检索效率低。

2.0版本搜索引擎:每次查询时都需要遍历所有文件及其内容,如果检索文件数量庞大,每次都全部遍历十分耗时。

2、优化思路

每次需要检索的单词数量不会很多,最多在十几,二十个左右,试着从这里着手优化呢?

在前面两个版本中,使用文件名作为 key,其内容作为 value 的格式存储于字典中,每次检索时需要遍历每个单词,再遍历每个单词是否在每个文件中。

如果把文件内容的每个单词作为 key,其出现在哪些文件中作为 value, 这样就可以只需程序第一次启动时进行全量文件内容的计算,得出一个结果字典。

以后每一次检索都只从结果字典中去查找遍历就好了,结果字典不需要随着每次检索而重新计算,又节省了一笔开销。(毕竟检索词库不会频繁更新)

这种 key,value 的处理方式也就是十分著名的搜索引擎方法——倒序索引

在检索时只需要将被检索的文本内容对应的 value 拿出来,然后再去寻找这些 value 之间共有的元素即文件名称,就能得到检索想要的结果。

思路梳理

思路清晰后,实现方式就不限了,这里我采用的是使用 Python 多个列表间求交集来实现,具体实现方式请参见下方的源码。

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


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

    def process_search_contents(self, file_path, content):
        """
        该函数实现功能:重写了父类的process_search_contents方法, 将每个文件对应的文件内容中每个单词作为key,
        该单词所出现在哪些文件中以append方式写入list作为value填充inverted_index字典。
        :param file_path: 完整路径下的文件名称,例如:/search_contents/1.txt
        :param content: 具体文件内容
        :return:
        """
        words = self.parse_text_to_words(content)  # 将每个文件对应的文本内容进行一定规则处理后返回无重复的单词set(集合)
        for word in words:
            """
            1、遍历set集合words,如果word作为key不存在于inverted_index字典中,
            则填充字典inverted_index的格式为:inverted_index = {'word':[]}
            
            2、然后再将words文本内容对应的文件名append至空[]中
            
            3、如果同一个word作为key,其value非空[],则'word not in self.inverted_index'条件不成立时直接
            将文件名append至已有的列表中,最终可能出现的数据格式为:
            inverted_index = {'a':['1.txt','2.txt'], 'b':['3.txt']}
            """
            if word not in self.inverted_index:
                self.inverted_index[word] = []
            self.inverted_index[word].append(file_path)

    def search(self, query_content):
        """
        :param query_content: 需要被检索的内容
        :return: 检索结果文件list
        """
        query_contents = list(self.parse_text_to_words(query_content))  # 将需要检索的文本内容进行一定规则处理后返回无重复的单词set(集合)并将其强转为list类型

        # 如果需要检索的文本内容(每个单词)只要有一个不存在于inverted_index字典的key中,则说明检索无结果,返回空list
        for query_content in query_contents:
            if query_content not in self.inverted_index:
                return []

        # 逻辑走到这里说明检索的单词作为key在词库inverted_index中有对应的value,即至少有一个文件中存在该key对应的检索单词
        query_key = []
        query_value = []
        for query_content in query_contents:
            query_key.append(query_content)
            query_value.append(self.inverted_index[query_content])
        query_result_dict = dict(zip(query_key, query_value))  # 将检索语句按照每个单词(key)及其所在的文件名(value为list类型)组装成字典

        result = []
        for v in query_result_dict.values():
            result.append(v)  # 将所有被检索单词对应的value(list类型)统一追加至result
        return list(reduce(lambda x, y: set(x) & set(y), result))  # 求result列表中多个小列表之间的交集,即是要求的最终结果list

    @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 = BOWInvertedModelEngine()
main(search_engine)

PS:

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

2.检索文件内容和被继承的基类SearchEngineBase实现代码都是和

仅30行代码,实现一个搜索引擎(1.0版)

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

这两篇文章中所使用的内容是一模一样的,本次只优化了继承父类的子类实现代码。

4、实现效果预览

至此,性能优化后的高阶版搜索引擎就完成了。

PS:

源码包中包含了1.0和2.0版本的实现代码和搜索样本文件,可以由简到难(1.0->2.0->3.0)对比核心代码的变化来体会优化思路。

本文参与?腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-28,如有侵权请联系?cloudcommunity@tencent.com 删除

本文分享自 无量测试之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、前言
  • 2、优化思路
  • 3、Python 核心代码实现
  • 4、实现效果预览
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com