1.概述
索引和底(di)層存(cun)儲(chu)息(xi)(xi)息(xi)(xi)相關,doris采用LSM的(de)(de)(de)(de)存(cun)儲(chu)結(jie)構,數(shu)據(ju)(ju)首先會(hui)寫入(ru)Tablet對應的(de)(de)(de)(de)memtable中,memtable寫滿之(zhi)后,數(shu)據(ju)(ju)會(hui)flush寫入(ru)磁(ci)盤,形(xing)成一(yi)個個不可變的(de)(de)(de)(de)segment文件, 由于(yu)memtable用的(de)(de)(de)(de)是skiplist數(shu)據(ju)(ju)結(jie)構,skiplist數(shu)據(ju)(ju)是按(an)照(zhao)key排(pai)序的(de)(de)(de)(de),所以flush到(dao)磁(ci)盤的(de)(de)(de)(de)segment文件也(ye)是按(an)照(zhao)key排(pai)序的(de)(de)(de)(de),doris底(di)層是按(an)照(zhao)列(lie)(lie)存(cun)儲(chu)數(shu)據(ju)(ju)的(de)(de)(de)(de),存(cun)儲(chu)在一(yi)種SST的(de)(de)(de)(de)數(shu)據(ju)(ju)結(jie)構中,每列(lie)(lie)數(shu)據(ju)(ju)會(hui)被(bei)分為(wei)多個data page。
數據從memtable flush到磁盤分為兩個階段:
1.將memtable中的(de)行存結構(gou)轉換為(wei)列(lie)存結構(gou),并為(wei)每一列(lie)生成對應的(de)索引結構(gou)
2.將轉換后(hou)的列存結構寫入磁(ci)盤,生成segment文件。
segment文(wen)件(jian)分(fen)為數據區(qu)域、索引區(qu)域和footer三個部分(fen),如下圖所示(shi):

說明:
data region: 存儲各個列的數(shu)據(ju)信息,每列數(shu)據(ju)被分(fen)為多(duo)個data page。
index region: Doris 中將各個列的(de) index 數據(ju)統一(yi)存儲(chu)在 Index Region,這里(li)的(de)數據(ju)會按(an)照列粒度進行加載(zai),所以跟(gen)列的(de)數據(ju)信息分開存儲(chu)
footer信息
footer信息(xi)段在文件的尾部,存儲了文件的整(zheng)體結構(gou),包括數據域和索(suo)引域的位置等(deng),共(gong)分(fen)(fen)為SegmentFooterPB,CheckSum,Length,MAGIC CODE 4 個部分(fen)(fen)。
segementFooterPB定義了元(yuan)數(shu)據信(xin)息(xi)(xi),包(bao)括列的元(yuan)數(shu)據信(xin)息(xi)(xi),索引(yin)的元(yuan)數(shu)據信(xin)息(xi)(xi),前綴(zhui)索引(yin)信(xin)息(xi)(xi),總行數(shu)等,數(shu)據結構如下(xia):

