1. 程式人生 > >資料知識工程大作業——goodu搜尋引擎設計與實現

資料知識工程大作業——goodu搜尋引擎設計與實現

前言

很長一段時間沒有寫部落格,因為最近在忙一些學校的事情,在資料知識工程這門課上,老師留了一個大作業,是做一個簡單的搜尋引擎,功能需求如下:

要求:

使用者可指定返回結果數

顯示查詢的響應時間

排序結果中提取文件中包含查詢關鍵詞的片段

支援短語(2單詞)查詢

按照功能的需求,我們最終完成了一個簡單的搜尋引擎,可以返回指定結果數、顯示查詢的響應時間,可以對結果進行排序,並且顯示搜尋結果所在的部分的文字,支援短語(2單詞)的查詢,並且支援類似於google /4 baidu的搜尋方式,用以搜尋在googlebaidu之間間隔小於等於四個詞的文件。

設計過程

索引

對於一個搜尋引擎來說,最重要的部分應該就是索引的建立,一個索引建立的好壞與否直接決定了後面搜尋部分的速度和準確度。而根據資料知識工程這門課程前面的講解,建立索引就是通過對所有文字的掃描來獲得單詞token

並且通過porter stemmer將單詞變為相應的詞根(term),然後將詞根建立為dictionary,通過倒排索引建立每個term的文件id列表(postingList)。

獲取token就是讀取檔案的過程,然後通過porter stemmer將單詞轉換為term。在建立索引的過程中有兩個部分需要設計相應的資料結構。DictionaryPostingList

dictionary的建立可以使用兩種資料結果來實現,一種是雜湊表,一種是樹。兩種資料結構各有優劣,雜湊表可以實現常數時間的查詢,查詢速度最快,但是如果dictionary需要增長的話需要耗費大量時間來重新建立雜湊表。用樹來儲存

term的好處在於可以實現字首的查詢,相對雜湊表來說增加dictionary代價更小,缺點是查詢不如雜湊表那麼快(logM)。因為本次作業是給定的資料集,為了實現最快速的查詢,我們毫無疑問要選擇雜湊表來實現,因為程式碼是用Java來實現的,所以我們使用了Java的容器類—Hashmap來儲存dictionary

public class Entry {

public int idf = 0;

public List<PostingListItem> postingList;

public Entry(int idf, List postingList){

this.idf = idf;

this.postingList = postingList;

}

 

}


PostingList是文件Id的列表,每個dictionary裡面的term都有一個指向相應PostingList的指標,PostingList裡儲存著文件Id等資訊,我們使用JavaLinkedList來作為PostingList的資料結構,如下。

</pre><pre name="code" class="java">

public class PostingListItem {
	public int DocumentId;
	public int tf;
	//public int position;
	public List<PositionItem> positionList;
	
	public PostingListItem(int id, int tf, List<PositionItem> positionList) {
		// TODO Auto-generated constructor stub
		this.DocumentId = id;
		this.tf = tf;
		//this.position = position;
		this.positionList = positionList;
	}
}

public class PositionItem {

 

int wordPos;

int charPos;

public PositionItem(int wordPos, int charPos){

this.wordPos = wordPos;

this.charPos = charPos;

}

 

}


 

最後整體的資料結構如下:


對索引部分進行了單元測試,部分結果如下:

For term: unit

DocumentId: 6

tf: 2

[176 22] [559 82]

DocumentId: 9

tf: 1

[1190 185]

DocumentId: 17

tf: 1

[28 4]

DocumentId: 21

tf: 3

[107 15] [199 29] [251 37]

DocumentId: 27

tf: 2

[156 20] [267 38]

DocumentId: 28

tf: 1

[101 17]

查詢

至此,索引的建立已經完畢,接下來要進行的就是查詢部分的設計,查詢分為單詞查詢和片語查詢,使用的是tf-idf來對每次搜尋在每個文件的重要程度進行的打分。

 

其中的tf就是我們在postingListItem中儲存的int型別的tfidf就是我們在entry中儲存的int型別的idfN是資料集中的文件數目。在查詢的時候通過公式進行計算得到相應的值。

單詞搜尋

最先完成的是對單詞進行的搜尋。因為需求中規定了可以指定返回的結果數目,所以我們沒有必要對所有文件進行排序,而是使用堆排序的方法,因為要返回前k個大的文件,所以堆排序是最適合該情況的方法。堆排序的建堆的時間複雜度為O(n),通過維護一個大小為k的最小堆來儲存前k大的文件,如果新文件比堆頂的要大,就更換堆頂,否則跳過。如果採用其它方法如快排,時間複雜度平均要O(n log n)

