儲存系統實現-跳躍表實現索引檢索

iteye_21202發表於2013-05-26

這一篇是我所實現的一個通過跳躍表的方式進行索引的檢索。跳躍表的基本思路把單步檢索擴充套件到多步檢索,這樣依賴減少檢索的步驟來升效能。

先用一張流程圖來闡述我檢索的步驟。

讀索引整體流程圖:

這裡舉一個具體的例子來說一下檢索的步驟。這裡說一種檢索到的情況,假設整個檔案表10萬條,id是連續自增,檢索id=2312的值

第一步:走快取(這裡是第一次檢索肯定不能命中快取)

第二步:走千步長

1)id=1000,小於2312,繼續

2)id=2000,小於2312,繼續

3) id=3000,大於2312,回退到id=2000的值

第三步:走百步長

1)id=2100,小於2312,繼續

2)id=2200,小於2312,繼續

3)id=2300,小於2312,繼續

4)id=2400,大於2312,回退到id=2300的值

第四步:走十步長

1)id=2310,小於2312,繼續

2)id=2320,大於2312,回退到id=2310的值

第五步:走單步長

1)id=2311,小於2312,繼續

2)id=2312,等於2312,定位到該值,返回資料

從這裡可以看出檢索這樣一個值,最多隻需要11步,如果快取命中的話只需要一步就找到值,而如果順序檢索的話則需要2312步才能檢索到值,這樣檢索效能得到極大的提升。

下面把兩程式碼程式碼給貼出來。

    /**
     * 先走一級步長,如果id>key,回退,走二級步長,id>key,一步一步走
     * 
     * @param id
     * @return
     */
    public synchronized DataOffset read(int id) {
        DataOffset offset = getPosFromCache(id);
        if(offset!=null){
            return offset;
        }
        long len;
        try {
            len = reader.length();
            //如果長度大於兩倍一級步長,先走一級步長
            int key = goByStepLevel(len, 0, id, 0, stepLevel_1000);
            if (key != 0) {
                key = goByStepLevel(len, reader.getFilePointer(), id, 0, stepLevel_100);
                if (key != 0) {
                    key = goByStepLevel(len, reader.getFilePointer(), id, 0, stepLevel_10);
                    if (key != 0) {
                        //直接走0級步長
                        System.out.println("[IndexFileReader.read]key="+key);
                        key = goByStepLevel(len, reader.getFilePointer(), id, 0, skip);
                    }
                }
            }
            System.out.println("[IndexFileReader.read]key2="+key);
            if (key == 0) {
                //拿到偏移量
                reader.readInt();
                offset = new DataOffset();
                offset.setStartPos(reader.readLong());
                //offset.setEndPos(reader.readLong());
                //byte[] bytes = ByteUtil.longToByte(offset.getStartPos(),offset.getEndPos());
                lruCache.put(indexPath + id, offset.getStartPos());
                return offset;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


這個方法是一個私有方法,是一個遞迴方法,走步長的時候通過遞迴走步長。

    /**
     * @param len
     * @param nowStep
     * @param id
     * @param key
     * @param stepLevel
     * @return 1:代表值還在後面,0:代表該節點即為值,-1:值在前面
     * @throws IOException
     */
    private int goByStepLevel(long len, long nowStep, int id, int key, long stepLevel)
            throws IOException {
        //如果後面的步驟已經小於一級步長
        if (len > nowStep + stepLevel) {
            //如果值仍然在後面,走一級步長
            if (id > key) {
                nowStep = nowStep + stepLevel;
                reader.seek(nowStep);
                //這裡已經讀出一個值了,需要回退
                key = reader.readInt();
                return goByStepLevel(len, nowStep, id, key, stepLevel);
            } else if (id < key) {
                //退出,走二級步長
                reader.seek(nowStep - stepLevel);
                return 1;
            } else {
                //相等,找到值直接定位到該值
                reader.seek(nowStep);
                return 0;
            }
        } else {
            //如果值仍然在後面,走二級步長
            if (id > key) {
                reader.seek(nowStep);
                return -1;
            } else if (id < key) {
                long preStep = nowStep - stepLevel;
                if (preStep > 0) {
                    reader.seek(preStep);
                } else {
                    //如果小於,則直接歸0,走二級步長
                    reader.seek(0);
                }
                return 1;
            } else {
                //相等,如果找到值,直接seek到該偏移
                reader.seek(nowStep);
                return 0;
            }
        }
    }

總結:這裡跳躍表的實現就寫完了。歡迎大家拍磚

 

相關文章