2.索引
目前 Doris 主(zhu)要支持兩類(lei)索(suo)引:
- 內建的智能索引,包括前綴索引和 ZoneMap 索引。
- 用戶手動創建的二級索引,包括 倒排索引、 bloomfilter索引、 ngram bloomfilter索引 和bitmap索引。
2.1前綴索引
Doris 不支持在任(ren)意列上(shang)創建索引。Doris 這類 MPP 架構的(de) OLAP 數(shu)據(ju)庫(ku),通常都(dou)是通過提高(gao)并發,來處理(li)大量數(shu)據(ju)的(de)。
本(ben)質上(shang),Doris 的數據(ju)存(cun)儲在類似 SSTable(Sorted String Table)的數據(ju)結構(gou)中。該(gai)結構(gou)是一種有序的數據(ju)結構(gou),可以按照指定的列進(jin)行排序存(cun)儲。在這種數據(ju)結構(gou)上(shang),以排序列作為條件進(jin)行查找,會非(fei)常的高效(xiao)。
在 Aggregate、Unique 和 Duplicate 三種數(shu)據(ju)模型中(zhong)。底(di)層的(de)(de)數(shu)據(ju)存儲,是按(an)照各自建表語句(ju)中(zhong),AGGREGATE KEY、UNIQUE KEY 和 DUPLICATE KEY 中(zhong)指定的(de)(de)列進行排序存儲的(de)(de)。
而前綴(zhui)索(suo)引(yin),即(ji)在排序(xu)的基(ji)礎上,實現的一種根據給定前綴(zhui)列,快速(su)查詢數據的索(suo)引(yin)方式。前綴(zhui)索(suo)引(yin)又(you)叫Short Key Index。
2.1.1存儲結構
前(qian)(qian)綴索(suo)(suo)引(yin)是(shi)一種稀疏(shu)索(suo)(suo)引(yin),數(shu)據寫入過程中,每隔(ge)1024行(xing)會(hui)生成一個(ge)(ge)索(suo)(suo)引(yin)項(xiang),前(qian)(qian)綴索(suo)(suo)引(yin)會(hui)對(dui)每一個(ge)(ge)索(suo)(suo)引(yin)間隔(ge)的(de)(de)第一個(ge)(ge)數(shu)據行(xing)的(de)(de)前(qian)(qian)綴字段(duan)進(jin)行(xing)編碼,前(qian)(qian)綴字段(duan)的(de)(de)編碼與前(qian)(qian)綴字段(duan)的(de)(de)值具有相同的(de)(de)排(pai)序(xu)(xu)規則,即前(qian)(qian)綴字段(duan)的(de)(de)值排(pai)序(xu)(xu)越(yue)靠前(qian)(qian),對(dui)應的(de)(de)編碼值排(pai)序(xu)(xu)也(ye)越(yue)靠前(qian)(qian)。Segment 文件是(shi)按 Key 排(pai)序(xu)(xu)的(de)(de),因此,前(qian)(qian)綴索(suo)(suo)引(yin)項(xiang)也(ye)是(shi)按 Key 排(pai)序(xu)(xu)的(de)(de)。
一個 Segment 文件中的前綴索引數據保存在一個獨立的 Short Key Page 中,其中包含每一條前綴索引項的編碼數據、每一條前綴索引項的 offset、Short Key Page 的 footer 以及 Short Key Page 的 Checksum 信息。Short Key Page 的 footer 中記錄了 Page 的類型、前綴索引編碼數據的大小、前綴索引 offset 數據的大小、前綴索引項的數目等信息
Short Key Page 在 Segment 中的 offset 和大小會被保存在Segment文件的footer中,以便于數(shu)據讀(du)取時(shi)能夠正確地從Segment文件中加載出前(qian)綴(zhui)索引(yin)數(shu)據。前(qian)綴(zhui)索引(yin)的存儲(chu)結(jie)構如圖所示:

