時序資料庫 Apache-IoTDB 源碼解析之文件索引塊(五)

来源:https://www.cnblogs.com/liutaohua/archive/2020/02/14/12307456.html
-Advertisement-
Play Games

上一章聊到 TsFile 的文件組成,以及數據塊的詳細介紹。詳情請見: 時序資料庫 Apache-IoTDB 源碼解析之文件數據塊(四) 打一波廣告,歡迎大家訪問IoTDB 倉庫,求一波 Star。 這一章主要想聊聊: TsFile索引塊的組成 索引塊的查詢過程 索引塊目前在做的改進項 索引塊 索引 ...


上一章聊到 TsFile 的文件組成,以及數據塊的詳細介紹。詳情請見:

時序資料庫 Apache-IoTDB 源碼解析之文件數據塊(四)

打一波廣告,歡迎大家訪問IoTDB 倉庫,求一波 Star。

這一章主要想聊聊:

  1. TsFile索引塊的組成
  2. 索引塊的查詢過程
  3. 索引塊目前在做的改進項

索引塊

索引塊結構圖

索引塊由兩大部分組成,其寫入的方式是從左到右寫入,也就是從文件頭向文件尾寫入。但讀出的方式是先讀出TsFileMetaData 再讀出 TsDeviceMetaDataList 中的具體一部分。我們按照讀取數據的順序介紹:

TsFileMetaData

TsFileMetaData屬於文件的 1 級索引,用來索引 Device 是否存在、在哪裡等信息,其中主要保存了:

  1. DeviceMetaDataIndexMap:Map結構,Key 是設備名,Value 是 TsDeviceMetaDataIndex ,保存了包含哪些 Device(邏輯概念上的一個集合一段時間內的數據,例如前幾章我們講到的:張三、李四、王五)以及他們的開始時間及結束時間、在左側 TsDeviceMetaDataList 文件塊中的偏移量等。
  2. MeasurementSchemaMap:Map結構,Key 是測點的一個全路徑,Value 是 measurementSchema ,保存了包含的測點數據(邏輯概念上的某一類數據的集合,如體溫數據)的原信息,如:壓縮方式,數據類型,編碼方式等。
  3. 最後是一個布隆過濾器,快速檢測某一個 時間序列 是不是存在於文件內(這裡等聊到 server 模塊寫文件的策略時候再聊)。我們知道這個過濾器的特點就是:沒有的一定沒有,但有的不一定有。為了保證準確性和過濾器序列化後的大小均衡,這裡提供了一個 1% - 10% 錯誤率的可配置,當為 1% 錯誤率時,保存 1 萬個測點信息,大概是 11.7 K。

我們再回想 SQL :SELECT 體溫 FROM 王五 WHERE time = 1 。讀文件的過程就應該是:

  1. 先用布隆過濾器判斷文件內是否有王五的體溫列,如果沒有,查找下一個文件。
  2. 從 DeviceMetaDataIndexMap 中找到王五的 TsDeviceMetaDataIndex ,從而得到了王五的 TsDeviceMetadata 的 offset,接下來就尋道至這個 offset 把王五的 TsDeviceMetadata 讀出來。
  3. MeasurementSchemaMap 不用關註,主要是給 Spark 使用的,ChunkHeader 中也保存了這些信息。

TsDeviceMetaDataList

TsDeviceMetaDataList 屬於文件的 2 級索引,用來索引具體的測點數據是不是存在、在哪裡等信息。其中主要保存了:

  1. ChunkGroupMetaData:ChunkGroup 的索引信息,主要包含了每個 ChunkGroup 數據塊的起止位置以及包含的所有的測點元信息(ChunkMetaData)。
  2. ChunkMetaData :Chunk 的索引信息,主要包含了每個設備的測點在文件中的起止位置、開始結束時間、數據類型和預聚合信息。

上面的例子中,從 TsFileMetadata 已經拿到了王五的 TsDeviceMetadataIndex,這裡就可以直接讀出王五的 TsDeviceMetadata,並且遍歷裡邊的 ChunkGroupMetadata 中的 ChunkMetadata,找到體溫對應的所有的 ChunkMetadata。通過預聚合信息對時間過濾,判斷能否使用當前的 Chunk 或者能否直接使用預聚合信息直接返回數據(等介紹到 server 的查詢引擎時候細聊)。

如果不能直接返回,因為 ChunkMetaData 包含了這個 Chunk 對應的文件的偏移量,只需要使用 seek(offSet) 就會跳轉到數據塊,使用上一章介紹的讀取方法進行遍歷就完成了整個讀取。