搜尋的過程,首先對搜尋的單詞進行詞根處理,然後通過hash表找到termdictionary裡的位置,並且找到其postingList,沿著postingList通過最小堆來篩選出score最大的前k個文件並返回其文件idweightposition到資料結構ResultSet中。

public class ResultSet {

public int DocumentId;

public double weight;

public int position;

public ResultSet(int id, double weight, int position){

this.DocumentId = id;

this.weight = weight;

this.position = position;

}

}


單詞搜尋的結果展示如下:

 

片語搜尋

片語搜尋的完成是基於單詞搜尋的基礎上,將搜尋的片語作為一個向量(向量的每一維都是一個termtf-idf),被搜尋的每個文件都作為一個向量,找出與搜尋向量最相近的k個向量。

 

使用向量夾角來量化搜尋與文件之間的關係

 

片語搜尋還要在兩個單詞相鄰的基礎上再進行向量夾角的計算,所以在之前的資料結構中使用了positionList來儲存每個term在每個文件中出現的位置(單詞位置),通過查詢兩個位置是否相鄰來獲取該檔案是否有該片語出現。同時也實現了google /4 baidu的搜尋效果,通過查詢兩個單詞的位置是否相差小於等於4的單詞數。獲取到含有該片語的文件後,再通過向量夾角的cos值來獲得score,並且使用最小堆得到前k個結果並返回。

片語搜尋的結果如下:

 

遇到的問題

遇到的問題是向量夾角cos的計算,在大量term存在的情況下,向量的維度會非常大,如果進行幾千維度與幾千維度的向量之間的點乘運算會耗費大量搜尋時間。後來發現搜尋的片語只有兩個單詞,也就是說其它維度的數值都是0,在進行點乘運算時與0相乘的步驟可以忽略,直接進行term1_score * doc1.term1_scor + term2_score * doc 2.term2_score ...得到結果。

還有就是片語搜尋需要知道某個單詞在文件中是第幾個,因此修改了資料結構postingList,增加了連結串列positionList來儲存term在某個文件中所有出現過的位置。

系統的特點

可以查詢單詞和片語(2單詞),查詢響應速度快,返回結果根據使用者的輸入按照weight由高到低返回前k個,可以返回查詢的時間,文件的id和文件名,相應的weightterm在文件中的字元位置,term所在位置的部分文字顯示。

 

支援在兩單詞中間輸入/n來表示搜尋兩單詞間距小於等於n的結果。


相關推薦

資料知識工程作業——goodu搜尋引擎設計實現

前言 很長一段時間沒有寫部落格,因為最近在忙一些學校的事情,在資料知識工程這門課上,老師留了一個大作業,是做一個簡單的搜尋引擎,功能需求如下: 要求: 使用者可指定返回結果數 顯示查詢的響應時間 排序結果中提取文件中包含查詢關鍵詞的片段 支援短語(2單詞)查詢 按照功能的

基於Spring4+Hibernate4的通用資料訪問層(Dao層)設計實現

基於泛型的依賴注入。當我們的專案中有很多的Model時,相應的Dao(DaoImpl),Service(ServiceImpl)也會增多。而我們對這些Model的操作很多都是類似的,下面是我舉出的一些(見名知意,其它自行腦補): 1.save 2.saveAll 3.fin

計算機網路- 可靠資料傳輸協議-停等協議的設計實現

一、所實現停等協議簡介 我設計的程式實現的是rdt3.0版本的停等協議,傳送端將資料包以0、1交替的順序傳送資料包,當傳送0資料包之後開始計時,只有接收到ack0才能繼續傳送1資料包,如果在沒有接收到ack0的時候已經超時,這時候需要重傳資料包0; 接收方按照所收到的資料包

打通感知認知,明略資料還要做資料知識工程

(上圖為明略資料創始人吳明輝) 作為國內行業知識圖譜領域的創新公司,明略資料在2018年4月進入了IDC的《中國知識圖譜市場,2018》創新者研究報告,成為IDC評選出的5家中國知識圖譜技術應用市場創新者。2017年8月,明略資料經過3年實踐沉澱以及8年大資料技術積

明略科學院院長、IEEE Fellow吳信東:資料知識工程基礎理論 | 直播課筆記

不久前,明略資料成立明略科學院,並由明略科學院院長吳信東教授帶來第一講:《大資料知識工程基礎理論

Hadoop技術內幕:深入解析MapReduce架構設計實現原理 (資料技術叢書).epub

  【下載地址】 《Hadoop技術內幕:深入解析MapReduce架構設計與實現原理》內容簡介:“Hadoop技術內幕”共兩冊,分別從原始碼的角度對“Common+HDFS”和“MapReduce的架構設計和實現原理”進行了極為詳細的分析。《Hadoop技術內幕:深入解析M

