Information Retrieval 倒排索引 學習筆記

一,問題描述

在Shakespeare文集(有很多文檔Document)中,尋找哪個文檔包含了單詞“Brutus”和"Caesar",且不包含"Calpurnia"。這其實是一個查詢操作(Boolean Queries)。

在Unix中有個工具grep,它能線性掃描一篇文檔,然后找出某個單詞是否在該文檔中。因此,尋找哪篇文檔包含了“Brutus”和“Caesar”可以用grep來實現。但是:不包含“Calpurnia”如何實現呢?

有時,還有一些更加復雜的情況:比如尋找“Romans”附近出現“countrymen”的文檔有哪些?附近 表示尋找的范圍,比如在某篇文檔中“Romans”和“countrymen”出現在同一段落中,那么這篇文檔就是要找的文檔;再比如:“Romans”前后10個詞內出現“countrymen”,則這篇文檔就是要找的文檔。這種情況又如何處理?

再比如,尋找 包含單詞“Brutus”和"Caesar"的文檔,返回的結果有很多篇文檔,哪篇文檔最相關呢?(Rank retrieval)。這些復雜的情況都無法用 grep 工具來實現,而是使用了一些特殊的數據結構(文檔表示方式)。比如 Term-document incidence matrices 和 倒排索引(Inverted?index)

二,Term-document incidence matrices

介紹一個新概念:Term

在處理文檔時,經常以單詞(word)作為分析處理單元(units),但有一些"專有名詞",又不是傳統意義上的單詞,比如"Hong Kong"或者一些一連串的數字。因此,在IR中,用term來表示"index units"。看到這里,就明白tf-idf(term?frequency–inverse?document?frequency) 中的 term 是什么意思了。

Terms are the indexed units,they are usually words, and for the moment you can think of them as words, 
but the information retrieval literature normally speaks of terms because some of them,
such as perhaps I-9 or Hong Kong are not usually thought of as words.

?

回到文章開頭提出的那個問題:哪個文檔包含了單詞“Brutus”和"Caesar",且不包含"Calpurnia"?,更專業地:

哪個文檔包含了 term? "Brutus" 和 term "Caesar",且不包含term "Calpurnia"?

首先將文檔"拆分"成一個個的 term 來表示,若某個term在這篇文檔中出現 就用1標識;未出現則用0標識

如上圖所示:每一列代表一篇文檔是否包含了某個term,比如 文檔 Julius Caesar 就包含了"Antony"、"Brutus"、"Caesar"、"Calpurnia",但是不包含"Cleopatra"、"mercy"、"worser"。

每一行表示 某個term 出現在哪幾篇文檔中。比如 term "Antony"出現在第一篇文檔、第二篇文檔(Julius Caesar)和最后一篇文檔中。

有了這個矩陣,就可以回答上面那個問題了。Brutus 在文檔中出現情況是 110100;Caesar在文檔中出現情況是?110111 ;Calpurnia 出現情況是?101111,將它們進行 與操作:

110100 AND 110111 AND 101111 = 100100

得出:包含了單詞“Brutus”和"Caesar",且不包含"Calpurnia"的文檔是第一篇文檔Antony?and?Cleopatra 和 第四篇文檔?Hamlet。而且對于計算機而言,進行與操作是很快的。

從上面可看出,通過Term-document incidence matrices這種文檔的表示形式,將 grep 線性查找操作,變成了 位與 操作。

但是,這種表示方式也存在著問題:這個矩陣會很稀疏。比如中文漢字有幾萬個(term 很多),一篇新聞文檔不會用到所有的中文漢字,因此矩陣中大部分元素為0。而要存儲一個很大的稀疏矩陣,對內存就造成了浪費。而倒排索引就可以解決這個問題。

?

三,inverted index

倒排索引就是:如果某個term在文檔中出現了,才記錄它。若不出現,則不記錄。

A much better representation is to record only the things that do occur, that is, the 1 positions.

We keep a dictionary of terms Then for each term, we have a list that records which documents the term occurs in.
Each item in the list – which records that a term appeared in a document– is conventionally called a posting

?

假設有很多文檔,如何構建倒排索引呢?首先是從文檔中選取出 term,也就是對文檔進行分詞,得到一個個的 term。比如有N篇文檔如下:

文檔一: Friends, Romans, countrymen.
文檔二: So let it be with Caesar
....
....
文檔N:

對文檔文檔分詞(tokenize),得到一系列的tokens:Friends、Romans、countrymen、So……

有時還需要對分詞的結果進行預處理(linguistic preprocessing),這種預處理操作一般是:刪除一些 stop words,進行?Stemming 操作 和 lemmatization操作。stemming操作 是從詞形上對單詞歸一化,比如說:復數cats 變成? cat。而?lemmatization 是尋找詞根,比如:are, is, am 都歸一化成 be

?

Stemming usually refers to a crude heuristic process that chops off the ends of words in the hope of 
achieving this goal correctly most of the time,
and often includes the removal of derivational affixes

?

Lemmatization usually refers to doing things properly with the use of a vocabulary and morphological analysis 
of words normally aiming to remove inflectional endings only and to return the base or dictionary form of a word,
which is known as the lemma。

?

預處理之后,得到一個個的 可索引的 term 了。倒排索引如下圖所示:

"Brutus"就是一個term,它關聯著一個鏈表(list),這個鏈表稱之為posting,鏈表中的每個元素代表文檔的標識,它表示: term? "Brutus"出現在 文檔1,文檔2,文檔4,文檔11,文檔31……文檔174中

若干個 term 組合起來就是一個 dictionary,所有的posting的集合就是 postings

從上可看出,使用倒排索引表示時:每個文檔都有一個唯一的文檔標識(docID),而且鏈表是有序的。并且上面的倒排索引只關注:某個term是文檔中 是否 出現過,并不知道出現了多少次

現在如何根據倒排索引找出:哪個文檔包含了單詞“Brutus”和"Caesar",且不包含"Calpurnia"?這其實就是 "Brutus" 指向的鏈表 和 "Caesar"指向的鏈表 求并 操作(intersection)---兩個有序的鏈表找公共元素。算法的偽代碼如下:

INTERSECT(p1, p2)answer ← <>
while p1 != NIL and p2 != NILdo if docID(p1) = docID(p2)then ADD(answer, docID(p1))p1 ← next(p1)p2 ← next(p2)
else if docID(p1) < docID(p2)then p1 ← next(p1)else p2 ← next(p2)return answer

時間復雜度為:O(N),N就是 文檔的總個數。對于兩個有序鏈表 求并 操作,時間復雜度會不會小于O(N)呢?那也是有可能的,那就是在鏈表的某些元素上,存儲一個"skip pointer"指針,如下圖所示:

舉個例子:假設目前已經找到了兩個鏈表中的第一個公共元素8,現在要找下一個公共元素。鏈表1移動到下一個位置指向16,鏈表2移動到下一個位置指向41。由于元素16存儲了一個skip pointer,該skip pointer指向28,由于鏈表是有序的而且28小于41,因此鏈表1可以直接跳過19、23這兩個元素,直接移動到28這個元素上(從而不需要將 19和23 這兩個元素與 鏈表2中的41比較)。算法偽代碼如下:

INTERSECTWITHSKIPS(p1, p2)
1 answer ← <>
2 while p1 != NIL and p2 != NIL
3 do if docID(p1) = docID(p2)
4     then ADD(answer, docID(p1))
5     p1 ← next(p1)
6     p2 ← next(p2)
7 else if docID(p1) < docID(p2)
8  then if hasSkip(p1) and (docID(skip(p1)) ≤ docID(p2))
9     then while hasSkip(p1) and (docID(skip(p1)) ≤ docID(p2))
10         do p1 ← skip(p1)
11    else p1 ← next(p1)
12 else if hasSkip(p2) and (docID(skip(p2)) ≤ docID(p1))
13    then while hasSkip(p2) and (docID(skip(p2)) ≤ docID(p1))
14        do p2 ← skip(p2)
15     else p2 ← next(p2)
16 return answer

?

引入skip pointers到底是好還是壞呢?這個不一而足。說幾個需要考慮的因素:

①引入skip pointer 需要額外的存儲空間。②移動到某個元素上時,需要判斷該元素是否存儲了 skip pointers。③在哪些元素上存儲 skip pointer比較好? skip pointers 跳過多少個元素比較好?……

?

額外的一點 補充,上面講到:每個 term 的posting list 長度是未知的。要找某兩個term的公共元素,其實就里線性遍歷這兩個term對應的posting list。因此,這個過程的時間復雜度是O(M+N) 。這里的M是第一個term對應的posting list的長度,N是第二個term對應的posting list的長度。那如果我要找多個term的posting list中的公共元素呢?

比如說:尋找 term : Brutus 、Calpurnia、Caesar這三個term,都在哪些文檔中出現了?

