2008-10-21 330 views
6

在我們的桌面應用程序中,我們使用inverted index實現了一個簡單的搜索引擎。應用程序的內存中搜索索引佔用太多內存 - 有什麼建議嗎?

不幸的是,我們的一些用戶的數據集可能會變得很大,例如,在創建倒排索引之前佔用大約1GB的內存。倒排索引本身佔用大量內存,幾乎與索引數據一樣多(另一個1GB的RAM)。

很明顯,這會造成內存不足錯誤的問題,因爲每個應用程序的32位Windows內存限制爲2GB內存,或者配置較少的計算機的用戶難以應付內存需求。當每個對象進行處理,使得所述的applicationObject的密鑰串和描述字存儲在倒排索引數據加載期間

Dictionary<string, List<ApplicationObject>> 

,這是創建:

我們的倒排索引被存儲爲一個。

所以,我的問題是:是否有可能更有效地存儲空間明智的搜索索引?也許需要使用不同的結構或戰略?或者可以創建一種CompressedDictionary?因爲它存儲了很多字符串,所以我期望它具有高度的可壓縮性。

回答

3

如果它將是1GB ...把​​它放在磁盤上。使用諸如Berkeley DB之類的東西。它將仍然非常快。

這裏是提供了一個.NET接口,它的一個項目:

http://sourceforge.net/projects/libdb-dotnet

+0

如果可能的話,我想避免這種情況,因爲它可以更簡單地擁有內存中的搜索索引。但也許這是不可能的,但它似乎應該*對我可能。 – RickL 2008-10-21 15:44:43

1

我bobwienholt同意,但如果你是索引數據集我認爲這些來自數據庫的某個地方。用DTSearchLucene.net這樣的搜索引擎搜索它會有意義嗎?

+0

也許,但我想這會更復雜?即應用對象被存儲在映射到不同特定應用對象的許多不同表中。啊,我們的應用程序也被緩衝了,所以內存數據集可能會與數據庫不同步。 – RickL 2008-10-21 15:18:09

3

我看到幾個解決方案:

  1. 如果你有一個數組的ApplicationObjects,商店僅僅是指數 - 可能會更小。
  2. 您可以使用一點C++/CLI來存儲字典,使用UTF-8。
  3. 不要打擾存儲所有不同的字符串,使用Trie
+0

對於點1)它們不存儲在一個數組中,但是你的意思是存儲索引而不是字符串鍵?那麼你如何通過字符串搜索?還是你的意思,而不是List 有一個列表?我想它可能會更小,但可能不是一個巨大的數額。 – RickL 2008-10-21 15:32:58

3

我懷疑你會發現你已經得到了很多非常小的列表。

我建議你大致瞭解頻率是多少 - 有多少個字典條目有單個元素列表,有多少個有兩個元素列表等等。你可能會存儲幾個單獨的字典 - 一個是「我只有得到一個元素「(直接映射),然後」我有兩個元素「(映射到具有兩個引用的Pair結構)等,直到它變得愚蠢 - 很可能在大約3個條目 - 這時你會回到正常名單。在一個簡單的界面後面封裝全部內容(添加條目/檢索條目)。這樣你就會有更少的浪費空間(主要是空緩衝區,數量等)。

如果這些都不合理,讓我知道,我會試着想出一些代碼。

+0

這是一個有趣的觀察......是的,我認爲大多數列表會很小。根據你的建議,我猜想倒排索引創建會花費更長的時間,因爲你必須在1項,2項等詞典之間移動項目,但可能會節省空間。 – RickL 2008-10-21 16:15:22

+0

我懷疑在性能上的差異會很小,說實話 - 但是,會有一些開銷。絕對值得在編碼之前檢查分佈:) – 2008-10-21 16:21:40

+0

一個想法是讓它開始使用可能更便宜:只需要一個Dictionary >。這意味着每個值都有一個對象,而不是使用結構來避免這種情況,但是您只需要替換字典中的條目而不是執行刪除/添加 – 2008-10-21 16:25:02

0

該索引是否只添加到或還從中刪除了鍵?

1

你可以採取Lucene的做法。首先,你創建一個隨機訪問內存流(System.IO.MemoryStream),這個流鏡像在磁盤上,但只有一部分(如果你有錯誤的部分,從磁盤加載另一個) 。這確實會導致一個頭痛,你需要一個文件可映射的格式爲您的字典。維基百科描述了paging technique

在文件可映射的場景。如果打開Reflector並反映Dictionary類,您將看到它包含存儲桶。您可以將這些桶中的每一個用作頁面和物理文件(這種插入方式更快)。然後,您可以通過簡單地向文件中插入「item x deleted」值並每隔一段時間清理一次文件來寬鬆地刪除值。

順便說一句,桶使用相同的散列值。你存儲的值重寫GetHashCode()方法是非常重要的(編譯器會警告你關於Equals()以便覆蓋它)。如果你這樣做,你會在查找中獲得顯着的速度提升。