架构设计
下面是一个简单的搜索引擎的架构设计,包含了主要的组件和它们之间的关系。
该搜索引擎架构包括以下组件:
用户界面:这是用户与搜索引擎交互的部分,用户输入查询关键词,并通过用户界面得到搜索结果。
查询处理器:这是搜索引擎的核心组件,负责处理用户查询,将其转化为可执行的搜索操作,并向下游组件发送搜索请求。
索引器:负责维护搜索引擎的索引数据库,将文本文档转换为可搜索的数据结构。当查询处理器发出搜索请求时,索引器会使用索引数据库返回匹配的文档。
排名器:对于给定的查询,排名器根据相关性对搜索结果进行排序,以便向用户呈现最相关的结果。
爬虫:负责从互联网上收集文档,并将它们发送到索引器进行处理。
数据存储:用于存储索引数据库和其他搜索引擎数据的数据存储系统。
这个架构也可以进一步扩展和优化,例如可以添加负载均衡器来处理高流量,也可以使用分布式存储系统来处理大规模的索引数据库。
任务简化和需求分析
我们的目标是基于python实现核心的搜索功能,那么可以再对上面的架构再进行简化。首先从需求层面需要实现如下的功能:
1.我们实现的是搜索的核心功能,用户可以通过搜索函数的调用来获取搜索的结果(但这里我们不实现用户界面);搜索的字符串 - > 匹配的文本文件,并给出位置?
2.搜索的对象是多个文本文件,我们通过关键词的查询,匹配到最合适的结果并返回。那么如何匹配,我们常用的做法就是倒排索引。
3.关键词中的每个字都要进行匹配,对于索引出来的结果,需要整合和排名。
4.在引擎工作之前,我们需要先对所有的文档构建出索引。
5.选取合适的数据结构和存储技术,对索引进行存储。
技术上来说,需要实现:
- 搜索引擎类 simpleTxtSearchEngine
- 初始化方法,并在其中调用索引构建/更新;如果有持久化的操作,需要打开数据库进行相关操作;
init / prepareIndex(倒排索引) / updateIndex / prepareIndexFromDB … - 监听搜索动作,在发生时调用搜索 startSearch
- 提供 startSearch 所需要的 match 和 sort 等操作。
基于以上的步骤,开发、测试和联调,并迭代功能,提升性能。
编码
python hints:
@abstractmethod 装饰器语法,修饰抽象函数
_init_ 类构造函数,前后各加了双下划线。
__开头的属性是私有属性
类函数 @classmethod
def create_empty_book(cls, title, author):
return cls(title=title, author=author, context=‘nothing’)
raise Exception(‘get_context_length not implemented’) // 抛出异常。
第一个版本的代码实现如下(纯英文):
from abc import abstractmethod, ABCMeta, ABC
import os
class SearchEngineBase(ABC):
def __init__(self):
print('base')
@abstractmethod
def prepareIndex(self, dir):
pass
@abstractmethod
def startSearch(self, queryWords):
pass
class SearchEngineSimple(SearchEngineBase):
def __init__(self, dir):
super().__init__()
self.dir = dir
self.fileContents = {}
def prepareIndex(self):
#读取文本信息
for filename in os.listdir(self.dir):
if filename.endswith(".txt"):
with open(os.path.join(self.dir, filename), "r") as file:
content = file.read()
print(content)
# 对读取的内容进行处理
# 可以将内容存储到一个列表或字典中
self.fileContents[filename] = content
print(self.fileContents)
def startSearch(self, queryWords):
results = []
# 遍历文件,查找关键字是否包含在其内。 返回命中的文件索引。
for filename, content in self.fileContents.items():
if queryWords in content:
results.append(filename)
return results
执行代码:
if __name__ == '__main__':
simpleEngine = SearchEngineSimple("/Users/guanzhenwei/Desktop/pyTest/searchEng/")
simpleEngine.prepareIndex()
while True:
query = input()
print(query)
results = simpleEngine.startSearch(query)
print("matched files=" + ", ".join(results))
最新版本实现如下(基于倒排索引):
from abc import abstractmethod, ABCMeta, ABC
import os
import re
class SearchEngineBase(ABC):
def __init__(self):
print('base')
@abstractmethod
def prepareIndex(self, dir):
pass
@abstractmethod
def startSearch(self, queryWords):
pass
@staticmethod
def textToWords(text):
# 使用正则表达式去除标点符号和换行符
text = re.sub(r'[^\w ]', ' ', text)
# 转为小写
text = text.lower()
# 生成所有单词的列表
word_list = text.split(' ')
# 去除空白单词
word_list = filter(None, word_list)
# 返回单词的 set, set自动去重。
return set(word_list)
@staticmethod
def queryMatch(queryWords, words):
queryWordList = SearchEngineBase.textToWords(queryWords)
rtn = True
for queryWord in queryWordList:
if queryWord not in words:
rtn = False
break
return rtn
# 这里的搜索是match,有顺序
class SearchEngineSimple(SearchEngineBase):
def __init__(self, dir):
super().__init__()
self.dir = dir
self.fileContents = {}
def prepareIndex(self):
# 读取文本信息
for filename in os.listdir(self.dir):
if filename.endswith(".txt"):
with open(os.path.join(self.dir, filename), "r") as file:
content = file.read()
print(content)
# 对读取的内容进行处理
# 可以将内容存储到一个列表或字典中
self.fileContents[filename] = content
print(self.fileContents)
def startSearch(self, queryWords):
results = []
# 遍历文件,查找关键字是否包含在其内。 返回命中的文件索引。
for filename, content in self.fileContents.items():
if queryWords in content:
results.append(filename)
return results
# 这里的搜索是基于简单的词袋模型,无顺序。例如 character their 也会命中,原文中是 their character。
class SearchEngineV2(SearchEngineBase):
def __init__(self, dir):
super().__init__()
self.dir = dir
self.fileWordSets = {} # key为文件名, value为内容分解后的词集合。
def prepareIndex(self):
#读取文本信息
for filename in os.listdir(self.dir):
if filename.endswith(".txt"):
with open(os.path.join(self.dir, filename), "r") as file:
content = file.read()
tempSet = self.textToWords(content)
# 对读取的内容进行处理
self.fileWordSets[filename] = tempSet
print(self.fileWordSets)
def startSearch(self, queryWords):
results = []
# 遍历文件,查找关键字是否包含在其内。 返回命中的文件索引。
for filename, fileWordSet in self.fileWordSets.items():
if self.queryMatch(queryWords, fileWordSet):
results.append(filename)
return results
# todo: 倒排索引和缓存。
# further: 支持中文分词,中英文混排和搜索。
class SearchEngineV3(SearchEngineBase):
def __init__(self, dir):
super().__init__()
self.dir = dir
self.wordIndexSets = {} # key为词, value为所在文件的集合。
def prepareIndex(self):
#读取文本信息
for filename in os.listdir(self.dir):
if filename.endswith(".txt"):
with open(os.path.join(self.dir, filename), "r") as file:
content = file.read()
tempFileWordsSet = self.textToWords(content)
for word in tempFileWordsSet:
tempSet = self.wordIndexSets.get(word)
if tempSet:
tempSet.add(filename)
else:
tempSet = set()
tempSet.add(filename)
self.wordIndexSets[word] = tempSet
print(self.wordIndexSets)
def startSearch(self, queryWords):
results = []
# 对queryWords进行分词。
queryWordList = self.textToWords(queryWords)
interSet = set()
for queryWord in queryWordList:
matchSet = self.wordIndexSets.get(queryWord)
if not matchSet:
return []
else:
interSet = matchSet
for queryWord in queryWordList:
matchSet = self.wordIndexSets.get(queryWord)
interSet.intersection_update(matchSet)
return interSet
增加lrucache的版本:文章来源:https://www.toymoban.com/news/detail-754830.html
class LRUCache(object):
def __init__(self, size=32):
self.cache = pylru.lrucache(size)
def has(self, key):
return key in self.cache
def get(self, key):
return self.cache[key]
def set(self, key, obj):
self.cache[key] = obj
class SearchEngineV3WithCache(SearchEngineV3, LRUCache):
def __init__(self, dir):
SearchEngineV3.__init__(self, dir)
LRUCache.__init__(self)
def startSearch(self, queryWords):
if self.has(queryWords):
print('hit cache!')
return self.get(queryWords)
else:
result = SearchEngineV3.startSearch(self, queryWords)
self.set(queryWords, result)
return result
以上主要展现了python oop编程的思想和简单应用,可以看到python的灵活和强大。文章来源地址https://www.toymoban.com/news/detail-754830.html
到了这里,关于一个基于python的文本搜索引擎的设计和实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!