[轉]FTP搜尋引擎設計實現(優化版)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Linux核心設計實現 總結筆記(第六章)核心資料結構

核心資料結構 Linux核心實現了這些通用資料結構,而且提倡大家在開發時重用。 核心開發者應該儘可能地使用這些資料結構,而不要自作主張的山寨方法。 通用的資料結構有以下幾種:連結串列、佇列、對映和二叉樹   一、連結串列 1.1 單向連結串列和雙向連結串列   1.2 環形

團隊作業3(開發設計分工)

  我們是10號團隊,開發專案為“家庭賬本APP”App名稱初步定為“小本本”。 主程式碼倉庫地址:https://gitee.com/chitu_heshui/product_code_repository 楊本興程式碼地址:https://gitee.com/yangbenxing666/

Redis 設計實現[1] -- 資料結構物件

1 簡單動態字串 Redis 沒有直接使用 C 語言傳統的字串表示,而是自己構建了一種簡單動態字串(SDS),使用 SDS 作為 REdis 的預設字串表示。 1.1 SDS 定義 struct sdshdr { // 記錄 buf 陣列中已經使用位元組的數量,等於 SDS 所儲

分散式站點資料同步機制的設計實現[出自別處]

摘要:在網際網路蓬勃發展的今天,把集團公司下的各個水電站的資料同步起來,統一管理的需求日益突顯。本公司首先採用了oracle公司自身提供的解決方案高階複製技術,但限於本國網速緩慢網路時常斷線的不穩定的狀態的特殊國情,實施效果不盡如人意。針對我國苛刻的網路條件,本公司努力研發,自主地設計了一套低網速資料同步系統

FPGA設計千兆乙太網MAC(3)——資料快取及位寬轉換模組設計驗證

1 `timescale 1ns / 1ps 2 3 module tx_buffer_tb( ); 4 5 parameter USER_CLK_CYC = 10, 6 ETH_CLK_CYC = 8, 7 RST_TIM = 3;

《redis設計實現》1-資料結構物件篇

前言 redis效能為什麼這麼出色?它與其他快取中介軟體有什麼區別? redis底層使用了哪些資料結構支撐它如此高效的效能? 內部豐富的資料型別底層為什麼都使用至少兩種資料結構實現?分別是什麼? 如果合理的使用redis才能發揮它最大的優勢? 學習完《redis設計與實現》前面關於資

lua設計實現(二)資料型別

lua中的資料型別 //lua.h /* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERD

Redis設計實現讀書筆記之第一部分: 資料結構物件

(一) 簡單動態字串SDS Redis沒有直接使用C語言傳統的字串表示(以空字串結尾的字串),而是構建了簡單動態字串SDS,其定義 struct sdshdr{ int len; //記錄buf陣列中已使用位元組的數量 int free; //記錄buf

java資料結構演算法之平衡二叉樹(AVL樹)的設計實現

關聯文章:   上一篇博文中,我們詳細地分析了樹的基本概念以及二叉查詢樹的實現過程,基於二叉查詢樹的特性,即對於樹種的每個結點T(T可能是父結點),它的左子樹中所有項的值小T中的值,而它的右子樹中所有項的值都大於T中的值。這意味著該樹所有的元素可以用某

基於BS架構的臨床科研資料管理系統的設計實現

        基於BS架構的臨床科研資料管理系統的設計與實現             2018年11月10日     目錄 第一章 緒論... 6 1.1

資料結構程式設計回顧(一) 通訊錄管理系統的設計實現

很久沒更了 最近在複習資料結構 沒事把之前的程式碼翻出來回憶一下  【題目來自去年課程設計的七個題目】 題目一:通訊錄管理系統的設計與實現 設計要求:系統包括通訊者結點資訊的插入、查詢、刪除、 更新以及通訊錄資訊的輸出等功能。 選單內容: 1. 通訊錄連結串列的建立 2

模版+資料分離渲染方式的設計實現

2 實現無等待的模版渲染         然而,在使用listener事件的時候又遇到了問題。         因為熟悉listener事件的同學都知道,事件fire與事件register是有先後順序的,register在前,fire在後,也就是說在ejs需要使用模版的時候,我們會使用listener

計算機網路實驗-可靠資料傳輸協議-GBN協議的設計實現

這一週做了一個計算機網路的實驗,名字叫 可靠資料傳輸協議-GBN協議的設計與實現 感覺自己做的很認真,實現的效果也不錯,就把自己的過程與結果記錄一下 對於這個實驗,實驗要求上說實現SR協議是加分項,而SR協議又是以GBN協議為基礎,所以自己直接一步到位,只實