《Introduction to Information Retrieval》读书笔记(一)

     最近细读了Christopher D. Manning, Prabhakar Raghavan and Hinrich Schütze的《Introduction to Information Retrieval》这本书,虽然是英文的,坚持着看了一大半了,确实不错,记下其中的一些重点内容,以备温习。书可以在这里找到:http://nlp.stanford.edu/IR-book/information-retrieval-book.html

反文档索引(inverted index)

A 建立反文档索引的步骤

1):收集将要被索引的文档,标号

2):将每个文档变成一系列的标志(token)

3):做些语言方面的预处理,将标志标准化

4):建索引 索引包括词典(dictionary)和后缀(posting),后缀对应该词出现在文中的信息。

B 建反文档的一个关键步骤是将各个文档的标记按字母序合并起来,相同的标志放在一块,因而形成词典+后缀的形式。由于一个标志出现在多个文档中,这样处理起来能够节省很多空间。词典中单词后面也可以记录单词的文档频率(document frequency),后缀部分进行第二次排序,按文档标号排序,这可以方便后面的查询

C 关于存储方式 词典多半存储于内存中,后缀多半存储于硬盘上。关于后缀的存储方式,通常的定长数组方式将后浪费很多空间,因为有的单词会出现在很多文章中。两个替换的接却方法是单链表和变长数组。单链表的插入开销小,这在频繁更新时有优势,并且他还可以方便的扩展成更高级的索引方法,例如跳跃链表(Skip list),这只需要额外增加一些指针即可;变长数组在空间开销上比单链表要小,因为它不需要单链表中用来存储指针的那部分,在时间开销上也更小,因为它使用连续内存空间,因而寻址速度更快。作为补充,额外的指针也可以用到变长数组上。如果数据更新不频繁,变长数组在检索上比单链表更紧凑、速度更快。也可以用后缀部分是定长数组的链表的混合模式,当后缀部分存储在硬盘上时,它作为一种连续形式存储于硬盘中,并且不带指针。这样减小了后缀的大小以及将后缀读入内存时的硬盘的寻址次数。

D 布尔查询步骤:A and B 形式

1):在词典中定位A单词,判断其后缀是否为空,p1指向其后缀

2):在词典中定位B单词,判断其后缀是否为空,p2指向其后缀

3):对A,B单词的后缀“求交”

求交的算法

InterSect(p1,p2)
answer <-- < >
while p1 != NIL and p2 != NIL
do if docID(p1)=docID(p2)
then ADD(answer,douID(p1))//1
     p1 <-- next(p1)
     p2 <-- next(p2)
else if docID(p1) < docID(p2)
     then p1 <-- next(p1)//2
     else p2 <-- next(p2)
/*注释
1.如果p1指向的文件ID与p2的相同,那么该文件是answer
2.由于后缀是按升序排列的,因而当某指针指向的ID较小时,移动相应的指针使ID变大再做比较。
*/

 

多重查询求交

INTERSECT(<t1,....,tn>)
terms <-- SortByIncreasingFrequency(<t1,...,tn>)//将t1,..tn按df排列
result <-- Postings(first(terms))//结构为最小df查询词的后缀
terms <-- rest(terms)
while terms != NIL and result != NIL
   do result <-- InterSect(result,postings(first(terms))//对最小和次小df查询词的后缀求交
   terms <-- rest(terms)
return result

 

一个改进:通过跳跃指针改进求交时间复杂度

1):在索引阶段增加一个跳跃指针,跳跃长度为后缀长度的平方根。

2):跳跃指针只对初始的后缀起作用,对复杂查询的中间结果不起作用。

 

 INTERSECTWITHSKIPS(p1,p2)
answer <-- < >
while p1 != NIL and p2 != NIL
  do if docID(p1) = docID(p2)
     then ADD(answer,docID(p1))
     p1 <-- next(p1)
     p2 <-- next(p2)
  elseif docID(p1) < docID(p2)
     then if hasSkip(p1) and (docID(Skip(p1)) <= docID(p2))
          then while hasSkip(p1) and  (docID(Skip(p1)) <= docID(p2))
                do p1 <-- Skip(p1)
      else p1 <-- next(p1)
   else if hasSkip(p2) and (docID(Skip(p2)) <= docID(p1))
          then while hasSkip(p2) and  (docID(Skip(p2)) <= docID(p2))
                do p2 <-- Skip(p2)
      else p2 <-- next(p2)
return answer

E利用空间索引解决词组或是短句查询的问题

1):建空间索引(positional indexes):在反文档索引的基础上进行一些修正即可:对词典中每个单词的后缀,为每个文档增加两个属性,一个是该单词出现在该文档中的频率(term frequency)及该词出现在文中的空间位置。

2):在检索时,和前面的一样,但在类似求AND时,要增加限制条件:检查文章是否符合查询词的位置关系,这只需计算查询词与查询词间的偏移量。

POSITIONALINTERSECT(p1,p2,K)

answer <-- <  >

while p1 != NIL and p2 != NIL

do if docID(p1)= docID(p2)

     then l <-- <  >

          pp1 <--position(p1)

          pp2 <--position(p2)

          while pp1 != NIL

          do while pp2 != NIl

                 do if |pos(pp1)-pos(pp2)|<= K//

                 then ADD(l,pos(pp2))//

                 else if  pos(pp2) > pos(pp1)//个人觉得此处有误

                       then break

                 pp2<-- next(pp2)

         while l != < > and |l[0] - pos(pp1)| > K

         do DELETE(l[0])

         for each ps <- l

         do ADD(answer,< docID(p1),pos(pp1),ps>)

         pp1 <- next(pp1)

     p1 <-- next(p1)

     p2 <-- next(p2)

else if

     docID(p1)<docID(p2)

     then p1 <-- next(p1)

     else p2  <-- next(p2)

return answer

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值