簡體   English   中英

高效的數據結構可存儲數百萬條記錄

[英]Efficient Data Structure To Store Millions of Records

我有一個包含數百萬個記錄的輸入文件,每個記錄又包含數千個列,其中每個列都由定界符分隔。

記錄和列的數量可能因文件而異。

我有一個要求,我必須解析這些記錄並將它們存儲在java對象中,以便可以將其進一步傳遞給Drools Framework進行列級驗證。

這就是我的輸入數據和架構文件的樣子。

輸入文件 :

John|Doe|35|10 Floyd St|132|Los Angeles|CA|USA ... and so on 
...
...
Millions records like this

架構文件:

firstName|String|false|20|NA
lastName|String|false|20|NA
age|Integer|false|3|NA
addressLine1|String|false|20|NA
addressLine2|String|false|20|NA
city|String|false|5|NA
state|String|false|10|NA
country|String|false|10|NA

我嘗試在地圖的幫助下實現此解決方案,並創建了一個包含該地圖的Java類。

class GenericRecord {
   Map<String,FieldSpecification> properties; //used HashMap as an implementation
}

class FieldSpecification {
    public String fieldName;
    public String dataType;
    public int length;
    public String value;
    public String format;
}

對於輸入文件中的覆蓋率行,我正在創建一個Record對象,並使用map存儲其列的值。 除此之外,我還在FieldSpecification Object中存儲有關列的元數據,例如dataType,length,format等。

對於我的輸入文件中的幾千行,它可以正常工作,但是一旦行數開始增加,它就會由於內存問題(如預期的那樣)而開始崩潰。 因為它正在創建數百萬個具有數千個鍵的對象的地圖。

我知道這不是解決此類問題的有效解決方案。

因此,我擔心的是基於內存的解決方案是否可以在我的方案中工作,或者我必須更喜歡基於磁盤的解決方案,例如嵌入式DB或基於磁盤的Maps。

請告知我是否可以使用其他任何開源Map實現。

注意:對於文件解析和數據驗證,我使用的是hadoop,它在40個節點的集群上運行。

這是我的映射器的流程和實現:

接收值作為完整行,此后將其傳遞到Java框架,該框架將其轉換為相應的GenericObject(如上所述),然后將此對象傳遞給drools框架以進行進一步驗證。

映射器實現:

public void map(LongWritable key , Text value , Context context) throws IOException, InterruptedException {

        //Convert the text value to string i.e line by line comes here
        String record = value.toString();





        // Develop a drools service that will take record as an input 
        // and will validate it on the basis of XL sheet provided
        workingMemory = knowledgeBase.newStatefulKnowledgeSession();
        DroolsObject recordObject = DroolsServiceImpl.validateByRecord(record, fileMetaData, workingMemory);



        //Check to validate if the processed record
        if(recordObject.isValid) {
            context.getCounter(AppCounter.VALID_RECORD).increment(1);
            mapperOutputKey.set("A");
            mapperOutputValue.set(recordObject.toString());
            context.write(mapperOutputKey,mapperOutputValue);
        }

        else {
            context.getCounter(AppCounter.INVALID_RECORD).increment(1);
            mapperOutputKey.set("R");
            mapperOutputValue.set(recordObject.toStringWithErrors());
            context.write(mapperOutputKey,mapperOutputValue);
        }
}

由於必須將文件中每個字節的數據保存在內存中(可能的分隔符除外),因此首先要查看文件的大小並將其與內存大小進行比較。 如果您的文件大於內存,請抓緊將其保存在內存中的整個想法。

如果內存大於文件 ,則有機會,盡管您需要仔細檢查此文件將來可能如何增長,程序將在哪些平台上運行,等等。

因此, 假設它適合您,您的數據結構將更加高效。 一種簡單的節省內存的方法是抓取地圖,然后將每個記錄保存為字符串(以文件中的編碼)。 字符串數組應具有最小的開銷,盡管您需要確保在填充原始數組時不會不斷調整其大小。

在數據結構變大時保持數據結構簡單,可以節省大量內存。

另外,如果數據很容易裝入內存,則可能需要對JVM進行一些調整,以為其分配足夠的內存( 使用-Xmx更改堆大小)以使JVM足夠大。 我希望您在64位平台上使用64位JVM。

我建議將數據保留在一個( byte[][] )表中,並通過其編號引用行。 然后,您可以使用游標按需讀取相應的字段:

class FieldSpecification {
    private final int row;
    private final byte[][] mem;

    public String fieldName();
    public String dataType();
    public int length();
    public String value();
    public String format();
}

垃圾收集器應該很容易地處理這些對象。 您只需要關心他們的生命周期。

如果字節數組不適合您的內存,那么無論如何您都會被搞砸。

然后,您可以通過將名稱映射到行號來實現映射。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM