如何使用 Python 语言和 Laravel 框架创建自己的搜索引擎 - 第 3 步(共 4 步)

作者:微信公众号:【架构师老卢】
8-9 8:42
46

概述:图片:Shutterstock / 内置索引是一种 data structure 技术,允许您从数据库文件中快速检索记录。它基于执行索引所基于的相同属性。什么是基于索引的搜索引擎?Python 上基于索引的搜索引擎是一种依赖于存储在倒排索引中的数据来查找答案的搜索引擎。当用户输入搜索查询时,它将扫描适当的索引以显示最接近的匹配结果,而不是一一搜索整个文档列表集。An index 是一个只有两列的小表。第一列包含表的主键或候选键的副本。它的第二列包含一组指针,用于保存存储该特定键值的磁盘块的地址。在 中search engine applications,这称为倒排索引。什么是倒挂指数?倒排索引

索引是一种 data structure 技术,允许您从数据库文件中快速检索记录。它基于执行索引所基于的相同属性。

什么是基于索引的搜索引擎?

Python 上基于索引的搜索引擎是一种依赖于存储在倒排索引中的数据来查找答案的搜索引擎。当用户输入搜索查询时,它将扫描适当的索引以显示最接近的匹配结果,而不是一一搜索整个文档列表集。

An index 是一个只有两列的小表。第一列包含表的主键或候选键的副本。它的第二列包含一组指针,用于保存存储该特定键值的磁盘块的地址。

在 中search engine applications,这称为倒排索引。

什么是倒挂指数?

倒排索引是为方便搜索查询而构建的索引、数据结构或数据库索引 。它的工作原理是存储从文档列表的内容(如单词或数字)到其在文档列表中的位置的数据映射。使用已映射的单词或数字,搜索过程将比在整个文档lists中逐个搜索更快、更高效。

什么是查询?

查询或在搜索引擎中称为搜索查询的查询是基于用户在搜索引擎中输入的特定搜索词的查询,以满足他或她的信息需求。

这是使用搜索引擎发出的信息请求。每次用户在搜索引擎中输入一串字符并按“Enter”键时,都会进行搜索引擎查询。Web 应用程序将显示搜索查询结果

在 Python 中构建基于索引的搜索引擎的要求

你应该有:

  • python 3.x.x
  • 包管理器 PIP
  • 代码编辑器(在本教程中,我将使用 Visual Studio Code,可选)

需求包

  • Pickle Library: Pickle 是 Python 2 和 Python 3 上安装的默认模块。如果未找到 pickle 模块,请在终端中运行以下命令以安装此库:
pip install pickle-mixin

我们将使用 pickle 模块来保存我们的索引文件,并在调用查询时加载索引文件。Pickle 模块可用于将 Python 对象存储到文件中。有了这个函数,我们将使用 pickle 将我们的字典 Python 保存到文件中,从而让我们更快地读取文件。

有关 Python 的更多信息:使用 Python 的 PCA:教程

如何在 Python 中创建倒排索引

为了制作倒排索引,我们将使用 Python 的字典。字典会将术语保存为键,并将文档的分数保存为值。这样,我们可以保存每个单词的数据文档和评分文档

为此,我们将使用术语“频率 — 反密集频率 (TF-IDF)”技术来计算文档的分数。

TF-IDF 是一种用于查找句子含义并消除单词袋技术缺点的技术。单词袋技术适用于文本分类或帮助机器读取数字中的单词。

使用 TF-IDF 进行脚本索引

import re
import sys
import json
import pickle
import math

#Argumen check
if len(sys.argv) !=3 :
	print ("\n\\Use python \n\t tf-idf.py [data.json] [output]\n")
	sys.exit(1)


#data argumen
input_data = sys.argv[1]
output_data = sys.argv[2]


data = open(input_data).read()
list_data = data.split("\n")

sw = open("stopword.txt").read().split("\n")

content=[]
for x in list_data :
	try:
		content.append(json.loads(x))
	except:
		continue


# Clean string function
def clean_str(text) :
	text = (text.encode('ascii', 'ignore')).decode("utf-8")
	text = re.sub("&.*?;", "", text)
	text = re.sub(">", "", text)    
	text = re.sub("[\]\|\[\@\,\$\%\*\&\\\(\)\":]", "", text)
	text = re.sub("-", " ", text)
	text = re.sub("\.+", "", text)
	text = re.sub("^\s+","" ,text)
	text = text.lower()
	return text



df_data={}
tf_data={}
idf_data={}

i=0;
for data in content :
	tf={} 
	#clean and list word
	clean_title = clean_str(data['book_title'])
	list_word = clean_title.split(" ")
	
	for word in list_word :
		if word in sw:
			continue
		
		#tf term frequency
		if word in tf :
			tf[word] += 1
		else :
			tf[word] = 1

		#df document frequency
		if word in df_data :
			df_data[word] += 1
		else :
			df_data[word] = 1

	tf_data[data['url']] = tf


# Calculate Idf
for x in df_data :
   idf_data[x] = 1 + math.log10(len(tf_data)/df_data[x])

tf_idf = {}

