我根本没有实现搜索索引的经验,所以任何一般信息如何构建一个,什么信息存储,如何实现高级搜索,如“整个短语”,结果排名等.
我不怕自己构建它,虽然我很乐意重用现有的组件(或使用一个开始使用原型).我正在寻找一个可从C访问的解决方案,最好不需要在运行时额外的安装.内容是静态的(因此聚合搜索信息是有意义的),但搜索可能必须从多个这样的存储库中累积结果.
我可以做一些教育的猜测,虽然:创建一个地图字==>对于所有(相关)词的页面,可以通过突出(h1> h2>>< p>)和靠近顶部的映射将等级分配给映射.高级搜索可以建立在其上:搜索短语“homo sapiens”可以列出包含“homo”和“sapiens”的所有页面,然后扫描返回的所有页面,它们在一起发生的位置.然而,有很多问题的场景和未回答的问题,所以我正在寻找一个应该是大量的现有工作,不知何故逃脱我的谷歌的功能.
[赏金]
我现在找到的最好的资源是is this和从那里的链接.
我确实有一个实验系统的创作路线图,但是我仍在寻找:
>关于索引创建和单独步骤的参考资料
>各个步骤的可用实现
>可重用的实现(具有上述环境限制)
解决方法
现有图书馆
这里有两个现有的解决方案可以完全集成到一个应用程序中,而不需要单独的进程(我相信都会用VC编译).
Xapian是成熟的,可以做很多你需要的,从索引到排序检索.需要单独的HTML解析,因为AFAIK,它不解析html(它有一个配套程序Omega,它是索引网站的前端).
Lucene是Java中的索引/搜索Apache库,具有官方预发行版本C版本lucy和非官方C版本CLucene.
实施信息检索
如果上述选项由于某种原因不可行,请参阅构建和使用索引的各个步骤的一些信息.根据您的应用需求,定制解决方案可以从简单到复杂.我把这个过程分成5个步骤
> HTML处理
>文字处理
>索引
>检索
>排名
HTML处理
这里有两种方法
>剥离您引用的页面讨论了通常称为剥离的技术,其中涉及删除所有不会显示的HTML元素,并将其他元素转换为其显示形式.就个人而言,我将使用perl进行预处理,并对结果文本文件进行索引.但是,对于集成解决方案,特别是要记录重要性标签(例如< h1>< h2>)的解决方案,您可能希望自己的角色. Here is a partial implementation的C剥离程序(出现在C的思考,最终版本的here),你可以从中构建.
>解析从剥离的复杂性上升到html解析,这将有助于您记录重要性标签.但是,一个好的C HTML解析器是hard to find.一些选项可能是htmlcxx(从来没有使用,但是有活力,看起来很有前途)或hubbub(C库,NetSurf的一部分,但声称是可移植的).
如果您正在处理XHTML或愿意使用HTML到XML转换器,则可以使用许多可用的XML解析器之一.但是,再次,HTML到XML转换器很难找到,我唯一知道的是HTML Tidy.除了转换为XHTML,其主要目的是修复丢失/损坏的标签,而has an API可能用于将其集成到应用程序中.给定XHTML文档,有许多很好的XML解析器,例如Xerces-C++和tinyXML.
文字处理
至少对于英文来说,处理文字到字很简单.当涉及搜索时,有一些并发症.
>停止单词是先验而不是提供集合中的文档(例如文章和命题)之间的有用区别的单词.这些词通常不会从查询流中编入索引和过滤.网络上有很多停止列表,例如one.
> stemming涉及预处理文档和查询,以确定每个单词的根,以更好地推广搜索.例如.寻找“foobarred”应该产生“foobarred”,“foobarring”和“foobar”.该索引可以单独构建和搜索.两种一般的干扰方法是基于字典(来自词==>根的查找)和基于算法.波特算法是非常普遍的,并且有几种实现可用,例如. C++ here或C here.在Snowball C library停留支持多种语言.
> Soundex encoding使搜索更加鲁棒的拼写错误的一种方法是使用语音编码对字进行编码.那么当查询语音错误时,他们仍然会直接映射到索引的单词. here’s one有很多实现.
索引
地图字==>页面数据结构被称为inverted index.它被反转,因为它经常从页面的前向索引生成==>话.反向索引通常有两种风格:反转文件索引,它们将每个文档映射到其中,并将完整的反向索引映射到每个文档中的每个位置.
重要的决定是后端用于索引,一些可能性是按照易于实现的顺序:
> SQLite或Berkly DB – 这两个都是具有集成到项目中的C API的数据库引擎,而不需要单独的服务器进程.持久性数据库基本上是文件,因此可以通过更改关联的文件来搜索多个索引集.使用DBMS作为后端可简化索引创建,更新和搜索.
>在内存数据结构中 – 如果您使用的反向文件索引不是太大(内存消耗和加载时间),则可以以std :: map< std :: string,word_data_class> ;,将boost::serialization用于持久性.
>在磁盘数据结构 – 我听说过使用内存映射文件这种事情,YMMV惊人的快速结果.具有反向文件索引将涉及到两个索引文件,一个表示与struct {char word [n]等字的单词; unsigned int offset; unsigned int count; },第二个表示(word,document)的元组只有unsigned int(在文件偏移量中隐含的单词).偏移量是第二个文件中单词的第一个文档ID的文件偏移量,count是与该单词相关联的文档ID数量(从第二个文件读取的ids的数量).然后,搜索将通过指向内存映射文件的指针减少到通过第一个文件的二进制搜索.缺点是需要填充/缩短单词以获得一个恒定的记录大小.
索引的过程取决于您使用的后端.用于生成反转文件索引(detailed here)的经典算法从阅读每个文档开始,并扩展(页面ID,字)元组的列表,忽略每个文档中的重复单词.处理所有文档后,按字排序列表,然后折叠为(word,(页面id1,页面id2,…)).
mifluz gnu库实现具有存储的倒排索引,但没有文档或查询解析. GPL,因此可能不是一个可行的选择,但会让您了解支持大量文档的反向索引所涉及的复杂性.
恢复
一个非常常见的方法是布尔检索,它只是分别用于或者分别连接到每个查询词的索引文档的联合/交集.如果文档ID按照每个术语的排序顺序存储,这些操作是有效的,因此可以直接应用std :: set_union或std :: set_intersection等算法.
检索有差异,wikipedia有一个概述,但是标准布尔对许多/大多数应用是有好处的.
排行
对布尔检索返回的文档进行排序有很多种方法.常用的方法是基于单词模型,这仅仅意味着词的相对位置被忽略.一般的方法是对每个检索到的文档相对于查询进行评分,并根据其计算得分对文档进行排名.有很多评分方法,但是起始的地方就是频率逆文档频率公式.
这个公式背后的想法是,如果一个查询词频繁出现在一个文档中,该文档应该得分更高,但是在许多文档中发生的一个词语的信息量较少,因此这个词应该被加权.公式是,超过查询词i = 1..N和文档j
score [j] = sum_over_i(word_freq [i,j] * inv_doc_freq [i])
其中word_freq [i,j]是文档j中单词i的出现次数,
inv_doc_freq [i] = log(M / doc_freq [i])
其中M是文档的数量,doc_freq [i]是包含单词i的文档数量.请注意,所有文件中出现的单词都不会对分数做出贡献.广泛使用的更复杂的得分模型是BM25,包括Lucene和Xapian.
通常情况下,通过反复调整可以获得特定领域的有效排名.通过标题/段落上下文来调整排名的起始位置可能会使基于标题/段落上下文的单词的word_freq膨胀. 1段,10级为顶级标题.对于其他一些想法,您可能会发现this paper有趣,作者调整了BM25排名的位置得分(这个想法是更接近文档开头的词语比结束语更相关).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。