查詢(xun)時會先打開segment文件,然(ran)后在segment footer中找到short key page的offset及大小,然(ran)后讀(du)取對應的short key page中索引數據(ju),并(bing)解析每一(yi)條前綴索引項。
2.1.2索引生成規則
doris將一(yi)行數據的前36個(ge)字節作為前綴(zhui)索引,如果遇到varchar類(lei)型,前綴(zhui)索引會直接(jie)截斷,
2.1.3應用案例
-
以下(xia)表結構的前綴索引為 user_id(8 Bytes) + age(4 Bytes) + message(prefix 20 Bytes)。
ColumnName Type user_id BIGINT age INT message VARCHAR(100) max_dwell_time DATETIME min_dwell_time DATETIME -
以下表結構的前綴索引為(wei)(wei) user_name(20 Bytes)。即使沒有達到 36 個(ge)字節,因為(wei)(wei)遇到 VARCHAR,所以直接截斷,不再往(wang)后繼續。
ColumnName Type user_name VARCHAR(20) age INT message VARCHAR(100) max_dwell_time DATETIME min_dwell_time DATETIME
當我們的查詢條件,是前綴索引的前綴時,可以極大的加快查詢速度。比(bi)如在第(di)一個(ge)例子中,我(wo)們執行如下查詢:
SELECT * FROM table WHERE user_id=1829239 and age=20;
該查詢的效率會遠高于如下查詢:
SELECT * FROM table WHERE age=20;
所以在建表時,正確的選擇列順序,能夠極大地提高查詢效率。
2.2 Zone Map 索引
segment中的(de)每(mei)列(lie)數(shu)據和(he)列(lie)中的(de)每(mei)個(ge)data page也會(hui)(hui)有(you)zone map索引項,zone map索引記(ji)錄(lu)每(mei)列(lie)及(ji)列(lie)中每(mei)個(ge)data page的(de)最(zui)大(da)值(max value)最(zui)小值(min value),是否(fou)有(you)Null值(has null),是否(fou)有(you)非Null值(has not null)等信息(xi)。初始化時(數(shu)據為(wei)(wei)空時),max value會(hui)(hui)被(bei)設置為(wei)(wei)當前(qian)列(lie)類型的(de)最(zui)小值, min value會(hui)(hui)被(bei)設置為(wei)(wei)當前(qian)列(lie)類型的(de)最(zui)大(da)值,has null和(he)has not null均為(wei)(wei)false.
2.2.1索引生成規則
doris默認為key列(AGGREGATE KEY、UNIQ KEY 和 DUPLICATE KEY)開啟(qi)ZoneMap索(suo)引,當表模型為 DUPULCATE 時,所有字段會(hui)開啟(qi) ZoneMap 索(suo)引。
數據寫入時(shi),會給data page生成zone map索(suo)引(yin),當data page中有數據更(geng)新(xin)時(shi),對應的(de)zone map索(suo)引(yin)也要更(geng)新(xin)。更(geng)新(xin)規則如下:
1.如(ru)果新增的(de)數據為null, 則(ze)has null=true, 否則(ze)has not null=true
2.如果(guo)新(xin)增(zeng)數(shu)據(ju)小于(yu)(yu)zone map索引(yin)中(zhong)的(de)min value,則(ze)使用(yong)當前(qian)數(shu)據(ju)更新(xin)min value, 如果(guo)新(xin)增(zeng)數(shu)據(ju)大于(yu)(yu)zone map索引(yin)中(zhong)的(de)max value,則(ze)使用(yong)當前(qian)數(shu)據(ju)更新(xin)max value.
當一個Data Page寫滿之后,不僅會更新當前data page的zone map索引,也會更新data page所在列的索引。
2.2.2 應用
在查詢過(guo)程中,范圍條件(jian)過(guo)濾字(zi)段會根據(ju)zone map索引中的統計信(xin)息選取掃描的數(shu)據(ju)范圍。
查詢如下:
SELECT * FROM table WHERE age > 20 and age < 1000
在沒有命中 Short Key Index 的(de)(de)情(qing)況下(xia),會(hui)根據(ju)條件語(yu)句中 age 的(de)(de)查詢條件,利用 ZoneMap 索(suo)引(yin)找到應該掃(sao)描的(de)(de)數據(ju) ordinary 范圍,減少要掃(sao)描的(de)(de) page 數量。
2.3 Ordinal 索引
2.3.1索引生成規則
Doris 底層采用列存(cun)的方式來(lai)存(cun)儲數據(ju),每一列數據(ju)會被分(fen)為多(duo)個Data Page。
數(shu)據(ju)刷寫(xie)時(shi),會(hui)為每一個Data Page生(sheng)成(cheng)一條Ordinal索引項(xiang),該(gai)索引項(xiang)保(bao)存Data Page在(zai)Segment文件中(zhong)的(de)offset、Data Page的(de)大小以(yi)及(ji)Data Page的(de)起始(shi)行(xing)號,所有Data Page的(de)Ordinal索引項(xiang)會(hui)保(bao)存在(zai)一個Ordinal Index Page中(zhong), Ordinal Index Page在(zai)Segment文件中(zhong)的(de)offset以(yi)及(ji)Ordinal Index Page的(de)大小會(hui)被保(bao)存在(zai)Segment文件的(de)footer中(zhong),以(yi)便于數(shu)據(ju)讀取時(shi)能夠通(tong)過(guo)兩級索引找到(dao)Data Page(首先,通(tong)過(guo)Segment文件的(de)footer找到(dao)Ordinal Index Page,然后(hou),通(tong)過(guo)Ordinal Index Page中(zhong)的(de)索引項(xiang)找到(dao)Data Page)。
Ordinal Index Page包(bao)含(han)以下(xia)信息:所(suo)有Ordinal索(suo)(suo)引(yin)項(xiang)數(shu)據、Ordinal Index Page的(de)(de)footer以及Short Key Page的(de)(de)Checksum信息。Ordinal Index Page的(de)(de)footer中包(bao)含(han)當前(qian)Page的(de)(de)類型、Ordinal索(suo)(suo)引(yin)項(xiang)數(shu)據的(de)(de)大小(xiao)、Ordinal索(suo)(suo)引(yin)項(xiang)數(shu)目等信息。
如(ru)果列中(zhong)(zhong)只(zhi)有一(yi)個Data Page時,即該列只(zhi)有一(yi)條Ordinal索引(yin)項,則Segment文(wen)(wen)件中(zhong)(zhong)不需(xu)要保存該列的(de)Ordinal索引(yin)數(shu)據(ju)(ju),只(zhi)需(xu)要將這(zhe)唯一(yi)的(de)Data Page在(zai)Segment文(wen)(wen)件中(zhong)(zhong)的(de)offset以及該Data Page的(de)大小保存在(zai)Segment文(wen)(wen)件的(de)footer中(zhong)(zhong)。數(shu)據(ju)(ju)讀取時可以通過Segment文(wen)(wen)件的(de)footer直(zhi)接找到這(zhe)唯一(yi)的(de)Data Page。Ordinal索引(yin)的(de)存儲(chu)結構如(ru)圖3所示。
Ordinal索引(yin)的(de)作用是(shi)為了方(fang)便(bian)其他類型(xing)的(de)索引(yin)能夠使用統一的(de)方(fang)式(shi)查找Data Page,進而可以對其他類型(xing)的(de)索引(yin)屏蔽Data Page在Segment文(wen)件中的(de)offset

