CS 582信息检索课程的最终项目
要从终端运行程序,只需使用命令:
python main.py
提供了一份报告,以更好地解释搜索引擎的功能和UI,请参考:
report.pdf
该文档是伊利诺伊大学芝加哥大学CS 582信息检索最终项目的报告。该项目包括从头开始为UIC域构建Web搜索引擎。该软件是模块化构建的,从网络爬行开始,浏览页面预处理,索引并最终添加图形用户界面。此外,我们发明的定制的“智能”组件是必需的。
我决定通过使用基于伪重复反馈方法的查询扩展来实验搜索引擎优化,该方法试图从用户的查询中获取广泛的上下文,我称其为上下文pseudo-rewance反馈( CPRF )。这应该已经为搜索引擎添加了两种改进类型:
不要仅将所有结果集中在查询中的单词上,而是将各种和相关的内容包括到检索到的页面集。
扩大结果总数,包括不包含查询中存在任何单词的网页,但由于处理同一主题,因此仍然可能对用户感兴趣。
页面排名实现也已集成,可以从应用程序UI打开或关闭。有关两个智能组件的更多详细信息,请稍后在本文档中找到。
可以通过GitHub访问包含该软件的存储库:
https://github.com/mirkomantovani/web-search-engine-uic
该软件是用Python3以面向对象的编程方式编写的,以使其在未来易于扩展。 In order to make it easy to download and test the code without having to perform an extensive and time-consuming crawling and page preprocessing, the dataset containing 10000 pages crawled from the UIC domain: https://www.uic.edu/, and the preprocessed pages and needed files generated (Inverted Index, TF-IDF scores, Page Ranks, Document lengths, documents' tokens, URL)包含在存储库中。这样,通过克隆存储库可以运行main.py ,并且在不到一秒钟的时间内,搜索引擎就可以在输入中获取查询。但是,在以下所有其他组件的小节中还包括并解释了运行爬网和预处理的脚本。
可以通过执行脚本MultineReaded_crawling.py来完成网络爬行,通过使用队列模块以同步的方式访问资源,可以同时进行爬行,可以通过在同一脚本中修改整体常数thread_number的线程数量,但是,默认情况下,crawement and crawneck and Internet and crawneck and Internet and tose note note note note note and the Internect and the Internect and the Internect and with note and bate and the Internet。
爬行从UIC CS子域开始:https://www.cs.uic.edu/在MultiThreaded_crawling.py脚本中指定。
爬行是通过广度优先的策略发生的,每个页面都使用HTMLPARSER库脱水,下载和解析,其链接被提取并检查为属于UIC域,然后将其添加到FIFO队列中,如果是适当的形式。所有不良格式的黑名单是由我得出的,同时看到了我在爬行中得到的结果,并以这种18种格式组成:“ .docx”,“ .doc”,“ .avi”,“ .mp4”,“ .jpg”,“ .jpg”,“ .jpeg”,.jpeg“ .jpeg”,“ .png”,.png“ .png”,“ .gif”,“ .gif”,“ .pdf”。 “ .tgz”,“ .zip”,“ .exe”,“ .js”,“ .css”,“ .ppt”。 10秒钟的超时将指定为下载页面并传递到下一页之前下载页面的最大时间。
提取它们后也修改了URL,每个最初的HTTP变成https,消除了末端的所有砍伐,查询字符串被删除,并且还删除了由哈希符号(#)表达的页面内链接,以便不让crawler相信更多的页面具有不同的页面,并且不同的是不同的页面,请与众不同。此外,通过在关闭HREF之前打开<a>标签的链接的处理,并通过在字符串中另一个标签“ <”打开的链接完成内部打开内部。
在爬网期间,将两个词典,来自代码的URL和来自URL的代码的URL经常保存到磁盘以后在以后使用,网页的代码是按时间顺序排列的下载页面的数量。
可以从run_preprocessing.py脚本执行爬行页面的预处理,您还可以通过更改相应的常数page_rank_max_iter和n_pages来指定要考虑的页面数量和页面排名的最大迭代次数。
在预处理过程中,使用Preprocess.py脚本的定制对象。首先在<script>和<style>中首先获取纯文本,从而对每个页面进行预处理。在此步骤中,我决定使用一个非常快速的库: SelectOlax ,这是使用C. Cpython编写的适度引擎的Python API,当然,相对于任何用纯Python编写的HTML Parses,计算时间中至少提供了一个数量级。然后,该页面被令牌化,使用NLTK使用Porterstemmer来驱动令牌,使用文件optwords.txt中提供的停止字的列表消除了停止字词,删除了数字,并且不考虑3个字母的单词。
在预处理中,构建了倒置索引,并且每个单词doc对的TF-idf计算并存储在倒置索引中。还创建了有向的Web图( Graph.py ),并将其输入到Page_rank.py中的页面排名的实现。然后,以后回答查询所需的所有文件将作为二进制文件保存。
预处理预处理和10000页的PAGE_RANK收敛所需的总时间约为236秒,页排名运行时间仅为11秒。
main.py脚本包含搜索引擎的访问点。启动程序时,创建了一个定制对象来引导查询,而是实例化tfidfranker对象,以根据查询对文档进行排名。
当基于用户查询对文档进行排名时,最多考虑100个文档,此常数可以在main.py中更改。
用户界面是图形的,并使用Python软件包:EasyGui实现。 GUI是一个可扩展的模块, customgui.py ,包含该程序基本功能的主要API。
当程序启动时,询问用户的基本设置,他是否要使用页面排名和上下文伪重复反馈。之后,出现主菜单。主菜单显示了搜索引擎的当前设置以及一些可以执行的主要操作的按钮。可以通过从主菜单中选择适当的按钮在运行时动态更改设置。其他两个选择是:退出程序并运行查询。如果用户按下按钮创建新查询,则会出现一个新窗口,并提示用户插入新查询。当他点击还可以时,查询将进行预处理,并对文档进行排名,并且将显示前10个文档(程序中的变量)文档以及有关预处理查询的信息以及如果伪优惠的反馈(如果打开),则可能是扩展的令牌。现在,用户可以双击结果打开页面上的页面上的新选项卡上的默认浏览器浏览器的新选项卡,也可以递归地按列表末尾的“显示更多结果”,以显示10个结果。此外,如果伪相关反馈的反馈已经关闭,则还可以使用户在扩展中重新汇总相同的查询。
运行查询并决定取消或打开结果后,将用户提示回主菜单,在那里他可以更改设置和/或运行新的查询或具有不同设置的同一查询,以将结果与先前获得的结果进行比较。
我在该项目开发过程中遇到的主要挑战是:
最初,选择要设计哪种智能组件确实很难。我在这种类型的应用程序上都没有经验,并且在没有演示测试的情况下考虑改进是如此困难。
在实施部分期间,我花了很多时间在了解我尚不知道的Python库和构造上,例如线程,如何实现或进行网络刮擦以将链接从HTML页面中获取。我必须从头开始学习的另一件事是如何在Python创建GUI。
一个烦人的事情是,我不得不多次爬行10000页,因为我以各种和错误的格式发现。最后,我必须黑名单的整个格式列表的大小为18个,其中包括“ .docx”,“ .doc”,“ .avi”,.mp4“,” .jpg“,” .jpeg“,” .jpeg”,“ .png”,“ .png”,“ .png”,“ .gif”,“ .gif”,“ .pdf”,“ .pdf” .pdf“ .pdf”,“ .gz”,“ .rar”,“ .rar”。 “ .exe”,“ .js”,“ .css”,“ .ppt”。
一个非常具有挑战性的是,超参数调整和页面排名的集成对文档进行排名。决定对扩展查询的代币进行多少重要性的参数“ E ”是最难调整的,因为如果您没有标记数据(每个查询的相关文档),则无法知道搜索引擎的平均性能。另外,查询相关性是主观的,您永远不知道一个人想要检索什么,并且只能根据查询进行猜测。我认为e最多应为0.5,最后我将其设置在0.1-0.2左右,您不想通过对未由用户键入的单词非常重要来偏向于疑问。
我使用的加权方案是文档中简单的单词的简单tf-idf,因为它被证明是Web搜索引擎最有效的一种,并且以正确的方式说明了每个文档中单词的重要性。我什至没有考虑尝试另一种措施,只是因为这不是该项目的目的,而且似乎效果很好。
用于对文档进行排名的相似性度量是余弦相似性。我从内部产品的相似性开始实现,然后切换到这只是更改一行代码的问题。我认为余弦相似性最好使用,因为它考虑了文档的长度和查询长度。它更为复杂,通常在这种类型的应用程序中效果很好,因此选择相似性度量并不是真正的问题,我只是知道余弦相似性是正确的。
我对我提出的一些随机和多样的查询进行了对10的评估(仅考虑了前10个结果)。这是结果:
查询: “顾问论文”,第一个结果是https://grad.uic.edu/electronic-thesis-dissertation-faqs,我认为所有结果都与论文和相关性有关,我将给出一个精度: p = 1.0与此查询。
查询: “职业博览会”,第一个结果是https://ecc.uic.edu/career-fairs,我认为所有结果都与职业博览会,职业服务,活动,活动和就业有些相关,我将精确: P = 1.0与此查询。
查询: “研究助手”,第一个结果是http://grad.uic.edu/assistanthips,我认为除最后一个与助手有关的是RA,TA或GA,仅仅是因为UIC域没有RA的特定页面,所以我将提供精确的: P = 0.9 to to to to to to to to to ie ceery。
查询: “实习和工作”,第一个结果是https://careerservices.uic.edu/students/internships,这次只有6个网页是相关的,但是,这些网页仍然与职业和就业无关。我将给出一个精度: p = 0.6对此查询。
查询: “学生中心东地址”,第一个结果是https://fimweb.fim.uic.edu/buildingsdata.aspx,此查询更加具体,更复杂,实际上只有从4个结果中,我们实际上能够提取建筑物的地址,但是所有其他结果,但是所有其他结果,都在谈论East的学生中心,这仍然不是那样。我将给出一个精度: p = 0.4对此查询。
平均精度为0.78 ,每个查询至少返回一个相关结果的事实,我认为结果是离散的。
我尝试的第一个智能是简单而简单的页面排名。在对页面的预处理进行预处理时,提取了链接,并基于创建世界图的链接连接。页面排名的实现使其与整个图创建了一个强烈的组件,这意味着从每个节点可以从每个节点中获得具有非null概率的另一个节点。通过这种解释,随机步行者不可能被卡在页面中。
页面排名很难集成到文档的评分中以对其进行排名。首先,我尝试仅将余弦相似性和页面排名的线性组合进行线性组合,看看它是如何工作的,这很糟糕,因为如果页面排名的重量远远超过主页和其他权威页面,那么结果总是会出现在结果中。相反,如果重量更倾向于余弦相似性,那么页排名根本就不会产生效果。
第二次尝试产生了相当不错的结果。我基本上只是仅使用了所有其他结果,并认为他们是非与之相关的。然后,我将线性组合与页面排名进行。这次之所以起作用,是因为它只是已经相关文档的不同置换,例如,本主页和其他权威文件目前已经被丢弃。
我认为,在这种类型的应用程序中,页面排名的目的是实现的,我能够偏向正常的搜索,以考虑更相关的更具权威的页面,以便用户更有可能找到与他在查询中类型的结果相似的结果之外,除了结果非常相似。
上下文伪重复反馈( CPRF ),我想出了我的原理和自定义智能组件的想法,将近一个月以来。当我实施时,我不确定它是否会按预期工作,我真的很害怕我无所事事。
当我想到网络搜索引擎可以拥有哪种智能组件时,我认为如果我们能猜测用户查询的上下文并给予他除了他专门要求的内容外,那将是很好的,这些结果与他所搜索的内容非常相关。基于同义词的简单静态查询扩展将太简单,无法捕获相关但具有不同语义的内容。
但是,起点总是必须是用户的查询,因为除了最初,别无其他。我真的很喜欢伪交易反馈如何让您以自动方式重新重新查询的想法。当然,当询问用户要在他的查询中包含哪些其他单词时,明确的相关性反馈可能会更好,但是与此同时,他在搜索时必须回答一些问题可能会很烦人。伪交易反馈似乎是一种更合适,更简单的方法,可以在后台运行一些更复杂的查询,甚至不知道。
为了提取一些可以表达公式查询的上下文的单词,我决定使用一些最初检索文档的固有信息。特别是,我认为文档中具有最高tf-idf的单词可以代表该文档的主题,及其与其他文档的区别,因为当许多文档中没有包含该单词时,TF-IDF很高,但该文档中的复发是很高的。
提取上下文单词的过程如下:从排名的文档中,我选择了number_docs_expansion文档,我将其设置为30,但可以在pseudo_relevance_feedback.py中更改。 ,对于每个文档,我将带有最高tf-idf(常数number_top_tokens)的令牌和对于其中的每个不同令牌所示,如果存在单词,则将每个文档的所有tf-idf总结。最后,我对令牌进行排名,排名最高的单词是代表查询上下文的每个检索文档的常见单词。然后,我返回n个扩展的单词(常数number_expansion_tokens)设置,将原始的查询令牌减去,以免重复重复,并且对这些单词赋予了过多的重要性。
扩展的令牌将具有差异的重量,少于查询中的原始单词,可以在statistics.py脚本中更改此e_const。
根据我尝试的查询,我认为智能组件在某些情况下确实给出了一些改进。
始终有效的第一个重要结果是能够扩展检索到的文档的集合,实际上,如果只有几个文档包含查询中的任何单词,则普通搜索引擎只能检索那些文档。取而代之的是,使用CPRF SMART组件,结果集将更大,并且可能始终导致检索到的尺寸超过100个文档。
我在某些查询中注意到的另一个积极结果是,它实际上找到了我要寻找的目的,而简单的搜索引擎甚至没有在前十个结果中找到它。可以通过搜索“计算机科学课程”来观察一个例子,我想找到的是UIC计算机科学系提供的所有主要课程的列表。这是当智能组件处于活动状态时,发动机检索的第一个结果。相反,如果不激活它,该页面就不在第一个结果中。
最后,我试图搜索“信息检索” ,没有CPRF的搜索引擎非常糟糕,第一个结果是UIC部门的搜索页面,这也可能是因为在UIC域中没有信息检索页面,或者仅包含在域中。但是,随着智能组件的启用,发现了许多与此相关的网页,其中两个是“ Cornelia Caragea”,教授在这本课程的教授中,许多页面确实与她的出版物和信息检索方面的工作有关,这也是搜索引擎的一个很好的属性。如果找不到非常相关的结果,它仍然能够找到有关相关事物的最佳结果。
正如5.3在我进行了普通搜索引擎和使用智能组件之间进行比较时所解释的那样,我认为产生的结果非常好,当我考虑这一点时,我得到了期望。我通过测试发现的摘要是:
即使原始查询仅输出一堆网站,也可以找到更多结果的能力。
像我在第5.3段中解释的那样,在查询“计算机科学课程”的查询“计算机科学课程”中找到我实际寻找的内容的能力。
即使语料库不包含与查询非常相关的页面以及用户正在搜索的内容,我还注意到此查询“信息检索”,如第5.3段所述的查询“信息检索” 。
一种向我表明这产生正确结果的方法是,在代表上下文的前10个扩展单词中,存在属于用户查询的某些单词。这说明了该方法如何有效地捕获主题,并且没有其他方法可以描述该集合中的其他单词,即使不是作为与原始查询中相同上下文的单词相同的单词。
谈论页面排名。我认为它可以完成工作,但是它不会以我实施的方式改变排名太多,这只是一种偏向结果的方式,以便如果有的话,更喜欢更有权威的页面。
可以肯定的是,必须从这里解决的一件事是超参数调整。这是最困难的事情,主要是因为缺乏标记的数据。我不知道,如果我无法评估查询的精度,则哪个值的效果更好,并且为了自动对其进行调整,应该有很多已经标记的数据。