這是一個與操作。如果知道 posting list的長度,先將長度比較短的term的posting list進行與操作,這樣能提高查詢的效率。比如說從上面圖中可看出:Calpurnia 的posting list的長度為4,先執行 Calpurnia & Brutus 得出的結果的長度也不會超過4,然后再去Caesar對應的posting list中查詢。效率要好。

即:執行順序為Calpurnia & Brutus & Caesar 比 Caesar & Brutus & Calpurnia 要好。

?

四,參考資料:

《An Introduction to Information Retrieval》第一章和第二章

?

原文:http://www.cnblogs.com/hapjin/p/8214254.html

轉載于:https://www.cnblogs.com/hapjin/p/8214254.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/281433.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/281433.shtml
英文地址,請注明出處:http://en.pswp.cn/news/281433.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機地址欄搜索不了網,我的電腦地址欄不見了怎么辦 地址欄不見了如何解決...

導語&#xff1a;小編對電腦是比較癡迷的&#xff0c;因此喜歡在自己的電腦上進行各種操作&#xff0c;也經常會碰到一些問題。今天要為大家介紹的是在我的電腦地址欄不見了之后怎么辦&#xff0c;熟悉電腦的朋友都能夠了解。在我的電腦主界面里面&#xff0c;有一個地址欄&…

實踐App內存優化:如何有序地做內存分析與優化

由于項目里之前線上版本出現過一定比例的OOM,雖然比例并不大&#xff0c;但是還是暴露了一定的問題&#xff0c;所以打算對我們App分為幾個步驟進行內存分析和優化&#xff0c;當然內存的優化是個長期的過程&#xff0c;不是一兩個版本的事&#xff0c;每個版本都需要收集線上內…

php OpenSSL 加解密

2018-1-6 17:10:19 星期六 1 $data 123456;2 $openssl_method AES-256-CBC;3 $openssl_iv_length openssl_cipher_iv_length($openssl_method);4 $openssl_iv openssl_random_pseudo_bytes($openssl_iv_length);5 $openssl_password openssl_random_pseudo_bytes(16);6 7 …

前端應該掌握的網絡知識(1)

1、客戶端&#xff1a;通過發送請求獲取服務器資源的web瀏覽器等。 2、TCP/IP協議族按層次分為&#xff1a;應用層、傳輸層、網絡層和數據鏈路層。 應用層決定了向用戶提供應用服務時通信的活動。比如&#xff1a;FTP&#xff08;文本傳輸協議&#xff09;和DNS&#xff08;域名…

WinForm(十四)窗體滾動日志

在桌面程序里&#xff0c;一般日志記錄到文件里就可以了&#xff0c;但有的時間&#xff0c;也需要在窗體上動態滾動顯示&#xff0c;這時&#xff0c;就需要引入日志框架了。這里引入的依舊是NLog&#xff08;在我的Mini API系統里&#xff0c;用的也是NLog&#xff09;。首先…

xp計算機找不到音量調節,WinXP電腦沒聲音且小喇叭不見了如何解決?

有用戶在使用電腦聽音樂的時候&#xff0c;突然發現電腦沒有聲音了&#xff0c;本來以為只是被禁了音&#xff0c;想著調節音量即可解決問題。但是當他想要點開音量小喇叭的時候&#xff0c;發現桌面任務欄通知區域的小喇叭不見了&#xff0c;這該怎么辦呢&#xff1f;下面小編…

2018-2019-1 20165211 實驗四 外設驅動程序設計

2018-2019-1 20165211 實驗四 外設驅動程序設計 任務一 1.實驗要求 學習資源中全課中的“hqyj.嵌入式Linux應用程序開發標準教程.pdf”中的第十一章 提交康奈爾筆記的照片&#xff08;可以多張&#xff09; 2. 任務完成 任務二 1. 實驗要求 在Ubuntu完成資源中全課中的“hqyj.嵌…

《ASP.NET Core 6框架揭秘》實例演示[31]:路由高階用法

ASP.NET的路由是通過EndpointRoutingMiddleware和EndpointMiddleware這兩個中間件協作完成的&#xff0c;它們在ASP.NET平臺上具有舉足輕重的地位&#xff0c;MVC和gRPC框架&#xff0c;Dapr的Actor和發布訂閱編程模式都建立在路由系統之上。Minimal API更是將提升到了前所未有…

java中文亂碼解決之道(五)—–java是如何編碼解碼的

