新聞中心
開(kāi)篇引題
上一篇我們提到了Apache IoTDB如何支持Nullable的問(wèn)題,IoTDB用NaN來(lái)代表沒(méi)有值,查詢(xún)之后我們發(fā)現(xiàn)NaN代表來(lái)當(dāng)前數(shù)據(jù)類(lèi)型的默認(rèn)值。如:FLOAT 的默認(rèn)值就是 0.0.

那么這個(gè)結(jié)果是在v.0.11.2 版本的行為,但從NaN的設(shè)計(jì)來(lái)說(shuō),這是一個(gè)錯(cuò)誤的行為,或者說(shuō)這是一個(gè)bug,在IoTDB-1158里面的討論區(qū),我們也提到了這一點(diǎn),目前在master已經(jīng)修復(fù)了。
那么今天我們聊一下,有了NaN我們目前還需要對(duì)Apache IoTDB增加Nallable的語(yǔ)法支持嗎?
Nallable的本質(zhì)
任何功能的支持我們可能需要考慮兩個(gè)維度,一是業(yè)務(wù)需求,客觀(guān)業(yè)務(wù)場(chǎng)景需要的功能一定是我們需要解決的,二是領(lǐng)域標(biāo)準(zhǔn),做時(shí)序數(shù)據(jù)庫(kù)我們要考慮傳統(tǒng)數(shù)據(jù)庫(kù)標(biāo)準(zhǔn),我們要考慮時(shí)序領(lǐng)域的標(biāo)準(zhǔn)。
在業(yè)務(wù)角度,業(yè)務(wù)期望的是當(dāng)由于某種原因,無(wú)法提供當(dāng)前時(shí)刻某個(gè)傳感器的值的時(shí)候,需要在查詢(xún)的是被業(yè)務(wù)感知的。那么IoTDB里面提供了NaN的策略來(lái)支持如 Float、Double等數(shù)值的不存在的情況,NaN(Not a number)。
在領(lǐng)域標(biāo)準(zhǔn)方面,傳統(tǒng)數(shù)據(jù)庫(kù)是有如 NOT NULL 的語(yǔ)法支持的,也就是說(shuō)字段類(lèi)型聲明時(shí)候如果沒(méi)有聲明NOT NULL默認(rèn)用戶(hù)在整行插入時(shí)候是可以不攜帶該字段的值的,而顯示聲明了NOT NULL 那么每次insert 語(yǔ)句就必須攜帶當(dāng)前的值。
今天我們文末就以Apache IoTDB Master代碼再看看對(duì)NaN的支持情況,基于Commit: b986cd1e5f
同類(lèi)(InfluxDB)行為
我們有時(shí)候在買(mǎi)東西時(shí)候經(jīng)常貨比三家,不管這物品是好是壞,是貴還是便宜,我們看看其他商家是什么品質(zhì),是什么價(jià)格,就能輔助我們做判斷。那么學(xué)習(xí)Apache IoTDB的小伙伴,我也建議對(duì)InfluxDB有一定的了解. 目前InFluxDB穩(wěn)定版本是1.8.4,我們就以1.8.4為例體驗(yàn)一下InfluxDB對(duì)null的支持方式。
二進(jìn)制安裝
我們今天在macOS下進(jìn)行操作,首先確保你已經(jīng)安裝了brew工具。然后我們可以一條命令安裝InfluxDB v1.8.4.
brew update
brew install influxdb
啟動(dòng)InfluxDB服務(wù)
influxd
客戶(hù)端連接并創(chuàng)建測(cè)試數(shù)據(jù)庫(kù)
jincheng:~ jincheng.sunjc$ influx -precision rfc3339
Connected to http://localhost:8086 version 1.8.4
InfluxDB shell version: 1.8.4
CREATE DATABASE "lemming";
use lemming;
INSERT cpu,host=LemmingServer,region=zh_hz value=1.68
SELECT * FROM cpu;
Nullable的支持情況
- 單值插入Null(參考InfluxDB的歷史信息)
- https://github.com/influxdata/influxdb/issues/7722
- https://github.com/influxdata/influxdb/pull/2429
- https://github.com/influxdata/influxdb/blob/v1.8.4/CHANGELOG.md
> INSERT cpu,host=LemmingServer,region=zh_hz value=
ERR: {"error":"unable to parse 'cpu,host=LemmingServer,region=zh_hz value=': missing field value"}
INSERT cpu,host=LemmingServer,region=zh_hz value=''
ERR: {"error":"unable to parse 'cpu,host=LemmingServer,region=zh_hz value=''': invalid boolean"}
> INSERT cpu,host=LemmingServer,region=zh_hz value=null
ERR: {"error":"unable to parse 'cpu,host=LemmingServer,region=zh_hz value=null': invalid number"}
如上現(xiàn)象說(shuō)明InfluxDB本身對(duì)單值的插入也是不支持Null的。那么這個(gè)和IoTDB的現(xiàn)狀是一樣的。我們?cè)賮?lái)看看多值同時(shí)插入的時(shí)候“現(xiàn)象”。
- 多插入Null
正常插入:
> INSERT temperature,machine=unit42,type=assembly external=25,internal=37
> select * from temperature;
name: temperature
time external internal machine type
---- -------- -------- ------- ----
2021-02-24T04:03:35.634296Z 25 37 unit42 assembly
internal為空:
> INSERT temperature,machine=unit42,type=assembly external=25,internal=
ERR: {"error":"unable to parse 'temperature,machine=unit42,type=assembly external=25,internal=': missing field value"}
internal為null:
> INSERT temperature,machine=unit42,type=assembly external=25,internal=null
ERR: {"error":"unable to parse 'temperature,machine=unit42,type=assembly external=25,internal=null': invalid number"}
不攜帶internal:
> INSERT temperature,machine=unit42,type=assembly external=25
> select * from temperature;
name: temperature
time external internal machine type
---- -------- -------- ------- ----
2021-02-24T04:03:35.634296Z 25 37 unit42 assembly
2021-02-24T04:05:37.18028Z 25 unit42 assembly
所以根據(jù)目前表現(xiàn),InfulxDB v1.8.4 不支持直接插入Null,但是可以在多值插入時(shí)候,不攜帶某個(gè)值,也就是空值的支持。
IoTDB Master 行為(b986cd1e5f)
我們基于 b986cd1e5f進(jìn)行編譯,如下:
啟動(dòng)服務(wù)和CLI
啟動(dòng)服務(wù),如下:
jincheng:apache-iotdb-0.12.0-SNAPSHOT-all-bin jincheng.sunjc$ nohup sbin/start-server.sh >/dev/null 2>&1 &
[1] 22357
注意我們最新的發(fā)布目錄已經(jīng)有變化`apache-iotdb-0.12.0-SNAPSHOT-all-bin`。
連接服務(wù)進(jìn)入CLI,如下:
sbin/start-cli.sh -h 127.0.0.1 -p 6667 -u root -pw root
NaN的支持
先進(jìn)行一些初始化,如下:
SET STORAGE GROUP TO root.ln
CREATE TIMESERIES root.ln.wf01.wt01.status WITH DATATYPE=BOOLEAN, ENCODING=PLAIN
CREATE TIMESERIES root.ln.wf01.wt01.temperature WITH DATATYPE=FLOAT, ENCODING=RLE
- 單值的插入
正常插入
INSERT INTO root.ln.wf01.wt01(timestamp,status) values(100,true);
INSERT INTO root.ln.wf01.wt01(timestamp,temperature) values(200,20.71)
我們可以看到,單值正常插入都是OK的,同時(shí)我們?cè)诓樵?xún)時(shí)候,如果在相同ts某些值不存在時(shí)候,我們查詢(xún)出來(lái)顯示是null的,用戶(hù)可以感知到多時(shí)間序列按時(shí)間對(duì)齊形成一行數(shù)據(jù)時(shí)候哪些字段為null。
異常插
IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,temperature) values(200,)
Msg: 401: Error occurred while parsing SQL to physical plan: line 1:64 mismatched input ')' expecting {NOW, TRUE, FALSE, '-', '.', 'NaN', INT, EXPONENT, DATETIME, DOUBLE_QUOTE_STRING_LITERAL, SINGLE_QUOTE_STRING_LITERAL}
IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,temperature) values(200,'')
Msg: 313: failed to insert measurements [temperature] caused by For input string: "''"
IoTDB> INSERT INTO root.ln.wf01.wt01(timestamp,temperature) values(200,null)
Msg: 401: Error occurred while parsing SQL to physical plan: line 1:64 mismatched input 'null' expecting {NOW, TRUE, FALSE, '-', '.', 'NaN', INT, EXPONENT, DATETIME, DOUBLE_QUOTE_STRING_LITERAL, SINGLE_QUOTE_STRING_LITERAL}
IoTDB>
這個(gè)現(xiàn)象其實(shí)與InfluxDB的表象也是一樣的,我們這樣設(shè)計(jì)也是合理的,因?yàn)槲覀兪菑?qiáng)類(lèi)型系統(tǒng),聲明了FLOAT類(lèi)型,就必須插入的是FLOAT值。那么我們?cè)倏纯炊嘀挡迦氲男袨楸憩F(xiàn)。
- 多值的插入
正常插入
INSERT INTO root.ln.wf01.wt01(timestamp,status,temperature) values(200,false,20.71)
上面一切正常,注意一點(diǎn),我們插入時(shí)間戳是用的是200,那么會(huì)覆蓋之前的相同時(shí)間戳的值。
缺值插入
INSERT INTO root.ln.wf01.wt01(timestamp,status,temperature) values(200,false,)
INSERT INTO root.ln.wf01.wt01(timestamp,status,temperature) values(200,false,null)
INSERT INTO root.ln.wf01.wt01(timestamp,status,temperature) values(200,false,NaN)
其實(shí),大家發(fā)現(xiàn)多值插入,和單值插入的支持是一樣的,如果顯示的指定要要插入某個(gè)列的值,那么就必須在values里面有其合法的值進(jìn)行插入。如果沒(méi)有業(yè)務(wù)值,IoTDB為大家提供了NaN來(lái)表示沒(méi)有具體的數(shù)值。當(dāng)然,NaN不僅僅在多值插入時(shí)候可以應(yīng)用,在單值進(jìn)行插入時(shí)候也是一樣可以支持的。比如:
篇尾提問(wèn):為啥一定需要NaN呢?
看到這里大家也許會(huì)有個(gè)疑問(wèn),既然我在插入時(shí)候沒(méi)有值我就可以不插入,在查詢(xún)的時(shí)候 IoTDB可以按時(shí)間對(duì)齊形成一行數(shù)據(jù)顯示,對(duì)應(yīng)時(shí)間戳不存在的值用null來(lái)顯示來(lái),那么我們?yōu)槭裁催€要用NaN呢?
這個(gè)就和業(yè)務(wù)有點(diǎn)關(guān)系來(lái),比如:如果一個(gè)列的值是null顯示的,那么到底是當(dāng)時(shí)這個(gè)時(shí)間點(diǎn)真的設(shè)備沒(méi)有值上送,還是雖然設(shè)備上送了數(shù)值,但是由于業(yè)務(wù)程序bug(或者值不合法)導(dǎo)致沒(méi)有插入成功呢?這個(gè)問(wèn)題是很難回答了,因?yàn)椋?/p>
- 設(shè)備沒(méi)上送值我們不插入,查詢(xún)時(shí)候是null,
- 設(shè)備雖然上送了,但是業(yè)務(wù)代碼有bug沒(méi)有插入成功,查詢(xún)時(shí)候也是null,
但是如果我們有NaN的支持,那么我們?cè)跇I(yè)務(wù)代碼里面每一個(gè)時(shí)間戳都對(duì)應(yīng)的所有列我們都進(jìn)行值的插入,如果沒(méi)有值或者值不合法,那么我們就顯示的設(shè)置一個(gè)NaN代表業(yè)務(wù)本身在那個(gè)時(shí)刻沒(méi)有收到合法的值,而一旦出現(xiàn)null,那就代表在那個(gè)時(shí)刻業(yè)務(wù)沒(méi)有收到設(shè)備的任何數(shù)據(jù)事件,也沒(méi)有進(jìn)行任何insert動(dòng)作,所以查詢(xún)時(shí)候就是null,就可以方便的定位問(wèn)題了。
再回到開(kāi)篇的問(wèn)題,有了NaN我們目前還需要對(duì)Apache IoTDB增加Nallable的語(yǔ)法支持嗎?
NaN 不等于 Nullable
NaN解決了Float/Double的某些場(chǎng)景的業(yè)務(wù)問(wèn)題,但是其他非數(shù)值類(lèi)型,如今天涉及到的Boolean類(lèi)型是沒(méi)有支持,從語(yǔ)義角度非數(shù)值類(lèi)型也不應(yīng)該有NaN的設(shè)計(jì),所以關(guān)于非數(shù)值類(lèi)型的Null的考慮還是值得進(jìn)一步討論的。
下一篇聊什么?
我們希望每一篇都聊點(diǎn)用戶(hù)提到的問(wèn)題,下一篇我們聊了InfluxDB和IoTDB如何解決下面這個(gè)朋友的問(wèn)題:
如果你有答案,也可以提前留言,看看你和我的思考是否一樣... ???? 我們今天就到這里,下次見(jiàn)。
作者介紹
孫金城,社區(qū)編輯,Apache Flink PMC 成員,Apache Beam Committer,Apache IoTDB PMC 成員,ALC Beijing 成員,Apache ShenYu 導(dǎo)師,Apache 軟件基金會(huì)成員。關(guān)注技術(shù)領(lǐng)域流計(jì)算和時(shí)序數(shù)據(jù)存儲(chǔ)。
標(biāo)題名稱(chēng):No.5時(shí)序數(shù)據(jù)庫(kù)隨筆 - NaN的支持
瀏覽路徑:http://fisionsoft.com.cn/article/dhhiioi.html


咨詢(xún)
建站咨詢(xún)