預聚合信息(Statistics)

文中多次提到了預聚合在這裡詳細介紹一下它的數據結構。

// 所屬文件塊的開始時間
private long startTime;  
// 所屬文件塊的結束時間
private long endTime;
// 所屬文件塊的數據類型
private TSDataType tsDataType;
// 所屬文件塊的最小值
private int minValue;  
// 所屬文件塊的最大值
private int maxValue;  
// 所屬文件塊的第一個值
private int firstValue;  
// 所屬文件塊的最後一個值
private int lastValue;  
// 所屬文件塊的所有值的和
private double sumValue;

這個結構主要保存在 ChunkMetaData 和 PageHeader 中,這樣做的好處就是,你不必從硬碟中讀取具體的Page 或者 Chunk 的文件內容就可以獲得最終的結果,例如:SELECT SUM(體溫) FROM 王五 ,當定位到 ChunkMetaData 時,判斷能否直接使用這個 Statistics 信息(具體怎麼判斷,之後會在介紹 server 時具體介紹),如果能使用,那麼直接返回 sumValue。這樣返回的速度,無論存了多少數據,它的聚合結果響應時間簡直就是 1 毫秒以內。

樣例數據

我們繼續使用上一章聊到的示例數據來展示。

時間戳人名體溫心率
1580950800 王五 36.7 100
1580950911 王五 36.6 90

完整的文件信息如下:

            POSITION|	CONTENT
            -------- 	-------
                   0|	[magic head] TsFile
                   6|	[version number] 000002
                    // 數據塊開始
|||||||||||||||||||||	[Chunk Group] of wangwu begins at pos 12, ends at pos 253, version:0, num of Chunks:2
                  12|	[Chunk] of xinlv, numOfPoints:1, time range:[1580950800,1580950800], tsDataType:INT32, 
                     	[minValue:100,maxValue:100,firstValue:100,lastValue:100,sumValue:100.0]
                    |		[marker] 1
                    |		[ChunkHeader]
                    |		1 pages
                 121|	[Chunk] of tiwen, numOfPoints:1, time range:[1580950800,1580950800], tsDataType:FLOAT, 
                     	[minValue:36.7,maxValue:36.7,firstValue:36.7,lastValue:36.7,sumValue:36.70000076293945]
                    |		[marker] 1
                    |		[ChunkHeader]
                    |		1 pages
                 230|	[Chunk Group Footer]
                    |		[marker] 0
                    |		[deviceID] wangwu
                    |		[dataSize] 218
                    |		[num of chunks] 2
|||||||||||||||||||||	[Chunk Group] of wangwu ends
                    // 索引塊開始
                 253|	[marker] 2
                 254|	[TsDeviceMetadata] of wangwu, startTime:1580950800, endTime:1580950800
                    |		[startTime] 1580950800
                    |		[endTime] 1580950800
                    |		[ChunkGroupMetaData] of wangwu, startOffset12, endOffset253, version:0, numberOfChunks:2
                    |			[ChunkMetaData] of xinlv, startTime:1580950800, endTime:1580950800, offsetOfChunkHeader:12, dataType:INT32, statistics:[minValue:100,maxValue:100,firstValue:100,lastValue:100,sumValue:100.0]
                    |			[ChunkMetaData] of tiwen, startTime:1580950800, endTime:1580950800, offsetOfChunkHeader:121, dataType:FLOAT, statistics:[minValue:36.7,maxValue:36.7,firstValue:36.7,lastValue:36.7,sumValue:36.70000076293945]
                 446|	[TsFileMetaData]
                    |		[num of devices] 1
                    |			[TsDeviceMetadataIndex] of wangwu, startTime:1580950800, endTime:1580950800, offSet:254, len:192
                    |		[num of measurements] 2
                    |		2 key&measurementSchema
                    |		[createBy isNotNull] false
                    |		[totalChunkNum] 2
                    |		[invalidChunkNum] 0
                    //布隆過濾器
                    |		[bloom filter bit vector byte array length] 30
                    |		[bloom filter bit vector byte array] 
                    |		[bloom filter number of bits] 256
                    |		[bloom filter number of hash functions] 5
                 599|	[TsFileMetaDataSize] 153
                 603|	[magic tail] TsFile
                 609|	END of TsFile

當執行: SELECT 體溫 FROM 王五 時:

  1. 從 599 開始讀,1 級索引長度為 153.
  2. 599 - 153 = 446 就是 1 級索引讀開始位置,並讀出 TsDeviceMetadataIndex of 王五,其中記錄了,王五設備的 2 級索引的 offset 為 254.
  3. 跳到 254 開始讀 2 級索引,找到 ChunkMetaData of 體溫, 其中記錄了體溫數據的 Chunk 的offset 為 121
  4. 跳到 121 ,這裡進入了數據塊,從 121 讀取到 230 ,讀出的數據就全部是體溫數據。