2.3.2查詢過濾
查(cha)詢時(shi),會(hui)加載每一個列(lie)(lie)的(de)Ordinal索(suo)引數據(ju)。通(tong)過Segment footer中記(ji)錄的(de)Ordinal索(suo)引的(de)Meta信息判(pan)斷當前(qian)(qian)列(lie)(lie)是否(fou)存在Ordinal Index Page,即(ji)判(pan)斷當前(qian)(qian)列(lie)(lie)是否(fou)有多個Data Page。
如果(guo)當前列存(cun)在(zai)Ordinal Index Page,則從(cong)Segment footer中獲(huo)取(qu)Ordinal Index Page在(zai)Segment中的(de)offset和(he)Ordinal Index Page的(de)大小(xiao),然(ran)后從(cong)Segment文件中讀取(qu)Ordinal Index Page數據,并解析出(chu)每一條Ordinal索(suo)引(yin)項,即可通過Ordinal索(suo)引(yin)項獲(huo)取(qu)當前列中每一個Data Page的(de)起(qi)始行號(hao)、Data Page在(zai)Segment中的(de)offset以及Data Page的(de)大小(xiao)。
如果當前(qian)列(lie)(lie)不存在Ordinal Index Page,則(ze)可以(yi)直(zhi)接從Segment footer中獲取當前(qian)列(lie)(lie)中唯一的(de)(de)Data Page在Segment中的(de)(de)offset以(yi)及Data Page的(de)(de)大小。
2.4 BitMap索引
為(wei)了加速查詢,doris支(zhi)持用戶為(wei)字段創(chuang)建Bitmap索引,Bitmap索引由(you)兩(liang)部分(fen)組成(cheng):
1.有序字典:有序保存(cun)一列中所有的不同取(qu)值。
2.字(zi)典(dian)(dian)的(de)(de)位圖:保存有(you)序字(zi)典(dian)(dian)中(zhong)每一個值的(de)(de)位圖,值是(shi)字(zi)典(dian)(dian)值在列中(zhong)的(de)(de)行(xing)號。
一列數據(ju)(ju)為(wei)[x, x, y, y, y, z, y, x, z, x],一共包含10行,則(ze)該列數據(ju)(ju)的(de)Bitmap索引的(de)有序(xu)字典為(wei){x, y, z}, 其中x、y、z對應的(de)位圖分別為(wei):
x的位圖: [0, 1, 7, 9]
y的位圖: [2, 3, 4, 6]
z的位圖: [5, 8]
如下圖所示:

左側為有序(xu)字典,右側為字典每一個元素對應的位圖。
2.4.1 索引生成規則
數據(ju)刷(shua)寫時,會(hui)給用戶指定的(de)(de)(de)列(lie)(lie)創建Bitmap索引(yin)(yin)。向列(lie)(lie)中每添加(jia)一個值(zhi)(zhi)(zhi)(zhi),都(dou)會(hui)更新(xin)當前列(lie)(lie)的(de)(de)(de)BitMap索引(yin)(yin)。從Bitmap索引(yin)(yin)對應的(de)(de)(de)有(you)序字典查找新(xin)添加(jia)的(de)(de)(de)值(zhi)(zhi)(zhi)(zhi)是否存(cun)在(zai),如果(guo)已經(jing)存(cun)在(zai),則只更新(xin)該字典值(zhi)(zhi)(zhi)(zhi)對應的(de)(de)(de)位(wei)圖(tu)(tu)(tu);如果(guo)不存(cun)在(zai),則將(jiang)該值(zhi)(zhi)(zhi)(zhi)添加(jia)到有(you)序字典中,并為(wei)這(zhe)個值(zhi)(zhi)(zhi)(zhi)生成(cheng)位(wei)圖(tu)(tu)(tu),Null值(zhi)(zhi)(zhi)(zhi)也(ye)會(hui)有(you)單獨(du)的(de)(de)(de)位(wei)圖(tu)(tu)(tu)。可(ke)以看出Bitmap只適合低基數的(de)(de)(de)列(lie)(lie),如果(guo)基數很高,生成(cheng)大量的(de)(de)(de)位(wei)圖(tu)(tu)(tu)會(hui)占用巨(ju)大的(de)(de)(de)空(kong)間(jian)。
Bitmap索引的(de)字典數據和位圖數據分(fen)開存(cun)儲。
字(zi)典(dian)數(shu)據存(cun)(cun)儲(chu)在(zai)(zai)對應的(de)(de)dict page中(zhong)(zhong),位圖(tu)數(shu)據存(cun)(cun)儲(chu)在(zai)(zai)對應的(de)(de)Bitmap page中(zhong)(zhong),而(er)dict page和(he)Bitmap page的(de)(de)元信(xin)息(xi)會記錄(lu)在(zai)(zai)segment footer中(zhong)(zhong)。如果一(yi)個(ge)(ge)列有多個(ge)(ge)dict page則會轉化成兩級(ji)索引(yin),第二級(ji)索引(yin)為(wei)多個(ge)(ge)dict page,保存(cun)(cun)字(zi)典(dian)數(shu)據,每一(yi)個(ge)(ge)dict page生(sheng)成一(yi)條value索引(yin)項,所有dict page的(de)(de)value 索引(yin)項會被(bei)被(bei)保存(cun)(cun)在(zai)(zai)一(yi)個(ge)(ge)value index page中(zhong)(zhong)作為(wei)一(yi)級(ji)索引(yin),每一(yi)個(ge)(ge)的(de)(de)Value索引(yin)項記錄(lu)了(le)當前(qian)Dict Page中(zhong)(zhong)第一(yi)個(ge)(ge)字(zi)典(dian)值的(de)(de)編碼以(yi)及當前(qian)Dict Page在(zai)(zai)Segment文件中(zhong)(zhong)的(de)(de)offset和(he)大(da)小(xiao),而(er)value index page的(de)(de)元信(xin)息(xi)則保存(cun)(cun)在(zai)(zai)segment footer中(zhong)(zhong)。
同(tong)理如果一(yi)個(ge)(ge)列有多個(ge)(ge)Bitmap page則(ze)會(hui)轉(zhuan)化成(cheng)二級(ji)(ji)索引(yin)(yin),第二級(ji)(ji)索引(yin)(yin)為(wei)多個(ge)(ge)的(de)Bitmap Page,其中(zhong)保(bao)存(cun)Bitmap索引(yin)(yin)的(de)位圖數據,每一(yi)個(ge)(ge)Bitmap Page生成(cheng)一(yi)條Ordinal索引(yin)(yin)項(xiang),所有Bitmap Page的(de)Ordinal索引(yin)(yin)項(xiang)會(hui)被保(bao)存(cun)在一(yi)個(ge)(ge)Ordinal Index Page(注意,此(ci)處(chu)的(de)Ordinal 索引(yin)(yin)與第3部(bu)分(fen)的(de)Ordinal 索引(yin)(yin)不同(tong),此(ci)處(chu)的(de)Ordinal 索引(yin)(yin)指向Bitmap Page,而第3部(bu)分(fen)的(de)Ordinal 索引(yin)(yin)指向Data Page)中(zhong)作為(wei)一(yi)級(ji)(ji)索引(yin)(yin),而Ordinal Index Page的(de)元(yuan)信息則(ze)保(bao)存(cun)在segment footer中(zhong)。
2.4.2適用場景
Doris支(zhi)持在(zai)建(jian)表(biao)時(shi)對(dui)指定的列創(chuang)建(jian)Bitmap索(suo)引,也可以對(dui)已經創(chuang)建(jian)的表(biao)執(zhi)行Alter Table命(ming)令(ling)添(tian)加Bitmap索(suo)引。
ALTER TABLE table_name ADD INDEX index_name (column_name) USING BITMAP COMMENT ‘’;
目(mu)前只支持(chi)對(dui)TINYINT、SMALLINT、INT、 UNSIGNEDINT、BIGINT、LARGEINT、CHAR、 VARCHAR、DATE、DATETIME、BOOL和DECIMAL類(lei)型(xing)的字段(duan)創建Bitmap索(suo)引,其他(ta)類(lei)型(xing)的字段(duan)均(jun)不(bu)支持(chi)Bitmap索(suo)引。
Bitmap索引比(bi)較適合在基(ji)數較低的列上進行(xing)等值查(cha)詢或范(fan)圍查(cha)詢的場景(jing)
2.5 Bloom Filter索引
Bloom Filter索引(yin)按照Data Page的(de)粒度生成(cheng)。數(shu)(shu)據寫(xie)(xie)入(ru)(ru)時(shi)(shi)(shi),會記(ji)錄每一個寫(xie)(xie)入(ru)(ru)Data Page的(de)值(zhi),當一個Data Page寫(xie)(xie)滿(man)之后,會根(gen)據該(gai)Data Page的(de)所有(you)不同取(qu)(qu)值(zhi)為該(gai)Data Page生成(cheng)Bloom Filter索引(yin)。數(shu)(shu)據查(cha)詢時(shi)(shi)(shi),查(cha)詢條件在設置(zhi)有(you)Bloom Filter索引(yin)的(de)字段進(jin)行(xing)過(guo)濾,當某個Data Page的(de)Bloom Filter沒有(you)命(ming)中時(shi)(shi)(shi),表示(shi)該(gai)Data Page中沒有(you)需要(yao)的(de)數(shu)(shu)據,這樣可(ke)以對Data Page進(jin)行(xing)快(kuai)速過(guo)濾,減少不必要(yao)的(de)數(shu)(shu)據讀(du)取(qu)(qu)。
2.5.1適用場景
Doris支持在建(jian)表時對(dui)指定的列創建(jian)Bloom Filter索(suo)引,也可以對(dui)已經創建(jian)的表執行Alter Table命令添加Bloom Filter索(suo)引。
ALTER TABLE table_name SET (“bloom_filter_columns”=”c1, c2, c3”);
目前只支持(chi)對(dui)SMALLINT、INT、UNSIGNEDINT、 BIGINT、LARGEINT、CHAR、 VARCHAR、DATE、DATETIME和DECIMAL類型的(de)(de)字段(duan)創建Bloom Filter索(suo)引,其他類型的(de)(de)字段(duan)均不支持(chi)Bloom Filter索(suo)引。對(dui)于創建了Bloom Filter索(suo)引的(de)(de)字段(duan),查(cha)詢條件是”=”、”is”或”in”語句(ju)時,才會使用Bloom Filter索(suo)引進(jin)行Data Page的(de)(de)過(guo)濾。Bloom Filter索(suo)引比較適合在(zai)基數較高的(de)(de)列上進(jin)行等值查(cha)詢的(de)(de)場景。
2.6NGram BloomFilter索引
為了(le)提升like的查詢(xun)性能,增加(jia)了(le)NGram BloomFilter索引。
2.6.1 NGram BloomFilter創建?
表創建時指定:
CREATE TABLE `table3` (
`siteid` int(11) NULL DEFAULT "10" COMMENT "",
`citycode` smallint(6) NULL COMMENT "",
`username` varchar(32) NULL DEFAULT "" COMMENT "",
INDEX idx_ngrambf (`username`) USING NGRAM_BF PROPERTIES("gram_size"="3", "bf_size"="256") COMMENT 'username ngram_bf index'
) ENGINE=OLAP
AGGREGATE KEY(`siteid`, `citycode`, `username`) COMMENT "OLAP"
DISTRIBUTED BY HASH(`siteid`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);
-- PROPERTIES("gram_size"="3", "bf_size"="256"),分(fen)別表(biao)示gram的(de)個數和(he)bloom filter的(de)字節數。
-- gram的(de)個數(shu)(shu)跟實際查(cha)詢場景相(xiang)關,通(tong)常(chang)設置(zhi)為大部(bu)分查(cha)詢字符(fu)串的(de)長度,bloom filter字節數(shu)(shu),可以通(tong)過(guo)測試(shi)得出,通(tong)常(chang)越(yue)(yue)大過(guo)濾效果越(yue)(yue)好,可以從256開始進(jin)行驗證測試(shi)看(kan)看(kan)效果。當然字節數(shu)(shu)越(yue)(yue)大也會帶(dai)來索引(yin)存儲、內(nei)存cost上升。
-- 如果數據(ju)基(ji)數比較高(gao),字節數可以不用設置過(guo)大,如果基(ji)數不是(shi)很(hen)高(gao),可以通(tong)過(guo)增加字節數來(lai)提升過(guo)濾效(xiao)果。
2.6.2 NGram BloomFilter使用注意事項?
- NGram BloomFilter只支持字符串列
- NGram BloomFilter索引和BloomFilter索引為互斥關系,即同一個列只能設置兩者中的一個
- NGram大小和BloomFilter的字節數,可以根據實際情況調優,如果NGram比較小,可以適當增加BloomFilter大小
- 如果要查看某個查詢是否命中了NGram Bloom Filter索引,可以通過查詢的Profile信息查看
2.7 倒排索引
從2.0.0版本(ben)(ben)開(kai)始,Doris支(zhi)持倒排索(suo)引,可以用來(lai)進(jin)行(xing)文(wen)(wen)(wen)本(ben)(ben)類(lei)型的全文(wen)(wen)(wen)檢索(suo)、普通數值日期類(lei)型的等值范圍(wei)查詢,快(kuai)速從海(hai)量數據(ju)中過濾出(chu)滿足條(tiao)件的行(xing)。本(ben)(ben)文(wen)(wen)(wen)檔主要(yao)介紹如何倒排索(suo)引的創建、刪除、查詢等使用方式。
inverted index:倒排索引,是信息檢索領域常用的索引技術(shu),將文本(ben)分割成一個(ge)(ge)個(ge)(ge)詞,構(gou)建 詞 -> 文檔編號(hao) 的索引,可以快速查(cha)找(zhao)一個(ge)(ge)詞在哪些(xie)文檔出(chu)現。
在Doris的(de)倒排(pai)索引實現(xian)中,table的(de)一行(xing)對應一個文檔(dang)、一列(lie)對應文檔(dang)中的(de)一個字段,因此利用倒排(pai)索引可以(yi)根(gen)據關鍵詞快速定位包含它的(de)行(xing),達到WHERE子句(ju)加速的(de)目(mu)的(de)。
與Doris中其他索(suo)引(yin)不同(tong)的(de)(de)是,在(zai)存儲層倒排索(suo)引(yin)使用獨立的(de)(de)文(wen)件,跟segment文(wen)件有邏輯對應關系、但存儲的(de)(de)文(wen)件相互獨立。這樣的(de)(de)好處(chu)是可以做到創建、刪除索(suo)引(yin)不用重寫tablet和segment文(wen)件,大幅降低處(chu)理開銷。
2.7.1 功能
- 增加了字符串類型的全文檢索
- 支持字符串全文檢索,包括同時匹配多個關鍵字MATCH_ALL、匹配任意一個關鍵字MATCH_ANY、匹配短語詞組MATCH_PHRASE
- 支持字符串數組類型的全文檢索
- 支持英文、中文以及Unicode多語言分詞
- 加速普通等值、范圍查詢,覆蓋bitmap索引的功能,未來會代替bitmap索引
- 支持字符串、數值、日期時間類型的 =, !=, >, >=, <, <= 快速過濾
- 支持字符串、數字、日期時間數組類型的 =, !=, >, >=, <, <=
- 支持完善的邏輯組合
- 新增索引對OR NOT邏輯的下推
- 支持多個條件的任意AND OR NOT組合
- 靈活、快速的索引管理
- 支持在創建表上定義倒排索引
- 支持在已有的表上增加倒排索引,而且支持增量構建倒排索引,無需重寫表中的已有數據
- 支持刪除已有表上的倒排索引,無需重寫表中的已有數據
2.7.2 使用
CREATE TABLE table_name
(
columns_difinition,
INDEX idx_name1(column_name1) USING INVERTED [PROPERTIES("parser" = "english|unicode|chinese")] [COMMENT 'your comment']
INDEX idx_name2(column_name2) USING INVERTED [PROPERTIES("parser" = "english|unicode|chinese")] [COMMENT 'your comment']
INDEX idx_name3(column_name3) USING INVERTED [PROPERTIES("parser" = "chinese", "parser_mode" = "fine_grained|coarse_grained")] [COMMENT 'your comment']
INDEX idx_name4(column_name4) USING INVERTED [PROPERTIES("parser" = "english|unicode|chinese", "support_phrase" = "true|false")] [COMMENT 'your comment']
)
table_properties;
- 利用倒排索引加速查詢
-- 1. 全文檢索關鍵詞匹配,通過MATCH_ANY MATCH_ALL完成
SELECT * FROM table_name WHERE column_name MATCH_ANY | MATCH_ALL 'keyword1 ...';
-- 1.1 logmsg中包含keyword1的行
SELECT * FROM table_name WHERE logmsg MATCH_ANY 'keyword1';
-- 1.2 logmsg中包含keyword1或者keyword2的行,后面還可以添加多個keyword
SELECT * FROM table_name WHERE logmsg MATCH_ANY 'keyword1 keyword2';
-- 1.3 logmsg中同時包含keyword1和keyword2的行,后面還可以添加多個keyword
SELECT * FROM table_name WHERE logmsg MATCH_ALL 'keyword1 keyword2';
-- 1.4 logmsg中同時包含keyword1和keyword2的行,并且按照keyword1在前,keyword2在后的順序
SELECT * FROM table_name WHERE logmsg MATCH_PHRASE 'keyword1 keyword2';
-- 2. 普通等值、范圍、IN、NOT IN,正常的SQL語句即可,例如
SELECT * FROM table_name WHERE id = 123;
SELECT * FROM table_name WHERE ts > '2023-01-01 00:00:00';
SELECT * FROM table_name WHERE op_type IN ('add', 'delete');
2.8參考文檔(dang)
doris官方(fang)文檔
百(bai)度開發者中(zhong)心
//developer.baidu.com/article/detail.html?id=293810
csdn