編碼&解碼 1&#xff1a;I/O操作 2&#xff1a;內存 3&#xff1a;數據庫 4&#xff1a;javaWeb 下面主要介紹前面兩種場景&#xff0c;數據庫部分只要設置正確編碼格式就不會有什么問題&#xff0c;javaWeb場景過多需要了解URL、get、POST的編碼&#xff0c;servlet的解碼…

java反射--Class類

面向對象的世界里&#xff0c;萬事萬物皆對象。 1&#xff09;類是誰的對象呢&#xff1f; 類是對象&#xff0c;類是java.lang.Class類的實例對象。 2&#xff09;這個對象如何表示呢&#xff1f; package com.reflect;public class ClassDemo1 {public static void main(Stri…

win10系統按esc會彈出計算機,win10系統版本2004控制面板多出ESC是什么原因?

如果我們的電腦在升級了win102004控制面板多出ESC什么情況方法一&#xff1a;“干凈啟動”&#xff0c;排除第三方軟體的影響1.停止非核心的程序運作(包括第三方殺毒、優化軟體)2.情況允許的話&#xff0c;卸載設備中的第三方殺毒、管家、優化軟件3.同時按【4.點擊【服務】>…

CentOS6/7 配置守護進程

CentOS6.xCentOS6中轉用Upstrat代替以前的init.d/rcX.d的線性啟動方式。一、相關命令通過initctl help可以查看相關命令[rootlocalhost ~]# initctl help Job commands:start Start job.stop Stop job.restart …

Vue源碼解析之數組變異

力有不逮的對象 眾所周知&#xff0c;在 Vue 中&#xff0c;直接修改對象屬性的值無法觸發響應式。當你直接修改了對象屬性的值&#xff0c;你會發現&#xff0c;只有數據改了&#xff0c;但是頁面內容并沒有改變。 這是什么原因&#xff1f; 原因在于&#xff1a; Vue 的響應式…

linux守護進程的編寫

linux監控一個進程進行 代碼如下: #!/bin/shcd /home/autoprocess/ autopgrep -f autoProcessNew.php | wc -l if [ "$auto" 0 ] then nohup php autoProcessNew.php & fi 監視autoProcessNew.php,使他一直監視轉載于:https://www.cnblogs.com/matengfei123/p/…

微軟2014編程之美初賽第一場——題目3 : 活動中心

【來源】 題目3 : 活動中心 【分析】 本題採用的是三分法。 輸入的一組點中找出左右邊界。作為起始邊界。 while(右邊界-左邊界<精度){將左右邊界構成的線段均勻分成3段&#xff0c;推斷切割點的距離關系&#xff0c;抹去距離大的一段。更新左右邊界。 } 輸出左(右)邊界 【…

windows10計算機里輸入法,win10電腦上輸入法不見了怎么辦

好的輸入法可以加快我們的工作效率&#xff0c;當電腦上輸入法不見時&#xff0c;你會調出來嗎?下面小編告訴你win10電腦上輸入法不見時弄出來的一些訣竅吧。win10電腦上輸入法不見了的解決方法win10電腦上輸入法不見了的解決方法&#xff1a;Win10系統輸入法圖標不見了的找回…

Java并發(二十一):線程池實現原理

一、總覽 線程池類ThreadPoolExecutor的相關類需要先了解&#xff1a; &#xff08;圖片來自&#xff1a;https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8%A7%88&#xff09; Executor&#xff1a;位于最頂層&#xff0c;只有一個 execute(Runnable runnable) 方法&a…

進程池

轉自&#xff1a;https://www.cnblogs.com/kaituorensheng/p/4465768.html 在利用Python進行系統管理的時候&#xff0c;特別是同時操作多個文件目錄&#xff0c;或者遠程控制多臺主機&#xff0c;并行操作可以節約大量的時間。當被操作對象數目不大時&#xff0c;可以直接利用…

gulp版本號管理插件注意事項

2019獨角獸企業重金招聘Python工程師標準>>> 打開node_modules\gulp-rev\index.js 第144行 manifest[originalFile] revisionedFile; 更新為: manifest[originalFile] originalFile ?v file.revHash; 打開node_modules\rev-path\index.js 第10行 return filena…

bigfile.to服務器位置,Cloudera Manager 遷移服務器

Cloudera Manager還是比較耗資源的&#xff0c;想把Cloudera Manager&#xff0c;移動到比較好的機器上。在這篇文章中&#xff0c;Cloudera Manager安裝在bigserver1上面&#xff0c;bigserver1是奔騰雙核的CPU。1&#xff0c;Cloudera Manager占資源比較多cloudera manager占…