for word in df_data:
	list_doc = []
	for data in content:
		tf_value = 0

		if word in tf_data[data['url']] :
			tf_value = tf_data[data['url']][word]

		weight = tf_value * idf_data[word]

		doc = {
			'url' : data['url'],
			'title' : data['book_title'],
			'image' : data['image-url'],
			'price' : data['price'],
			'score' : weight
		}

		if doc['score'] != 0 :
			if doc not in list_doc:
				list_doc.append(doc)
		
		
	tf_idf[word] = list_doc

# Write dictionary to file
with open(output_data, 'wb') as file:
     pickle.dump(tf_idf, file)

参数行脚本

if len(sys.argv) !=3 :
   print ("\n\nPenggunaan\n\ttf-idf.py [data.json] [output]\n")
   sys.exit(1)
input_data = sys.argv[1]
output_data = sys.argv[2]
data = open(input_data).read()
list_data = data.split("\n")
#load Stopword
sw = open("stopword.txt").read().split("\n")
content=[]
for x in list_data :
    try:
        content.append(json.loads(x))
    except: continue

在上面的代码中,我加载了我们在抓取过程中返回的数据,并输入了一个我们不用于索引的“停用词”术语。若要运行脚本,请键入以下命令:

python3 tf-idf.py <data_json> <index_name>

是我们在执行抓取过程时得到的data set,并且是此脚本的输出,使其成为索引文件。

清理字符串数据集

# Clean string function                       
def clean_str(text) :                        
    text = (text.encode('ascii', 'ignore')).decode("utf-8")
    text = text.lower()                   
    text = re.sub("&.*?;", "", text)                        
    text = re.sub(">", "", text)                            
    text = re.sub("[\]\|\[\@\,\$\%\*\&\\\(\)\":]", "", text)               
    text = re.sub("-", " ", text)                        
    text = re.sub("\.+", "", text)                        
    text = re.sub("^\s+","" ,text)                        
                          
    return text

顾名思义,此函数的作用是从无用标点符号产生的数据集中清除book_title。

如何计算 TF-IDF

您应该了解三个术语:

  • **术语频率 (TF):**这是所有文档的术语频率。
  • **文档频率 (DF):**这是特定文档的术语频率。
  • **反向文档频率 (IDF):**这是您使用公式计算 DF 得出的值: IDF =Log[(# Number of documents) / (Number of documents containing the word (DF))]

使用这种 TF-IDF 技术,我们可以获得每个单词相对于文档的权重。每个单词的权重就是我们将用作分数值的权重。获得此权重的公式为:WEIGHT = TF * IDF

将索引保存到文件

with open(output_data, 'wb') as file:
   pickle.dump(tf_idf, file)

此代码用于使用 pickle 模块将字典保存到文件中。

制作查询脚本

将创建的查询脚本必须能够读取存储在早期文件中的字典。当然,如果你使用 pickle 模块保存了它,那么我们将使用 pickle 模块来读取它。

import re
import sys
import json
import pickle

#Argumen check
if len(sys.argv) != 4 :
	print ("\n\nPenggunaan\n\tquery.py [index] [n] [query]..\n")
	sys.exit(1)

query = sys.argv[3].split(" ")
n = int(sys.argv[2])

with open(sys.argv[1], 'rb') as indexdb:
	indexFile = pickle.load(indexdb)

#query
list_doc = {}
for q in query:
	try :
		for doc in indexFile[q]:
			if doc['url'] in list_doc :
				list_doc[doc['url']]['score'] += doc['score']
			else :
				list_doc[doc['url']] = doc
	except :
		continue


#convert to list
list_data=[]
for data in list_doc :
	list_data.append(list_doc[data])


#sorting list descending
count=1;
for data in sorted(list_data, key=lambda k: k['score'], reverse=True):
	y = json.dumps(data)
	print(y)
	if (count == n) :
		break
	count+=1

如何运行查询脚本

要运行此脚本,只需在终端中键入以下命令:

python3 query.py <index_file> <n-query> <string-query>

<index_file>是我们之前在 pickle 模块中创建的index_file。

<n-query>是我们想要显示的结果数。

<string-query>是用户所需信息的关键字。

如何加载索引文件

with open(sys.argv[1], 'rb') as indexdb:
   indexFile = pickle.load(indexdb)

使用 pickle 模块读取文件字典并不需要很长时间。我们甚至可以使用 pickle 模块编写索引。

如何计算文档对查询的分数

我们在索引上得到的分数不能作为排名参考,因为我们制作的索引只包含一克单词。因此,由多个单词组成的短语不能固定在索引的分数上。

为了解决这个问题,我们将对查询中的单词进行划分,并计算每个查询单词的分数。

for q in query:
   try :
      for doc in indexFile[q]:
          if doc['url'] in list_doc :
              list_doc[doc['url']]['score'] += doc['score']
          else :
              list_doc[doc['url']] = doc
    except :
          continue

如何对查询结果进行排名

要进行排名,我们只需要根据最高分对搜索结果进行排序。

源代码获取:公众号回复消息【code:64477

相关代码下载地址
重要提示!:取消关注公众号后将无法再启用回复功能,不支持解封!
第一步:微信扫码关键公众号“架构师老卢”
第二步:在公众号聊天框发送code:64477,如:code:64477 获取下载地址
第三步:恭喜你,快去下载你想要的资源吧