改進項

1. 只讀投影列

前面第 3 步中,讀取 2 級索引時候,會將這個設備下的所有測點數據全部讀出來,這依然不太符合只讀投影列的設計,所以在新的 TsFile 中,修改了 1級索引和 2 級索引的部分結構,使得讀出的數據更少,更高效。有興趣的同學可以關註 PR: Refactor TsFile #736

2. 文件級 Statistics

在物聯網場景中經常會涉及到查詢某個設備的最後狀態,比如:車聯網中,查詢車輛的末次位置( SELECT LAST(lat,lon) FROM VechicleID ),或者當前的點火、熄火狀態等 SELECT LAST(accStatus) FROM VechicleID 

或者當某些分頁查詢等情況時候,經常會使用到 COUNT(*) 等操作,這些都非常符合 Statistics 結構,這些場景涉及到的索引設計也都會體現到新的 TsFile 索引改動中。

到此已經介紹完了文件的整體結構,瞭解了大體的寫入和讀取過程,但是 TsFile 的 API 是如何設計的,怎樣在代碼里做一些特殊的功課,來繞過 Java 裝箱、GC 等問題呢?歡迎持續關註。。。。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Blend 修改TreeViewItem樣式 1、用Blend for Visual Studio 2019 新建Wpf項目,拖動一個TreeView控制項到Grid上 2、在繪圖視窗選中TreeViewItem,右鍵編輯模版 編輯副本 3、繪製水平、垂直虛線( "參考博文" ) 在TreeViewI ...
  • ASPNetCore 發佈到IIS 準備工作 1.1. 安裝IIS。(具體操作不再說明) 安裝成功後再瀏覽器輸入localhost得到的頁面如下 1.2. 安裝dotnet-hosting-2.2.2-win.exe安裝成功後在IIS 中可以看到如下兩個程式 這兩個程式對應得NetCore的版本不一 ...
  • 1.Ctrl+s:快速保存代碼 一定要記得隨時隨地用 Ctrl+s 來保存我們的代碼哦!!!不然等到電腦關機或者是使用的Eclipse突然閃退就欲哭無淚了。此時腦海裡就突然出現了嗶嗶嗶的畫面~ 2.Alt+/:自動補全代碼或者提示代碼後半部分 牆裂推薦大家使用啊,真的是超級好用了。 給大家舉一個例子 ...
  • 在看 apue 第 19 章偽終端第 6 節使用 pty 程式時,發現“檢查長時間運行程式的輸出”這一部分內容的實際運行結果,與書上所說有出入。 於是展開一番研究,最終發現是書上講的有問題,現在摘出來讓大家評評理。 先上代碼 pty.c pty_fun.c 這是書上標準的 pty 程式,簡單說起來就 ...
  • 背景介紹 我們在工作中難免會寫一些重覆性的代碼,所以需要我們具備一定的抽象能力,比如把共同的邏輯抽取到抽象類中,也可以通過一些工具類來避免冗餘代碼 今天這篇文章就是把一個調用服務的重試功能抽取出一個工具類,以備復用。這裡為了方便介紹,把調用服務簡化成方法的調用,被調用的 foo 方法如下: ~~~ ...
  • 1 SQL 的哲學 形如 Linux 哲學一切都是文件,在 SQL 領域也有這樣一條至理名言 2 關係資料庫 所謂關係資料庫(Relational database)是創建在關係模型基礎上的資料庫,藉助於集合代數等數學概念和方法來處理資料庫中的數據。 現實世界中的各種實體以及實體之間的各種聯繫均用關 ...
  • 該文為《 MySQL 實戰 45 講》的學習筆記,感謝查看,如有錯誤,歡迎指正 一、索引簡介 索引就類似書本的目錄,作用就是方便我們更加快速的查找到想要的數據。 索引的實現方式比較多,常見的有 ,`有序數組 搜索樹`。 1.1 哈希表 是將數據以 的形式存儲起來,簡單來說就是將 通過哈希函數換算成數 ...
  • 資料庫索引是資料庫系統中一個重要的概念,索引也叫做 key ,是一種用於提升資料庫查詢效率的數據結構,我們可以把索引理解成一本書的目錄,通過目錄我們可以快速找到對應章節的內容,同樣的,通過資料庫索引,我們可以快速找到數據表中對應的記錄。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...