2016-03-04 119 views
2

我有多頭long[]的許多陣列,我需要序列化它們,並將它們保存到磁盤供以後閱讀,注意到,每個陣列必須進行修改不時,但讀取頻繁時寫入次數不多。 通常我的應用程序只需要少量那些同時加載到內存中的應用程序。 在將數組存儲回磁盤之前,對每個數組的編輯可以在內存中進行批量處理。每個陣列都有數百個至上百萬個元素。 在我的應用程序中,將所需數組加載到內存中非常關鍵。最緊湊的方式來序列化的long數組在Java中

在我的情況下,每個數組中的長整數平均而言非常接近另一個,即從一個值到另一個值的差值(如果在單個數組內排序)小於整數。

採用字典樹狀結構as presented here似乎不適用於我的情況下,由於在溶液中的陣列值是已知的,並永遠不會改變的溶液。

This solution here告訴我使用ByteBufferLongBuffer加快I/O,但我的想法是這樣的陣列也存儲在最緊湊的方式,以便來加速通過將其加載到主存儲器所需的時間減少我需要閱讀的大小。 直覺就是存儲排序後的值,並存儲一個值與下一個值之間的差值,平均值在整數範圍內,因此佔用的空間較小。 但是,由於這並非總是如此,我仍然無法將所有的值存儲爲整數,所以這個方向似乎並不樂觀。 我錯過了一些明顯的東西嗎?

什麼是最有效的方式,在I/O時間,來實現這一目標?


編輯一般來說,對於性能完全I/O時間,在不考慮磁盤空間,this question有更好的答案。

+0

你做了多少內存處理?您可以從左側的字段中考慮映射到「LongBuffer」的MappedByteBuffer,除了您實際訪問的元素外,它完全消除了I/O。 – EJP

+0

@EJP我不明白你的問題和你的建議。你能澄清它嗎?謝謝。 – Kuzeko

+0

我的問題是'你在做多少內存處理?'。你不瞭解哪一部分?我的建議是使用直接由磁盤文件支持的虛擬長陣列。根據你對數據做多少計算,這將工作或不能快速工作。 – EJP

回答

2

您仍可以編碼數組元素具有下列另外整數:

// The first int is the array length 
    buf.putInt(array.length); 

    long prev = 0; 
    for (long next : array) { 
     if (next - prev <= Integer.MAX_VALUE) { 
      // Delta is small. Change the sign and encode as int. 
      buf.putInt((int) (prev - next)); 
     } else { 
      // Delta does not fit in 31 bits. Encode two parts of long. 
      buf.putInt((int) (next >>> 32)); 
      buf.putInt((int) next); 
     } 
     prev = next; 
    } 

注意,31位delta將被編碼爲負int。在解碼過程中,最高位(符號位)將指示該值是否爲delta或原始63位long。在後一種情況下,你下一個讀取int和兩個整數組成一個63位long

// The first int is the array length 
    long[] array = new long[buf.getInt()]; 

    long next = 0; 
    for (int i = 0; i < array.length; i++) { 
     int delta = buf.getInt(); 
     if (delta <= 0) { 
      // Negative sign means the value is encoded as int delta. 
      next -= delta; 
     } else { 
      // Positive sign means the value is encoded as raw long. 
      // Read the second (lower) part of long and combine it with the higher part. 
      next = (long) delta << 32 | (buf.getInt() & 0xffffffffL); 
     } 
     array[i] = next; 
    } 

這工作,如果陣列中的所有值都是正的。如果有正值和負值,則將它們分成兩個數組。


順便說一句,像GZIP流壓縮(或類似LZ4更快的替代方案)也將工作做好,如果鄰居值接近。請參閱GZIPOutputStream

+0

使用底片也是一個想法,我想到了,那麼你會如何消除它們?你能舉一個使用你建議的壓縮的例子:我應該使用哪個類/方法? – Kuzeko

+0

@Kuzeko我已經用編碼/解碼邏輯的例子更新了答案。另外還增加了對GZIPOutputStream的引用,用於替代方法。 – apangin

3

您似乎很重視緊湊性和速度。要將這些降至真正的最低水平,需要進行大量優化。而且,我的意思是,比你的典型開發人員必須處理的要多得多。

而不是做這個自己,你將是明智的研究現有的數據庫解決方案。這些數據庫的開發人員多年來一直致力於理解執行這些操作的最有效方式,而且開銷遠低於您的想象。更不用說您獲得免費的正確性和可靠性。

我會用一個股票數據庫解決方案(只是鞭打一個mysql,瑪麗亞,或者Postgres的實例,並將其發送到鎮),看看是否能滿足您的性能指標。如果沒有,找到它不符合的具體指標,並將其調整到那些指標。你問的事情需要你的數據的專業知識和實驗與它的能力,是任何人在互聯網上可以做的(或將預期免費做。)

+0

這似乎已經引起了投票反對。我並不特別介意,但我很想知道這個答案有什麼可以改進的! – corsiKa

+0

這是我的投票,對不起。你建議看看現有的數據庫,但我不明白這是如何回答這個問題的。你知道DBMS擅長壓縮int64系列嗎?爲什麼您認爲關係數據庫可能對此有所幫助,當時所描述的場景更多是關鍵值使用?你爲什麼暗示作者還沒有研究過使用DBMS的可能性?鑑於建議作爲評論是好的,但作爲答案不夠有建設性。 – apangin

+1

@apangin問題中沒有任何內容表明OP已經查看了現有的數據庫解決方案,以及爲什麼最常見的解決方案不符合標準,所以很可能OP沒有考慮它。就「壓縮」而言,事實是,除非OP有一個能夠在功能上運行並可以運行基準的解決方案,否則對磁盤使用率和速度等進行優化是毫無價值的。就關係vs nosql dbs而言,我的經驗是他們處理文本記錄的方式比二進制更好,但無論如何,請嘗試使用Mongo實例。但是使用現有的解決方案而不是先滾動自己的解決方案 – corsiKa

相關問題