JSON查詢
概述
JSON查詢是Druid內(nèi)置的本機(jī)查詢,本機(jī)查詢級別較低,與內(nèi)部計算的執(zhí)行方式密切相關(guān)螺垢。json查詢被設(shè)計為輕量級且非常快速地完成赖歌。這意味著,對于更復(fù)雜的分析或構(gòu)建更復(fù)雜的可視化,需要json查詢枉圃。
一、時間序列查詢(Timeseries)
這些類型的查詢采用時間序列查詢對象庐冯,并返回JSON對象數(shù)組孽亲,其中每個對象代表時間序列查詢所要求的值。
時間序列查詢對象示例如下所示:
{
"queryType": "timeseries",
"dataSource": "sample_datasource",
"granularity": "day",
"descending": "true",
"filter": {
"type": "and",
"fields": [
{ "type": "selector", "dimension": "sample_dimension1", "value": "sample_value1" },
{ "type": "or",
"fields": [
{ "type": "selector", "dimension": "sample_dimension2", "value": "sample_value2" },
{ "type": "selector", "dimension": "sample_dimension3", "value": "sample_value3" }
]
}
]
},
"aggregations": [
{ "type": "longSum", "name": "sample_name1", "fieldName": "sample_fieldName1" },
{ "type": "doubleSum", "name": "sample_name2", "fieldName": "sample_fieldName2" }
],
"postAggregations": [
{ "type": "arithmetic",
"name": "sample_divide",
"fn": "/",
"fields": [
{ "type": "fieldAccess", "name": "postAgg__sample_name1", "fieldName": "sample_name1" },
{ "type": "fieldAccess", "name": "postAgg__sample_name2", "fieldName": "sample_name2" }
]
}
],
"intervals": [ "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000" ]
}
屬性 | 描述 | 必須 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 timeseries | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
descending | 是否進(jìn)行降序排序展父。默認(rèn)值為false(升序)返劲。 | 否 |
intervals | 定義查詢時間范圍。 | 是 |
granularity | 定義查詢結(jié)果的粒度 | 是 |
filter | 過濾器 | 否 |
aggregations | 聚合 | 否 |
postAggregations | 后聚合 | 否 |
limit | 限制結(jié)果數(shù)量栖茉。默認(rèn)值為無限制篮绿。 | 否 |
context | 上下文,可用于修改查詢行為吕漂,包括總計和零填充 | 否 |
上面的查詢將從“ sample_datasource”表中返回2個數(shù)據(jù)點(diǎn)搔耕,從2012年1月1日到2012年1月3日之間每天返回一個數(shù)據(jù)點(diǎn)。每個數(shù)據(jù)點(diǎn)將是sample_fieldName1的(long)總和痰娱,sample_fieldName2的(double)總和和sample_fieldName1的(double)結(jié)果除以過濾器集的sample_fieldName2
[
{
"timestamp": "2012-01-01T00:00:00.000Z",
"result": { "sample_name1": <some_value>, "sample_name2": <some_value>, "sample_divide": <some_value> }
},
{
"timestamp": "2012-01-02T00:00:00.000Z",
"result": { "sample_name1": <some_value>, "sample_name2": <some_value>, "sample_divide": <some_value> }
}
]
Druid可以在時間序列結(jié)果集的最后一行包含額外的“總計”行弃榨。要啟用此功能,請?zhí)砑?"grandTotal":true 到您的查詢context中梨睁【ňΓ總計行將在結(jié)果數(shù)組中顯示為最后一行。即使查詢以“降序”模式運(yùn)行坡贺,也將是最后一行官辈。總計行中的后聚合將基于總計匯總進(jìn)行計算遍坟。
{
"queryType": "timeseries",
"dataSource": "sample_datasource",
"intervals": [ "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000" ],
"granularity": "day",
"aggregations": [
{ "type": "longSum", "name": "sample_name1", "fieldName": "sample_fieldName1" },
{ "type": "doubleSum", "name": "sample_name2", "fieldName": "sample_fieldName2" }
],
"context": {
"grandTotal": true
}
}
時間序列查詢通常用零填充空的結(jié)果段拳亿。如,如果您對間隔2012-01-01/2012-01-04發(fā)送“day”粒度時間序列查詢愿伴,而2012-01-02沒有數(shù)據(jù)肺魁,您將收到:
[
{
"timestamp": "2012-01-01T00:00:00.000Z",
"result": { "sample_name1": <some_value> }
},
{
"timestamp": "2012-01-02T00:00:00.000Z",
"result": { "sample_name1": 0 }
},
{
"timestamp": "2012-01-03T00:00:00.000Z",
"result": { "sample_name1": <some_value> }
}
]
完全位于數(shù)據(jù)間隔之外的時間段不會填充零。
您可以使用context標(biāo)記"skipEmptyBuckets": "true"跳過空結(jié)果填充隔节。在這種模式下鹅经,結(jié)果中將省略2012-01-02的數(shù)據(jù)點(diǎn)寂呛。
{
"queryType": "timeseries",
"dataSource": "sample_datasource",
"granularity": "day",
"aggregations": [
{ "type": "longSum", "name": "sample_name1", "fieldName": "sample_fieldName1" }
],
"intervals": [ "2012-01-01T00:00:00.000/2012-01-04T00:00:00.000" ],
"context" : {
"skipEmptyBuckets": "true"
}
}
二、TopN查詢(TopN)
Druid TopN查詢根據(jù)某些條件返回的結(jié)果集中進(jìn)行排序的結(jié)果瘾晃。從理論上講贷痪,可以將它們視為具有Ordering規(guī)范的單個維度上的近似GroupByQuery查詢。在此用例中蹦误,TopN比GroupBy更快劫拢,資源效率更高。這些類型的查詢采用topN查詢對象强胰,并返回JSON對象數(shù)組舱沧,其中每個對象代表topN查詢所要求查詢條件。
TopN是近似值哪廓,因為每個數(shù)據(jù)集處理時狗唉,將對它們的前K個結(jié)果進(jìn)行排名初烘,并且僅將這些前K個結(jié)果返回給Broker涡真。K在數(shù)據(jù)庫中默認(rèn)為 max(1000, threshold)。實際上肾筐,這意味著如果您要求返回前1000個結(jié)果哆料,則前900個結(jié)果的正確性將為100%,后續(xù)的結(jié)果則不能保證100%的正確和有序性吗铐,所以通過更改max的設(shè)置可以使TopN更加準(zhǔn)確东亦。
{
"queryType": "topN",
"dataSource": "sample_data",
"dimension": "sample_dim",
"threshold": 5,
"metric": "count",
"granularity": "all",
"filter": {
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "dim1",
"value": "some_value"
},
{
"type": "selector",
"dimension": "dim2",
"value": "some_other_val"
}
]
},
"aggregations": [
{
"type": "longSum",
"name": "count",
"fieldName": "count"
},
{
"type": "doubleSum",
"name": "some_metric",
"fieldName": "some_metric"
}
],
"postAggregations": [
{
"type": "arithmetic",
"name": "average",
"fn": "/",
"fields": [
{
"type": "fieldAccess",
"name": "some_metric",
"fieldName": "some_metric"
},
{
"type": "fieldAccess",
"name": "count",
"fieldName": "count"
}
]
}
],
"intervals": [
"2013-08-31T00:00:00.000/2013-09-03T00:00:00.000"
]
}
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 topN | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
intervals | 定義查詢時間范圍。 | 是 |
granularity | 定義查詢結(jié)果的粒度 | 是 |
filter | 過濾器 | 否 |
aggregations | 聚合 | 否 |
postAggregations | 后聚合 | 否 |
dimension | 一個String或JSON對象唬渗,定義使用的類型 | 是 |
threshold | 定義TopN中N的值 | 是 |
metric | 一個String或JSON對象典阵,它指定要排序的指標(biāo) | 是 |
context | 上下文 | 否 |
[
{
"timestamp": "2013-08-31T00:00:00.000Z",
"result": [
{
"dim1": "dim1_val",
"count": 111,
"some_metrics": 10669,
"average": 96.11711711711712
},
{
"dim1": "another_dim1_val",
"count": 88,
"some_metrics": 28344,
"average": 322.09090909090907
},
{
"dim1": "dim1_val3",
"count": 70,
"some_metrics": 871,
"average": 12.442857142857143
},
{
"dim1": "dim1_val4",
"count": 62,
"some_metrics": 815,
"average": 13.14516129032258
},
{
"dim1": "dim1_val5",
"count": 60,
"some_metrics": 2787,
"average": 46.45
}
]
}
]
多值維度
topN查詢可以對多值維度進(jìn)行分組。在對多值維度進(jìn)行分組時镊逝,匹配行中的所有值將用于為每個值生成一組壮啊。查詢返回的組可能比行多。例如撑蒜,一個TopN的字段 tags 經(jīng)過過濾器 "t1" AND "t3" 將只有ROW1一個匹配歹啼,最終與三個組生成結(jié)果:t1,t2座菠,和t3狸眼。如果只需要包含與過濾器匹配的值,則可以使用過濾的 DimensionSpec屬性設(shè)置可以少返回一些結(jié)果浴滴,這也可以提高性能拓萌。
混疊
當(dāng)前的TopN算法是一種近似算法。返回每個段的前1000個局部結(jié)果合并以確定全局topN升略。這樣司志,topN算法在等級和結(jié)果上都是近似的甜紫。近似結(jié)果僅適用于超過1000個結(jié)果值的情況。少于1000個唯一維度值的維度上的topN可以被認(rèn)為是排名準(zhǔn)確且集合體準(zhǔn)確骂远。
閾值可以通過服務(wù)器參數(shù)默認(rèn)值1000進(jìn)行修改囚霸,該參數(shù) Druid.query.topN.minTopNThreshold 需要重新啟動服務(wù)器才能生效,或者在查詢上下文中設(shè)置(對每個查詢生效)minTopNThreshold激才。
如果您希望TopN的N數(shù)拓型,則均勻分布的維度前100個按一些low-cardinality,均勻分布的維度排序瘸恼,則可能會找回丟失數(shù)據(jù)的聚合劣挫。
換句話說,topN的最佳用例是您可以確信總體結(jié)果始終位于頂部东帅。例如压固,如果某個特定的站點(diǎn)ID在每天的每個小時中均處于某個指標(biāo)的前10名中,則它在幾天之內(nèi)在前N名中可能很準(zhǔn)確靠闭。但是帐我,如果某個站點(diǎn)在任何給定的小時內(nèi)幾乎都沒有進(jìn)入前1000名,但在整個查詢粒度中都排名前500名(例如:一個站點(diǎn)在數(shù)據(jù)集中與具有高度周期性數(shù)據(jù)的站點(diǎn)混合在一起獲得高度統(tǒng)一的流量)愧膀,則top500查詢可能沒有使該特定網(wǎng)站具有確切的排名拦键,并且對于該特定網(wǎng)站的匯總可能并不準(zhǔn)確。
在使用TopN之前檩淋,請考慮是否確實需要確切的結(jié)果芬为。獲得準(zhǔn)確的結(jié)果是非常耗費(fèi)資源的過程。對于絕大多數(shù)結(jié)果集來說蟀悦,近似topN算法可提供足夠的準(zhǔn)確性媚朦。
希望獲得具有大于1000個唯一值的維度上,要求精確排名和精確聚合時日戈,應(yīng)發(fā)出groupBy查詢并自行對結(jié)果進(jìn)行排序询张。
可以容忍具有大于1000個唯一值的維度上,允許近似結(jié)果集時,但需要精確的集合涎拉,用戶可以發(fā)出兩個查詢瑞侮,一個用于獲取近似topN的N個值,另一個用于N個值使用選擇過濾器的topN鼓拧,該過濾器僅使用第一個的topN結(jié)果半火。
-
示例一:
{ "aggregations": [ { "fieldName": "L_QUANTITY_longSum", "name": "L_QUANTITY_", "type": "longSum" } ], "dataSource": "tpch_year", "dimension":"l_orderkey", "granularity": "all", "intervals": [ "1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z" ], "metric": "L_QUANTITY_", "queryType": "topN", "threshold": 2 }
-
示例二:
{ "aggregations": [ { "fieldName": "L_TAX_doubleSum", "name": "L_TAX_", "type": "doubleSum" }, { "fieldName": "L_DISCOUNT_doubleSum", "name": "L_DISCOUNT_", "type": "doubleSum" }, { "fieldName": "L_EXTENDEDPRICE_doubleSum", "name": "L_EXTENDEDPRICE_", "type": "doubleSum" }, { "fieldName": "L_QUANTITY_longSum", "name": "L_QUANTITY_", "type": "longSum" }, { "name": "count", "type": "count" } ], "dataSource": "tpch_year", "dimension":"l_orderkey", "filter": { "fields": [ { "dimension": "l_orderkey", "type": "selector", "value": "103136" }, { "dimension": "l_orderkey", "type": "selector", "value": "1648672" } ], "type": "or" }, "granularity": "all", "intervals": [ "1900-01-09T00:00:00.000Z/2992-01-10T00:00:00.000Z" ], "metric": "L_QUANTITY_", "queryType": "topN", "threshold": 2 }
三、分組查詢(GroupBy)
Druid查詢采用groupBy查詢對象季俩,并返回JSON對象數(shù)組钮糖,其中每個對象代表查詢所要求的分組條件。
注意:如果要使用時間作為唯一分組進(jìn)行聚合,或者在單個維度上使用有序的groupBy進(jìn)行聚合店归,請考慮使用Timeseries和TopN查詢以及groupBy阎抒。在某些情況下,它們的性能可能會更好消痛。
{
"queryType": "groupBy",
"dataSource": "sample_datasource",
"granularity": "day",
"dimensions": ["country", "device"],
"limitSpec": { "type": "default", "limit": 5000, "columns": ["country", "data_transfer"] },
"filter": {
"type": "and",
"fields": [
{ "type": "selector", "dimension": "carrier", "value": "AT&T" },
{ "type": "or",
"fields": [
{ "type": "selector", "dimension": "make", "value": "Apple" },
{ "type": "selector", "dimension": "make", "value": "Samsung" }
]
}
]
},
"aggregations": [
{ "type": "longSum", "name": "total_usage", "fieldName": "user_count" },
{ "type": "doubleSum", "name": "data_transfer", "fieldName": "data_transfer" }
],
"postAggregations": [
{ "type": "arithmetic",
"name": "avg_usage",
"fn": "/",
"fields": [
{ "type": "fieldAccess", "fieldName": "data_transfer" },
{ "type": "fieldAccess", "fieldName": "total_usage" }
]
}
],
"intervals": [ "2012-01-01T00:00:00.000/2012-01-03T00:00:00.000" ],
"having": {
"type": "greaterThan",
"aggregation": "total_usage",
"value": 100
}
}
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 groupBy | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
dimensions | 一個用于進(jìn)行分組的維度的JSON列表 | 是 |
limitSpec | 請參limitSpec具體用法 | 否 |
having | 請參having具體用法 | 否 |
granularity | 定義查詢結(jié)果的粒度 | 是 |
filter | 過濾器 | 否 |
aggregations | 聚合 | 否 |
postAggregations | 后聚合 | 否 |
intervals | 定義查詢時間范圍且叁。 | 是 |
subtotalsSpec | 一個JSON數(shù)組數(shù)組,用于返回其他結(jié)果集秩伞,以對頂級子集進(jìn)行分組dimensions | 否 |
context | 上下文 | 否 |
上面的查詢將返回n * m個數(shù)據(jù)點(diǎn)逞带,最多可返回5000個點(diǎn),其中n是country維的基數(shù)纱新,m是device維的基數(shù)展氓。device維介于sample_datasource表的2012-01-01到2012-01-03之間的每一天司忱,如果數(shù)據(jù)點(diǎn)的值大于100塑煎,那么每個數(shù)據(jù)點(diǎn)都包含total_usage的(long)和、data_transfer的(double)和,total_usage除以data_transfer針對的特定分組,過濾器集country和device
[
{
"version" : "v1",
"timestamp" : "2012-01-01T00:00:00.000Z",
"event" : {
"country" : <some_dim_value_one>,
"device" : <some_dim_value_two>,
"total_usage" : <some_value_one>,
"data_transfer" :<some_value_two>,
"avg_usage" : <some_avg_usage_value>
}
},
{
"version" : "v1",
"timestamp" : "2012-01-01T00:00:12.000Z",
"event" : {
"dim1" : <some_other_dim_value_one>,
"dim2" : <some_other_dim_value_two>,
"sample_name1" : <some_other_value_one>,
"sample_name2" :<some_other_value_two>,
"avg_usage" : <some_other_avg_usage_value>
}
},
...
]
多值維度
groupBy查詢可以對多值維度進(jìn)行分組呻逆。在對多值維度進(jìn)行分組時簿废,匹配行中的所有值將用于為每個值生成一組空入。查詢返回的組可能比行多。例如捏鱼,在查詢結(jié)果的GROUPBY tags與過濾器"t1" AND "t3"將只ROW1最終匹配执庐,但是與三個組生成結(jié)果:t1酪耕,t2导梆,和t3。如果只需要包含與過濾器匹配的值迂烁,則可以使用過濾的DimensionSpec減少返回的結(jié)果數(shù)量看尼,這也可以提高性能。
小計功能信息
小計功能允許在單個查詢中計算多個子組盟步。若要使用此功能,請在查詢中添加一個“subtotalsSpec”屬性却盘,該列表應(yīng)該是子組維度集的列表狰域。它應(yīng)在“維度”屬性中包含維度中的“outputName”,其順序與在“維度”屬性中出現(xiàn)的順序相同
{
"type": "groupBy",
...
...
"dimensions": [
{
"type" : "default",
"dimension" : "d1col",
"outputName": "D1"
},
{
"type" : "extraction",
"dimension" : "d2col",
"outputName" : "D2",
"extractionFn" : extraction_func
},
{
"type":"lookup",
"dimension":"d3col",
"outputName":"D3",
"name":"my_lookup"
}
],
...
...
"subtotalsSpec":[ ["D1", "D2", D3"], ["D1", "D3"], ["D3"]],
..
}
返回的結(jié)果等同于將3個groupBy查詢的結(jié)果與 DimensionSpec 的json blob 連接在一起黄橘,其中“dimensions”字段為[“ D1”兆览,“ D2”,D3“]塞关,[” D1“抬探,” D3“]和[” D3“] 就像上面的查詢中使用的一樣。
[
{
"version" : "v1",
"timestamp" : "t1",
"event" : { "D1": "..", "D2": "..", "D3": ".." }
}
},
{
"version" : "v1",
"timestamp" : "t2",
"event" : { "D1": "..", "D2": "..", "D3": ".." }
}
},
...
...
{
"version" : "v1",
"timestamp" : "t1",
"event" : { "D1": "..", "D3": ".." }
}
},
{
"version" : "v1",
"timestamp" : "t2",
"event" : { "D1": "..", "D3": ".." }
}
},
...
...
{
"version" : "v1",
"timestamp" : "t1",
"event" : { "D3": ".." }
}
},
{
"version" : "v1",
"timestamp" : "t2",
"event" : { "D3": ".." }
}
},
...
]
[1] 實現(xiàn)細(xì)節(jié)
策略
可以使用兩種不同的策略來執(zhí)行GroupBy查詢帆赢。集群的默認(rèn)策略由Broker上的“ Druid.query.groupBy.defaultStrategy”運(yùn)行時屬性確定小压∠吖#可以在查詢上下文中使用“groupByStrategy”來覆蓋它。如果既未設(shè)置上下文字段也未設(shè)置屬性怠益,則將使用"v2"策略仪搔。
默認(rèn)情況下,"v2"旨在提供更好的性能和內(nèi)存管理蜻牢。該策略的使用僻造,完全是堆外映射生成每個段的結(jié)果。數(shù)據(jù)處理使用的是孩饼,完全堆外并發(fā)實時映射和堆上字符串字典合并成每個段結(jié)果髓削。這可能會涉及磁盤溢出。數(shù)據(jù)進(jìn)程將排序后的結(jié)果返回給borker镀娶,borker使用N路合并來合并結(jié)果流立膛。如有必要,borker將具體化結(jié)果(例如梯码,如果查詢按其維度以外的列進(jìn)行排序)宝泵。否則,它會在合并結(jié)果時將結(jié)果流回轩娶。
傳統(tǒng)策略"v1"使用部分堆(維度鍵和地圖本身)和部分堆(合計值)的映射在數(shù)據(jù)流程(歷史記錄儿奶,實時,MiddleManager)上生成每段結(jié)果鳄抒。然后闯捎,數(shù)據(jù)處理使用Druid的索引機(jī)制合并每個段的結(jié)果。默認(rèn)情況下许溅,此合并是多線程的瓤鼻,但也可以選擇是單線程的。borker再次使用Druid的索引機(jī)制合并最終結(jié)果集贤重。borker合并始終是單線程的茬祷。因為Broker使用索引機(jī)制合并結(jié)果,所以它必須在返回任何結(jié)果之前實現(xiàn)完整的結(jié)果集并蝗。在數(shù)據(jù)進(jìn)程和borker上祭犯,默認(rèn)情況下,合并索引完全處于堆中狀態(tài)滚停,但是可以選擇將聚集值存儲在堆外沃粗。
v1和v2之間的區(qū)別
查詢API和結(jié)果,在兩個策略之間是兼容的;但是铐刘,從集群配置角度來看陪每,存在一些差異:
groupBy v1使用基于行的限制(maxResults)控制資源使用,而groupBy v2使用基于字節(jié)的限制。另外檩禾,groupBy v1合并結(jié)果在堆上挂签,而groupBy v2合并結(jié)果在堆外。這些因素意味著內(nèi)存調(diào)整和資源限制在v1和v2之間表現(xiàn)不同盼产。尤其是由于這個原因饵婆,某些可以在一個引擎中成功完成的查詢可能會超出資源限制。
groupBy v1對并發(fā)運(yùn)行的查詢數(shù)量沒有限制戏售,而groupBy v2通過使用有限大小的合并緩沖池來控制內(nèi)存使用侨核。默認(rèn)情況下,合并緩沖區(qū)的數(shù)量是處理線程數(shù)量的1/4灌灾。您可以根據(jù)需要進(jìn)行調(diào)整搓译,以平衡并發(fā)和內(nèi)存使用。
groupBy v1支持在Broker或Historical進(jìn)程上進(jìn)行緩存锋喜,而groupBy v2僅支持在Historical進(jìn)程上進(jìn)行緩存些己。
groupBy v1支持使用chunkPeriod并行化執(zhí)行Broker上的合并,而groupBy v2則忽略chunkPeriod嘿般。
groupBy v2支持基于數(shù)組的聚合和基于哈希的聚合段标。僅當(dāng)分組鍵是單個索引字符串列時才使用基于數(shù)組的聚合。在基于數(shù)組的聚合中炉奴,將字典編碼的值用作索引逼庞,因此可以直接訪問數(shù)組中的聚合值,而無需基于哈希查找存儲瞻赶。
[2] 內(nèi)存調(diào)整和資源限制
使用groupBy v2策略時赛糟,三個參數(shù)控制資源的使用和限制:
Druid.processing.buffer.sizeBytes:每個查詢用于聚合的堆外哈希表的大小,以字節(jié)為單位共耍。最多的Druid.processing.numMergeBuffers將立即創(chuàng)建其中的一個虑灰,這也作為并發(fā)運(yùn)行的groupBy查詢數(shù)量的上限吨瞎。
Druid.query.groupBy.maxMergingDictionarySize:堆查詢時按每個查詢痹兜,對字符串進(jìn)行分組的字典的大小(以字節(jié)為單位)颤诀。請注意字旭,這是基于對字典大小的粗略估算,而不是實際大小崖叫。
-
Druid.query.groupBy.maxOnDiskStorage:磁盤上用于聚合的空間量遗淳,每個查詢,以字節(jié)為單位心傀。默認(rèn)情況下屈暗,該值為0,這意味著聚合將不使用磁盤。
如果maxOnDiskStorage為0(默認(rèn)值)养叛,則超過堆上字典大小的限制或堆外聚合表的限制种呐,則查詢失敗,并顯示“超出資源限制”錯誤弃甥,描述已超過的限制爽室。
如果maxOnDiskStorage大于0,則超出內(nèi)存限制的查詢將開始使用磁盤進(jìn)行聚合淆攻。在這種情況下阔墩,當(dāng)堆上字典大小或堆外哈希表被填滿時,將對部分聚合的記錄進(jìn)行排序并將其刷新到磁盤瓶珊。然后啸箫,將清除兩個內(nèi)存結(jié)構(gòu)以進(jìn)行進(jìn)一步聚合。查詢超過maxOnDiskStorage設(shè)置的將失敗伞芹,并顯示“超出資源限制”錯誤筐高,表明它們已用完磁盤空間。
使用groupBy v2策略丑瞧,集群操作者應(yīng)確保對于最大可能的并發(fā)查詢負(fù)載(由提供Druid.processing.numMergeBuffers)柑土,堆外哈希表和堆上合并字典不會超出可用內(nèi)存 。
Broker不需要基本groupBy查詢的合并緩沖區(qū)绊汹。query如果只有一個子查詢稽屏,則帶有子查詢的查詢(使用dataSource)需要一個合并緩沖區(qū),如果有一層以上的嵌套子查詢西乖,則需要兩個合并緩沖區(qū)狐榔。具有小計的查詢需要一個合并緩沖區(qū)。它們可以彼此疊加:一個具有多層嵌套子查詢層的groupBy查詢(也使用小計)將需要三個合并緩沖區(qū)获雕。
Historicals和提取任務(wù)的每個groupBy查詢都需要一個合并緩沖區(qū)薄腻,除非啟用了并行組合,在這種情況下届案,每個查詢都需要兩個合并緩沖區(qū)庵楷。
使用groupBy v1策略時,所有聚合都在堆上完成楣颠,而資源限制則通過參數(shù)Druid.query.groupBy.maxResults設(shè)置尽纽。這是結(jié)果集中最大結(jié)果數(shù)的上限。超過此限制的查詢將失敗童漩,并顯示“超出資源限制”錯誤弄贿,表明它們超過了行限制。集群操作者應(yīng)確保對于預(yù)期的并發(fā)查詢負(fù)載矫膨,堆上聚合不會超出可用的JVM堆空間差凹。
[3] groupBy v2策略的性能調(diào)優(yōu)
-
限制疊加優(yōu)化
Druid limit盡可能將groupBy查詢中的規(guī)范下推到Historicals上進(jìn)行細(xì)分期奔,以盡早刪減不必要的中間結(jié)果,并最大程度地減少傳輸給Brokers的數(shù)據(jù)量危尿。默認(rèn)情況下能庆,僅當(dāng)orderBy規(guī)范中的所有字段都是分組鍵的子集時才應(yīng)用此技術(shù)。這是因為脚线,limitPushDown如果orderBy規(guī)范中包含不在分組鍵中的任何字段搁胆,則不能保證準(zhǔn)確的結(jié)果。如果您接受諸如topN查詢中的快速查詢處理的準(zhǔn)確性時邮绿,也可以啟用此技術(shù)渠旁。
-
優(yōu)化哈希表
groupBy v2策略使用開放式地址哈希表進(jìn)行匯總。哈希表使用給定的初始存儲桶編號進(jìn)行初始化船逮,并在緩沖區(qū)已滿時逐漸增長顾腊。在哈希沖突中,使用線性探測技術(shù)挖胃。
初始存儲桶的默認(rèn)大小為1024杂靶,哈希表的默認(rèn)最大負(fù)載因子為0.7。如果您在哈希表中看到太多沖突酱鸭,則可以調(diào)整這些數(shù)字吗垮。bufferGrouperInitialBuckets和bufferGrouperMaxLoadFactor在高級GROUPBY V2策略配置中有相關(guān)說明。
-
平行組合
Historicals使用哈希表完成聚合后凹髓,將對聚合結(jié)果進(jìn)行排序和合并烁登,然后再將其發(fā)送到Broker中以進(jìn)行Broker中的N路合并聚合。默認(rèn)情況下蔚舀,Historicals使用所有可用的處理線程(由配置Druid.processing.numThreads)進(jìn)行聚合饵沧,但使用單個線程對聚合進(jìn)行排序和合并,這是將線程發(fā)送到Broker的http線程赌躺。
這是為了防止某些繁重的groupBy查詢阻止其他查詢狼牺。在Druid中,處理線程在所有提交的查詢之間共享礼患,并且它們不可中斷是钥。這意味著,如果繁重的查詢占用了所有可用的處理線程讶泰,則所有其他查詢都可能被阻塞咏瑟,直到繁重的查詢完成為止。GroupBy查詢通常比時間序列查詢或topN查詢花費(fèi)更多的時間痪署,因此應(yīng)盡快釋放處理線程。
但是兄旬,您可能會關(guān)心一些非常繁瑣的groupBy查詢的性能狼犯。通常余寥,繁重的groupBy查詢的性能瓶頸是合并排序的聚合。在這種情況下悯森,您也可以使用處理線程宋舷。這稱為并行合并。要啟用并行合并瓢姻,請參閱numParallelCombineThreads“ 高級groupBy v2策略配置”祝蝠。請注意,只有在實際溢出數(shù)據(jù)時才能啟用并行組合(請參閱內(nèi)存調(diào)整和資源限制)幻碱。
啟用并行合并后绎狭,groupBy v2策略可以創(chuàng)建合并樹以合并排序的聚合。樹的每個中間節(jié)點(diǎn)都是一個線程褥傍,用于合并子節(jié)點(diǎn)的聚合儡嘶。葉節(jié)點(diǎn)線程從哈希表(包括溢出表)讀取和合并聚合。通常恍风,葉進(jìn)程比中間節(jié)點(diǎn)慢蹦狂,因為它們需要從磁盤讀取數(shù)據(jù)。結(jié)果朋贬,默認(rèn)情況下凯楔,較少的線程用于中間節(jié)點(diǎn)。您可以更改中間節(jié)點(diǎn)的程度锦募。
請注意啼辣,每個Historicals都需要兩個合并緩沖區(qū)來通過并行合并處理groupBy v2策略查詢:一個用于計算每個段的中間聚合,另一個用于并行合并中間聚合御滩。
[4] 備選方案
在某些情況下鸥拧,其他查詢類型可能比groupBy更好。
對于沒有“維度”的查詢(即僅按時間分組)削解,時間序列查詢通常比groupBy更快富弦。主要區(qū)別在于,它以完全流式方式實現(xiàn)(利用段已按時間排序的事實)氛驮,并且不需要使用哈希表進(jìn)行合并腕柜。
對于具有單個“維度”元素(即按一個字符串維度分組)的查詢,TopN查詢 有時會比groupBy更快矫废。
[5] 內(nèi)置的groupby
對于"v1"和"v2"盏缤,內(nèi)置的groupBys(“查詢”類型的數(shù)據(jù)源)的執(zhí)行方式有所不同。Broker首先以通常的方式運(yùn)行內(nèi)部groupBy查詢蓖扑。然后唉铜,"v1"策略使用Druid的索引機(jī)制,在內(nèi)部,實現(xiàn)內(nèi)部查詢,并在這些實現(xiàn)的結(jié)果上運(yùn)行外部查詢律杠。"v2"策略則使用可溢出到磁盤的堆外實時映射和堆上字符串字典潭流,在內(nèi)部查詢的結(jié)果流上運(yùn)行外部查詢竞惋。兩種策略都以單線程方式在Broker上執(zhí)行外部查詢。
[6] 配置
本節(jié)介紹groupBy查詢的配置灰嫉。您可以runtime.properties在Broker拆宛,Historical和MiddleManager進(jìn)程的文件中設(shè)置運(yùn)行時屬性。您可以通過查詢上下文設(shè)置查詢上下文參數(shù)讼撒。
-
groupBy v2的配置
運(yùn)行時屬性
屬性 描述 默認(rèn) Druid.query.groupBy.maxMergingDictionarySize 合并期間用于字符串字典的最大堆空間量(大約)浑厚。當(dāng)字典超過此大小時,將觸發(fā)溢出到磁盤根盒。 100000000 Druid.query.groupBy.maxOnDiskStorage 合并緩沖區(qū)或字典填滿時钳幅,每個查詢用于將結(jié)果集溢出到磁盤的最大磁盤空間量。超過此限制的查詢將失敗郑象。設(shè)置為零可禁用使用磁盤贡这。 0(禁用) 查詢上下文:
屬性 描述 maxMergingDictionarySize 可用于降低Druid.query.groupBy.maxMergingDictionarySize的默認(rèn)值。 maxOnDiskStorage 可用于降低Druid.query.groupBy.maxOnDiskStorage的默認(rèn)值厂榛。 -
高級配置(通用配置)
運(yùn)行時屬性:
屬性 描述 默認(rèn) Druid.query.groupBy.defaultStrategy 默認(rèn)groupBy查詢策略盖矫。 v2 Druid.query.groupBy.singleThreaded 使用單個線程合并結(jié)果。 否 查詢上下文:
屬性 描述 groupByStrategy 覆蓋Druid.query.groupBy.defaultStrategy的默認(rèn)值击奶。 groupByIsSingleThreaded 覆蓋Druid.query.groupBy.singleThreaded的默認(rèn)值辈双。 -
GroupBy v2配置
運(yùn)行時屬性:
屬性 描述 默認(rèn) Druid.query.groupBy.bufferGrouperInitialBuckets 堆外哈希表中用于結(jié)果分組的初始存儲桶數(shù)。設(shè)置為0以使用合理的默認(rèn)值(1024)柜砾。 0 Druid.query.groupBy.bufferGrouperMaxLoadFactor 用于結(jié)果分組的堆外哈希表的最大負(fù)載因子湃望。當(dāng)負(fù)載系數(shù)超過此大小時,表將增長或溢出到磁盤痰驱。設(shè)置為0以使用合理的默認(rèn)值(0.7)证芭。 0 Druid.query.groupBy.forceHashAggregation 強(qiáng)制使用基于哈希的聚合。 否 Druid.query.groupBy.intermediateCombineDegree 合并樹中合并在一起的中間節(jié)點(diǎn)數(shù)担映。更高的級別需要更少的線程废士,如果服務(wù)器有足夠強(qiáng)大的cpu核心,那么通過減少太多線程的開銷蝇完,這可能有助于提高查詢性能 8 Druid.query.groupBy.numParallelCombineThreads 并行合并線程的數(shù)量官硝。該值應(yīng)大于1以啟用并行合并功能。用于并行合并的實際線程數(shù)為min(Druid.query.groupBy.numParallelCombineThreads短蜕,Druid.processing.numThreads)氢架。 1(已禁用) Druid.query.groupBy.applyLimitPushDownToSegment 如果Broker將下限限制到可查詢的節(jié)點(diǎn)(Historicals,peons)朋魔,則在段掃描期間限制結(jié)果岖研。 真(啟用) 查詢上下文:
屬性 描述 默認(rèn) bufferGrouperInitialBuckets 覆蓋Druid.query.groupBy.bufferGrouperInitialBuckets的默認(rèn)值。 沒有 bufferGrouperMaxLoadFactor 覆蓋Druid.query.groupBy.bufferGrouperMaxLoadFactor的默認(rèn)值铺厨。 沒有 forceHashAggregation 覆蓋Druid.query.groupBy.forceHashAggregation的默認(rèn)值缎玫。 沒有 intermediateCombineDegree 覆蓋Druid.query.groupBy.intermediateCombineDegree的默認(rèn)值硬纤。 沒有 numParallelCombineThreads 覆蓋Druid.query.groupBy.numParallelCombineThreads的默認(rèn)值解滓。 沒有 sortByDimsFirst 首先按維度值對結(jié)果排序赃磨,然后按時間戳排序。 否 forceLimitPushDown 當(dāng)orderby中的所有字段都是分組鍵的一部分時洼裤,Broker將把limit申請下推至Historical進(jìn)程邻辉。當(dāng)排序使用字段不在分組關(guān)鍵字中時陈瘦,此優(yōu)化可能會導(dǎo)致近似結(jié)果的準(zhǔn)確性降低敢靡,因此截汪,在這種情況默認(rèn)禁用此項癣疟。需啟用則在上下文中設(shè)置 否 applyLimitPushDownToSegment 如果Broker將下限限制到可查詢的節(jié)點(diǎn)(Historical掏湾,peons)兆龙,則在段掃描期間限制結(jié)果宛官。此上下文屬性可覆蓋Druid.query.groupBy.applyLimitPushDownToSegment媒咳。 是
-
GroupBy v1配置
運(yùn)行時屬性:
屬性 描述 默認(rèn) Druid.query.groupBy.maxIntermediateRows 每段分組允許的最大行數(shù)迹缀。這是一個調(diào)整參數(shù)使碾,沒有強(qiáng)加任何限制。相反祝懂,它可能會將合并工作從每個細(xì)分引擎轉(zhuǎn)移到整體合并索引票摇。超過此限制的查詢不會失敗。 50000 Druid.query.groupBy.maxResults 最大結(jié)果數(shù)砚蓬。超過此限制的查詢將失敗矢门。 500000 支持的查詢上下文:
屬性 描述 默認(rèn) maxIntermediateRows 用于降低Druid.query.groupBy.maxIntermediateRows的默認(rèn)值。 沒有 maxResults 用于降低Druid.query.groupBy.maxResults的默認(rèn)值灰蛙。 沒有 useOffheap 設(shè)置為true可以在合并結(jié)果時以非堆方式存儲聚合祟剔。 否
基于數(shù)組的結(jié)果行
Druid內(nèi)部始終使用基于數(shù)組的groupBy結(jié)果行表示,但是默認(rèn)情況下摩梧,它在Broker處轉(zhuǎn)換為基于映射的結(jié)果格式物延。為了減少此轉(zhuǎn)換的開銷,如果在查詢上下文resultAsArray中將其設(shè)置為true障本,則結(jié)果也可以直接從Broker基于數(shù)組格式返回教届。
四、掃描查詢(Scan)
Scan查詢以流模式返回查詢結(jié)果驾霜。
除了將簡單的用法(向broker發(fā)送scan查詢)之外案训,還可以將scan查詢直接發(fā)送給Historical或流式攝取任務(wù)。如果要并行檢索大量數(shù)據(jù)粪糙,這將很有用强霎。
{
"queryType": "scan",
"dataSource": "wikipedia",
"resultFormat": "list",
"columns":[],
"intervals": [
"2013-01-01/2013-01-02"
],
"batchSize":20480,
"limit":3
}
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 scan | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
intervals | 定義查詢時間范圍。 | 是 |
resultFormat | 結(jié)果集格式 | 否 |
filter | 過濾器 | 否 |
columns | 要掃描的維度和指標(biāo)的字符串?dāng)?shù)組蓉冈。如果保留為空城舞,則返回所有維度和指標(biāo)轩触。 | 否 |
batchSize | 返回給客戶端之前緩沖的最大行數(shù)。默認(rèn)為20480 | 否 |
limit | 要返回多少行家夺。如果未指定脱柱,將返回所有行。 | 否 |
order | 根據(jù)時間戳返回的行的順序拉馋。支持“升序”榨为,“降序”和“無”(默認(rèn))。當(dāng)前煌茴,僅對__time字段中包含該列columns且滿足時間順序部分中概述的要求的查詢才支持“升序”和“降序” 随闺。 | 否 |
legacy | 與“scan-query”類似。默認(rèn)屬性設(shè)置Druid.query.scan.legacy蔓腐,默認(rèn)為false矩乐。 | 否 |
context | 上下文 | 否 |
當(dāng)resultFormat等于list時,結(jié)果:
[{
"segmentId" : "wikipedia_editstream_2012-12-29T00:00:00.000Z_2013-01-10T08:00:00.000Z_2013-01-10T08:13:47.830Z_v9",
"columns" : [
"timestamp",
"robot",
"namespace",
"anonymous",
"unpatrolled",
"page",
"language",
"newpage",
"user",
"count",
"added",
"delta",
"variation",
"deleted"
],
"events" : [ {
"timestamp" : "2013-01-01T00:00:00.000Z",
"robot" : "1",
"namespace" : "article",
"anonymous" : "0",
"unpatrolled" : "0",
"page" : "11._korpus_(NOVJ)",
"language" : "sl",
"newpage" : "0",
"user" : "EmausBot",
"count" : 1.0,
"added" : 39.0,
"delta" : 39.0,
"variation" : 39.0,
"deleted" : 0.0
}, {
"timestamp" : "2013-01-01T00:00:00.000Z",
"robot" : "0",
"namespace" : "article",
"anonymous" : "0",
"unpatrolled" : "0",
"page" : "112_U.S._580",
"language" : "en",
"newpage" : "1",
"user" : "MZMcBride",
"count" : 1.0,
"added" : 70.0,
"delta" : 70.0,
"variation" : 70.0,
"deleted" : 0.0
}, {
"timestamp" : "2013-01-01T00:00:00.000Z",
"robot" : "0",
"namespace" : "article",
"anonymous" : "0",
"unpatrolled" : "0",
"page" : "113_U.S._243",
"language" : "en",
"newpage" : "1",
"user" : "MZMcBride",
"count" : 1.0,
"added" : 77.0,
"delta" : 77.0,
"variation" : 77.0,
"deleted" : 0.0
} ]
} ]
當(dāng)resultFormat等于compactedList時回论,結(jié)果:
[{
"segmentId" : "wikipedia_editstream_2012-12-29T00:00:00.000Z_2013-01-10T08:00:00.000Z_2013-01-10T08:13:47.830Z_v9",
"columns" : [
"timestamp", "robot", "namespace", "anonymous", "unpatrolled", "page", "language", "newpage", "user", "count", "added", "delta", "variation", "deleted"
],
"events" : [
["2013-01-01T00:00:00.000Z", "1", "article", "0", "0", "11._korpus_(NOVJ)", "sl", "0", "EmausBot", 1.0, 39.0, 39.0, 39.0, 0.0],
["2013-01-01T00:00:00.000Z", "0", "article", "0", "0", "112_U.S._580", "en", "1", "MZMcBride", 1.0, 70.0, 70.0, 70.0, 0.0],
["2013-01-01T00:00:00.000Z", "0", "article", "0", "0", "113_U.S._243", "en", "1", "MZMcBride", 1.0, 77.0, 77.0, 77.0, 0.0]
]
} ]
[1] 時間排序
Scan查詢當(dāng)前只支持對非傳統(tǒng)查詢的時間戳排序散罕。使用時間戳排序?qū)a(chǎn)生的結(jié)果你們盟指定來自于哪一個具體的段。使用時間戳排序需要結(jié)果集限制要少于Druid.query.scan.maxRowsQueuedForOrdering 的行或所有掃描的段少于Druid.query.scan.maxSegmentPartitionsOrderedInMemory分區(qū)時透葛。除非指定了段列表笨使,否則直接發(fā)布到historicals的查詢不支持時間排序。這些限制的原因在于僚害,時間排序的實現(xiàn)使用兩種策略硫椰,如果不去限制的話,它們會消耗過多的堆內(nèi)存萨蚕。這些策略(下面列出)是根據(jù)historicals選擇的靶草,具體取決于查詢結(jié)果集限制和要掃描的段數(shù)。
優(yōu)先級隊列:historicals上的每個段都按順序打開岳遥。每行都添加到有界優(yōu)先級隊列中奕翔,該隊列按時間戳排序。對于超過結(jié)果集限制的每一行浩蓉,具有最早(如果遞減)時間戳或最新(如果遞升)時間戳的行將出隊派继。處理完每一行后,優(yōu)先級隊列的排序內(nèi)容將分批流回給broker捻艳。嘗試將太多的行加載到內(nèi)存中會帶來歷史節(jié)點(diǎn)內(nèi)存不足的風(fēng)險驾窟。該Druid.query.scan.maxRowsQueuedForOrdering屬性通過限制使用時間排序時,查詢結(jié)果集中的行數(shù)來防止這種情況认轨。
N向合并:對于每個段绅络,并行打開每個分區(qū)。由于每個分區(qū)的行已經(jīng)按時間排序,因此可以對每個分區(qū)的結(jié)果執(zhí)行n路合并恩急。這種方法不會將整個結(jié)果集持久存儲在內(nèi)存中(例如Priority Queue)杉畜,因為它會從合并函數(shù)返回批次時將其返回。但是衷恭,由于需要為每個分區(qū)打開解壓縮和解碼緩沖區(qū)此叠,嘗試查詢太多分區(qū)也可能導(dǎo)致高內(nèi)存使用。該Druid.query.scan.maxSegmentPartitionsOrderedInMemory限制通過限制使用時間順序時匾荆,隨時打開的分區(qū)的數(shù)量來防止這種情況拌蜘。
二者Druid.query.scan.maxRowsQueuedForOrdering和Druid.query.scan.maxSegmentPartitionsOrderedInMemory是可配置的杆烁,并且可以基于硬件規(guī)格與被查詢的維度數(shù)來調(diào)節(jié)牙丽。也可以使用查詢上下文中的maxRowsQueuedForOrdering和maxSegmentPartitionsOrderedInMemory屬性來覆蓋這些配置屬性。
[2] 傳統(tǒng)模式
Scan查詢支持傳統(tǒng)模式兔魂,該模式旨在與先前的Scan查詢contrib擴(kuò)展協(xié)議兼容烤芦。在傳統(tǒng)模式下,您可以期望以下行為更改:
- 該__time列返回為"timestamp"而不是"__time"析校。這將優(yōu)先于您可能擁有的其他任何列"timestamp"构罗。
- __time即使您沒有特別要求,該列也包含在列列表中智玻。
- 時間戳記以ISO8601時間字符串返回遂唧。
- 可以通過傳入 "legacy":true 查詢JSON或通過 Druid.query.scan.legacy=true 在Druid進(jìn)程中進(jìn)行設(shè)置來觸發(fā)傳統(tǒng)模式。如果您以前使用的是scan-query contrib擴(kuò)展名吊奢,則最佳遷移方式是在滾動升級過程中激活傳統(tǒng)模式盖彭,然后在升級完成后將其關(guān)閉。
[3] 配置屬性
屬性 | 描述 | 取值 | 默認(rèn) |
---|---|---|---|
Druid.query.scan.maxRowsQueuedForOrdering | 使用時間排序時返回的最大行數(shù) | [1页滚,2147483647]中的整數(shù) | 100000 |
Druid.query.scan.maxSegmentPartitionsOrderedInMemory | 使用時間排序時召边,每個historical掃描的最大段數(shù) | [1,2147483647]中的整數(shù) | 50 |
Druid.query.scan.legacy | 是否應(yīng)為Scan查詢打開傳統(tǒng)模式 | 是 或 否 | 否 |
[4] 查詢上下文屬性
屬性 | 描述 | 取值 | 默認(rèn) |
---|---|---|---|
maxRowsQueuedForOrdering | 使用時間排序時返回的最大行數(shù)裹驰。覆蓋同名的config隧熙。 | [1,2147483647]中的整數(shù) | Druid.query.scan.maxRowsQueuedForOrdering |
maxSegmentPartitionsOrderedInMemory | 使用時間排序時幻林,每個歷史記錄掃描的最大段數(shù)贞盯。覆蓋同名的config。 | [1沪饺,2147483647]中的整數(shù) | Druid.query.scan.maxSegmentPartitionsOrderedInMemory |
查詢context 的JSON對象:
{
"maxRowsQueuedForOrdering": 100001,
"maxSegmentPartitionsOrderedInMemory": 100
}
五躏敢、時間邊界查詢(TimeBoundary)
時間邊界查詢返回數(shù)據(jù)集的最早和最新數(shù)據(jù)點(diǎn)
{
"queryType" : "timeBoundary",
"dataSource": "sample_datasource",
"bound" : < "maxTime" | "minTime" > # optional, defaults to returning both timestamps if not set
"filter" : { "type": "and", "fields": [<filter>, <filter>, ...] } # optional
}
時間邊界查詢包含3個主要部分:
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 timeBoundary | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
bound | 可選,設(shè)置為maxTime或minTime僅返回最新或最早的時間戳随闽。如果未設(shè)置父丰,默認(rèn)返回兩者 | 否 |
filter | 見過濾器 | 否 |
context | 參見上下文 | 否 |
[ {
"timestamp" : "2013-05-09T18:24:00.000Z",
"result" : {
"minTime" : "2013-05-09T18:24:00.000Z",
"maxTime" : "2013-05-09T18:37:00.000Z"
}
} ]
六、段元數(shù)據(jù)查詢(SegmentMeatadata)
- 段中所有列的基數(shù)
- 段中字符串類型列的最小值/最大值
- 如果段列以平面格式存儲,則估計的字節(jié)大小
- 段內(nèi)存儲的行數(shù)
- 該段所覆蓋的區(qū)間
- 段中所有列的列類型
- 如果以平面格式存儲蛾扇,則估計的總段字節(jié)大小
- 段是否累積
- 段ID
{
"queryType":"segmentMetadata",
"dataSource":"sample_datasource",
"intervals":["2013-01-01/2014-01-01"]
}
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 segmentMetadata | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
intervals | 定義查詢時間范圍攘烛。 | 是 |
toInclude | 在結(jié)果中包括的列。默認(rèn)為所有镀首。 | 否 |
merge | 將所有單獨(dú)段的元數(shù)據(jù)結(jié)果合并在一起 | 否 |
context | 上下文 | 否 |
analysisTypes | 字符串列表坟漱,指定應(yīng)計算哪些列屬性(例如基數(shù),大懈濉)并在結(jié)果中返回芋齿。默認(rèn)為[“ cardinality”,“ interval”成翩,“ minmax”]觅捆,但可以使用段元數(shù)據(jù)查詢config覆蓋。 | 否 |
lenientAggregatorMerge | 如果為true麻敌,則合并聚合栅炒。 | 否 |
[ {
"id" : "some_id",
"intervals" : [ "2013-05-13T00:00:00.000Z/2013-05-14T00:00:00.000Z" ],
"columns" : {
"__time" : { "type" : "LONG", "hasMultipleValues" : false, "size" : 407240380, "cardinality" : null, "errorMessage" : null },
"dim1" : { "type" : "STRING", "hasMultipleValues" : false, "size" : 100000, "cardinality" : 1944, "errorMessage" : null },
"dim2" : { "type" : "STRING", "hasMultipleValues" : true, "size" : 100000, "cardinality" : 1504, "errorMessage" : null },
"metric1" : { "type" : "FLOAT", "hasMultipleValues" : false, "size" : 100000, "cardinality" : null, "errorMessage" : null }
},
"aggregators" : {
"metric1" : { "type" : "longSum", "name" : "metric1", "fieldName" : "metric1" }
},
"queryGranularity" : {
"type": "none"
},
"size" : 300000,
"numRows" : 5000000
} ]
維度列的類型為STRING,指標(biāo)列將具有類型FLOAT或LONG或者底層復(fù)雜的類型,如hyperUnique類型术羔。時間戳列的類型為LONG赢赊。
如果該errorMessage字段為非空,則不需要檢查其他的字段因為它們的內(nèi)容是不確定的级历。
只有維度列(即具有type為STRING)的列將具有任何基數(shù)释移。其余列(時間戳記和指標(biāo)列)將顯示基數(shù)為null。
[1] 時間間隔
如果未指定時間間隔寥殖,則查詢將使用默認(rèn)時間間隔玩讳,該時間間隔從最近段的結(jié)束時間開始到之前的可配置時間長度。該默認(rèn)時間段的長度是通過以下方式在Broker配置中設(shè)置的:Druid.query.segmentMetadata.defaultHistory
[2] 3種類型的toInclude對象
-
all
"toInclude": { "type": "all"}
-
none
"toInclude": { "type": "none"}
-
list
"toInclude": { "type": "list", "columns": [<string list of column names>]}
[3] analysisTypes
這是一列屬性扛禽,這些屬性確定有關(guān)列返回的信息量锋边,即要對列執(zhí)行的分析。
默認(rèn)情況下编曼,將使用“cardinality”豆巨,“interval”和“minmax”類型。如果不需要某個屬性掐场,則從此列表中刪除
可以通過以下方式在Broker配置中設(shè)置默認(rèn)分析類型: Druid.query.segmentMetadata.defaultAnalysisTypes
列分析的類型
-
cardinality
cardinality結(jié)果將返回每一列的估計基數(shù)下限往扔。僅與維列相關(guān)。
-
minmax
每列的估計最小值/最大值熊户。僅與維列相關(guān)萍膛。
-
size
結(jié)果中將包含估計的總段字節(jié)大小
-
intervals
結(jié)果中將包含與查詢段關(guān)聯(lián)的間隔列表
-
timestampSpec
結(jié)果中將包含存儲在段中的數(shù)據(jù)的timestampSpec
-
queryGranularity
結(jié)果中將包含存儲在段中的數(shù)據(jù)的查詢粒度
-
aggregators
結(jié)果中將包含可用于查詢指標(biāo)列的聚合器列表 合并可以嚴(yán)格也可以寬松 結(jié)果的形式是列名到聚合器的映射
-
rollup
結(jié)果為 true/false/null
[4] lenientAggregatorMerge
如果某些段的聚合器未知,或者兩個段的同一列使用不兼容的聚合器(例如嚷堡,longSum更改為doubleSum)蝗罗,則跨段的聚合器元數(shù)據(jù)之間可能會發(fā)生沖突艇棕。
聚合器可以嚴(yán)格合并(默認(rèn))或?qū)捤珊喜ⅰMㄟ^嚴(yán)格合并串塑,如果存在任何段的聚合器未知或任何類型的沖突沼琉,則合并的聚合器列表將為null。通過寬松的合并桩匪,將忽略具有未知聚合器的段打瘪,并且聚合器之間的沖突只會使該特定列的聚合器無效。
特別是在寬大合并的情況下傻昙,單個列的聚合器可能是null闺骚。嚴(yán)格合并不會發(fā)生這種情況。
七妆档、數(shù)據(jù)源元數(shù)據(jù)查詢(DatasourceMeatadata)
數(shù)據(jù)源的元數(shù)據(jù)查詢僻爽,返回數(shù)據(jù)源的元數(shù)據(jù)信息。
{
"queryType" : "dataSourceMetadata",
"dataSource": "sample_datasource"
}
數(shù)據(jù)源的元數(shù)據(jù)查詢包含兩個主要部分:
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 dataSourceMetadata | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
context | 參見上下文 | 否 |
[ {
"timestamp" : "2013-05-09T18:24:00.000Z",
"result" : {
"maxIngestedEventTime" : "2013-05-09T18:24:09.007Z"
}
} ]
八过吻、搜索查詢(Search)
搜索查詢返回與搜索規(guī)范匹配
{
"queryType": "search",
"dataSource": "sample_datasource",
"granularity": "day",
"searchDimensions": [
"dim1",
"dim2"
],
"query": {
"type": "insensitive_contains",
"value": "Ke"
},
"sort" : {
"type": "lexicographic"
},
"intervals": [
"2013-01-01T00:00:00.000/2013-01-03T00:00:00.000"
]
}
屬性 | 描述 | 必要 |
---|---|---|
queryType | 設(shè)置查詢類型為時間序列 search | 是 |
dataSource | 數(shù)據(jù)源 | 是 |
granularity | 定義查詢結(jié)果的粒度 | 是 |
filter | 過濾器 | 否 |
limit | 限制結(jié)果數(shù)量进泼。默認(rèn)值為無限制。 | 否 |
intervals | 定義查詢時間范圍纤虽。 | 是 |
searchDimensions | 要進(jìn)行搜索的維度。默認(rèn)在所有維度上進(jìn)行绞惦。 | 沒有 |
query | 查詢 | 是 |
sort | 指定排序字段 字典(默認(rèn))逼纸,字母,數(shù)字等济蝉。 | 沒有 |
context | 上下文 | 沒有 |
[
{
"timestamp": "2013-01-01T00:00:00.000Z",
"result": [
{
"dimension": "dim1",
"value": "Ke$ha",
"count": 3
},
{
"dimension": "dim2",
"value": "Ke$haForPresident",
"count": 1
}
]
},
{
"timestamp": "2013-01-02T00:00:00.000Z",
"result": [
{
"dimension": "dim1",
"value": "SomethingThatContainsKe",
"count": 1
},
{
"dimension": "dim2",
"value": "SomethingElseThatContainsKe",
"count": 2
}
]
}
]
[1] 實施細(xì)節(jié)
可以使用兩種不同的策略來執(zhí)行搜索查詢杰刽。默認(rèn)策略由Broker上的“ Druid.query.search.searchStrategy”運(yùn)行時屬性確定⊥趼耍可以在查詢上下文中使用“ searchStrategy”來覆蓋它贺嫂。如果既未設(shè)置上下文字段也未設(shè)置屬性,則將使用“ useIndexes”策略雁乡。
“useIndexes”策略首先根據(jù)搜索維度對位圖索引的支持將其分為兩類第喳。然后,它將useIndexes策略和基cursorOnly策略分別應(yīng)用于支持位圖和其他維度的維組踱稍。useIndexes策略用于搜索查詢處理曲饱。對于每個維度,它會讀取每個維度值的位圖索引珠月,評估搜索謂詞扩淀,最后檢查時間間隔和篩選謂詞。useIndexes策略對于大基數(shù)的搜索維度性能較低啤挎,這意味著大多數(shù)搜索維值都是唯一的驻谆。
“cursorOnly”策略生成基于基礎(chǔ)指針計劃。該計劃創(chuàng)建一個指針標(biāo),該指針從queryableIndexSegment中讀取一行胜臊,然后評估搜索的詞氛谜。如果某些過濾器支持位圖索引,則指針只能讀取滿足這些過濾器的行区端,從而節(jié)省了I/O成本值漫。但是,對于低選擇性的過濾器织盼,它可能會很慢杨何。
“auto”策略使用基于搜索成本的計劃程序,來選擇最佳搜索策略沥邻。它評估useIndexes和cursorOnly兩種策略的成本危虱,并選擇最佳的計劃。當(dāng)前唐全,由于成本估算的開銷埃跷,默認(rèn)情況下未啟用它。
[2] 服務(wù)器配置
屬性 | 描述 | 默認(rèn) |
---|---|---|
Druid.query.search.searchStrategy | 默認(rèn)搜索查詢策略邮利。 | useIndexes |
[3] 查詢上下文
屬性 | 描述 |
---|---|
searchStrategy | 覆蓋Druid.query.search.searchStrategy此屬性值弥雹。 |
九、選擇查詢(Select)
從當(dāng)前新版本開始延届,刪除select的查詢使用Scan查詢代替剪勿,該查詢可提高內(nèi)存使用率和性能。這解決了用戶在選擇查詢中遇到Druid內(nèi)存不足或速度變慢的問題方庭。
Scan查詢具有不同的語法厕吉,但支持Select查詢的許多功能,包括時間排序和限制械念。Scan查詢不包括Select查詢的分頁功能头朱;但是,在許多情況下龄减,使用Scan不需要分頁项钮,因為它能夠在一個調(diào)用中返回幾乎無限數(shù)量的結(jié)果。
十欺殿、多值維度查詢(Multi-value dimensions)
Druid支持多值維度查詢寄纵。當(dāng)輸入字段包含的值是數(shù)組而不是單個值(例如JSON數(shù)組或包含一個或多個listDelimiter 字符的TSV字段)時,將生成這些字段脖苏。
當(dāng)多值維度用作分組依據(jù)的維度時程拭,本文檔描述了groupBy(topN具有類似行為)查詢的行為。有關(guān)內(nèi)部表示形式的詳細(xì)信息棍潘,請參見分段中的多值列一 節(jié)恃鞋。本文檔中的示例采用本機(jī)Druid查詢的形式崖媚。有關(guān)在SQL中使用多值字符串維的詳細(xì)信息,請參閱Druid SQL文檔恤浪。
[1] 查詢多值維度
假設(shè)您有一個數(shù)據(jù)源畅哑,該數(shù)據(jù)源的段中包含以下行,且其多值維度稱為tags水由。
{"timestamp": "2011-01-12T00:00:00.000Z", "tags": ["t1","t2","t3"]} #row1
{"timestamp": "2011-01-13T00:00:00.000Z", "tags": ["t3","t4","t5"]} #row2
{"timestamp": "2011-01-14T00:00:00.000Z", "tags": ["t5","t6","t7"]} #row3
{"timestamp": "2011-01-14T00:00:00.000Z", "tags": []} #row4
[2] Filter
所有查詢類型以及經(jīng)過過濾的聚合器都可以對多值維度進(jìn)行過濾荠呐。過濾器在多值維度上遵循以下規(guī)則:
- 如果多值維度的任何值與過濾器匹配,則值過濾器(例如“selector”砂客,“bound”和“in”)將與一行匹配泥张。
- 如果維度有任何重疊,則“列比較”過濾器將匹配一行鞠值。
- 匹配null或""(空字符串)的值過濾器將匹配多值維度中的空單元格媚创。
- 邏輯表達(dá)式過濾器的行為與在單值維度上的行為相同:如果所有基礎(chǔ)過濾器均與該行匹配,則“and”匹配該行彤恶;如果任何基礎(chǔ)過濾器匹配該行钞钙,則“or”匹配該行;如果基礎(chǔ)過濾器與該行不匹配声离,則“not”與該行匹配芒炼。
例如,此“or”過濾器將匹配上面數(shù)據(jù)集的row1和row2抵恋,但不匹配row3:
{
"type": "or",
"fields": [
{
"type": "selector",
"dimension": "tags",
"value": "t1"
},
{
"type": "selector",
"dimension": "tags",
"value": "t3"
}
]
}
此“and”過濾器將僅匹配上述數(shù)據(jù)集的row1:
{
"type": "and",
"fields": [
{
"type": "selector",
"dimension": "tags",
"value": "t1"
},
{
"type": "selector",
"dimension": "tags",
"value": "t3"
}
]
}
此“selector”過濾器將匹配以上數(shù)據(jù)集的row4:
{
"type": "selector",
"dimension": "tags",
"value": null
}
[3] Group
topN和groupBy查詢可以對多值維度進(jìn)行分組焕议。在對多值維度進(jìn)行分組時,匹配行中的所有值將用于為每個值生成一組弧关。可以認(rèn)為這等效于許多SQL語言支持UNNEST的ARRAY類型上使用的運(yùn)算符唤锉。這意味著查詢有可能返回的行多于結(jié)果行數(shù)世囊。例如,一個topn的維度列tags與filter "t1" AND "t3"將只ROW1匹配窿祥,并與三個組生成結(jié)果:t1株憾,t2,和t3晒衩。如果只需要包含與filter匹配的值嗤瞎,則可以使用filter的 DimensionSpec。這也可以提高性能听系。
不使用filter的GroupBy查詢
{
"queryType": "groupBy",
"dataSource": "test",
"intervals": [
"1970-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z"
],
"granularity": {
"type": "all"
},
"dimensions": [
{
"type": "default",
"dimension": "tags",
"outputName": "tags"
}
],
"aggregations": [
{
"type": "count",
"name": "count"
}
]
}
返回結(jié)果贝奇。
[
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t1"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t2"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 2,
"tags": "t3"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t4"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 2,
"tags": "t5"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t6"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t7"
}
}
]
使用selector查詢使用filter的結(jié)果進(jìn)行GroupBy查詢
{
"queryType": "groupBy",
"dataSource": "test",
"intervals": [
"1970-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z"
],
"filter": {
"type": "selector",
"dimension": "tags",
"value": "t3"
},
"granularity": {
"type": "all"
},
"dimensions": [
{
"type": "default",
"dimension": "tags",
"outputName": "tags"
}
],
"aggregations": [
{
"type": "count",
"name": "count"
}
]
}
返回結(jié)果。
[
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t1"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t2"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 2,
"tags": "t3"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t4"
}
},
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 1,
"tags": "t5"
}
}
]
您可能會驚訝地發(fā)現(xiàn)結(jié)果中包含“t1”靠胜,“t2”掉瞳,“t4”和“t5”毕源。發(fā)生這種情況是因為查詢過濾器在分解前應(yīng)用于行。對于多值維度陕习,“t3”的選擇器過濾器將匹配row1和row2霎褐,然后進(jìn)行分解。如果多個值中的任何單個值與查詢過濾器匹配该镣,則查詢過濾器將匹配一行冻璃。
使用selector查詢過濾器和“維度”屬性中的其他過濾器進(jìn)行GroupBy查詢,要解決上述問題并僅獲取返回的“t3”行,則必須使用“過濾的尺寸規(guī)格”损合,如下面的查詢所示省艳。
{
"queryType": "groupBy",
"dataSource": "test",
"intervals": [
"1970-01-01T00:00:00.000Z/3000-01-01T00:00:00.000Z"
],
"filter": {
"type": "selector",
"dimension": "tags",
"value": "t3"
},
"granularity": {
"type": "all"
},
"dimensions": [
{
"type": "listFiltered",
"delegate": {
"type": "default",
"dimension": "tags",
"outputName": "tags"
},
"values": ["t3"]
}
],
"aggregations": [
{
"type": "count",
"name": "count"
}
]
}
返回結(jié)果。
[
{
"timestamp": "1970-01-01T00:00:00.000Z",
"event": {
"count": 2,
"tags": "t3"
}
}
]
對于groupBy查詢塌忽,使用具有spec的結(jié)果可能會得到類似的結(jié)果拍埠,但是使用過濾后的DimensionSpec會更加有效,因為這是在查詢處理管道中的最低級別的應(yīng)用土居。
十一枣购、查找查詢(Lookups)
Lookups是Druid中的一個概念,其中(可選)將維值替換為新值擦耀,從而實現(xiàn)類似聯(lián)接的功能棉圈。在Druid中應(yīng)用查找類似于在數(shù)據(jù)倉庫中加入維度表。就這些文檔而言眷蜓,“key”是指要匹配的值分瘾,“value”是指其替換值。因此吁系,如果您想映射 appid-12345到德召,Super Mega Awesome App則鍵為appid-12345,值將為 Super Mega Awesome App汽纤。
值得注意的是上岗,查找不僅支持將鍵一對一映射到唯一值(例如國家/地區(qū)代碼和國家/地區(qū)名稱)的用例奈揍,而且還支持將多個ID映射到同一值(例如跷究,多個應(yīng)用程序ID)的用例。映射到單個客戶經(jīng)理传轰。當(dāng)查詢是一對一的時背传,Druid可以在查詢時應(yīng)用其他優(yōu)化呆瞻。
查找沒有歷史記錄。他們總是使用當(dāng)前數(shù)據(jù)径玖。這意味著痴脾,如果某個特定應(yīng)用程序ID的主要客戶經(jīng)理發(fā)生了變化,并且您發(fā)出了一個查詢挺狰,以查找存儲該應(yīng)用程序ID與客戶經(jīng)理的關(guān)系明郭,則它將返回該應(yīng)用程序ID的當(dāng)前客戶經(jīng)理买窟。
如果您需要數(shù)據(jù)時間范圍敏感的查找,那么當(dāng)前在查詢時不動態(tài)支持這種用例薯定,并且此類數(shù)據(jù)屬于原始的非規(guī)范化數(shù)據(jù)始绍,供在Druid中使用。
可以在查詢時將很小的查找(鍵的數(shù)量在幾十到幾百的數(shù)量級上)作為“映射”查找(根據(jù)維度規(guī)格)進(jìn)行傳遞话侄。
其他查找類型也可以作為擴(kuò)展使用亏推,包括:
- 通過lookups-cached-global從本地文件,遠(yuǎn)程URI或JDBC全局緩存的查找年堆。
- 通過kafka-extraction-namespace從Kafka主題全局緩存的查找吞杭。
[1] 查詢語法
在Druid SQL中,可以使用LOOKUP函數(shù)查詢查詢
SELECT LOOKUP(column_name, 'lookup-name'), COUNT(*) FROM datasource GROUP BY 1
在本機(jī)json查詢中变丧,可以使用維度列或擴(kuò)展查詢芽狗。
[2] 查詢執(zhí)行
當(dāng)查詢執(zhí)行涉及到的聚合時,Druid可以決定在掃描和聚合行時應(yīng)用查詢痒蓬,還是在聚合完成后應(yīng)用查詢童擎。聚合完成后應(yīng)用查找更為有效,因此Druid會這樣做攻晒。Druid通過檢查查找是否標(biāo)記為“injective”來決定顾复。通常,應(yīng)該為任何自然一對一的查找設(shè)置此屬性鲁捏,以允許Druid盡可能快地運(yùn)行查詢芯砸。
內(nèi)射式查找應(yīng)包括可能顯示在數(shù)據(jù)集中的所有可能的鍵,并且還應(yīng)將所有鍵映射成唯一值给梅。這很重要假丧,因為非注入式查找可能會將不同的鍵映射到相同的值,這必須在聚合過程中加以考慮动羽,以免查詢結(jié)果包含兩個應(yīng)該聚合為一個的結(jié)果值虎谢。
-
此查詢是內(nèi)射性的(假定它包含數(shù)據(jù)中所有可能的鍵):
1 -> Foo 2 -> Bar 3 -> Billy
-
但有一個不是,因為“ 2”和“ 3”都映射到相同的鍵:
1 -> Foo 2 -> Bar 3 -> Bar
要告訴Druid您的lookup是已經(jīng)配置的 "injective":true曹质,必須在查找配置中指定。Druid不會自動檢測到這一點(diǎn)擎场。
[3] 動態(tài)配置
動態(tài)查找配置是一項實驗功能羽德。不再支持靜態(tài)配置。以下內(nèi)容記錄了可通過Coordinator訪問的群集范圍配置的行為迅办。通過服務(wù)器“層”的概念傳遞配置宅静。“層”定義為一組接收查詢站欺,一組查詢的服務(wù)姨夹。例如纤垂,您可能將所有“歷史記錄”作為的一部分__default,而“Peons”則作為其任務(wù)所使用的數(shù)據(jù)源的各個層的一部分磷账。查找的層完全獨(dú)立于歷史層峭沦。
通過以下URI模板使用JSON訪問這些配置
http://<COORDINATOR_IP>:<PORT>/Druid/coordinator/v1/lookups/config/{tier}/{id}
假定以下所有URI都已http://<COORDINATOR_IP>:<PORT>添加。
如果你以前從來沒有配置lookup逃糟,您必須張貼一個空的JSON對象{}來/Druid/coordinator/v1/lookups/config初始化配置吼鱼。
將返回以下結(jié)果之一:
- 404, 如果找不到資源
- 400,如果請求的格式有問題
- 202, 如果請求被異步接受(POST和DELETE)
- 200绰咽,如果請求成功(僅GET)
[4] 配置傳播行為
配置由Coordinator傳播到查詢服務(wù)進(jìn)程(Broker/Router/Peon/Historical)菇肃。查詢服務(wù)流程具有內(nèi)部API,用于管理流程上的查找取募,并且由Coordinator使用琐谤。Coordinator會定期檢查是否有任何進(jìn)程需要加載/刪除,查找并適當(dāng)?shù)馗滤鼈儭?/p>
單個查詢服務(wù)過程只能同時處理2個查找配置傳播請求。應(yīng)用此限制是為了防止查找處理占用過多的服務(wù)器HTTP連接玩敏。
[5] 用于配置查找的API
批量更新
可以通過將JSON對象來批量更新查找/Druid/coordinator/v1/lookups/config
{
"<tierName>": {
"<lookupName>": {
"version": "<version>",
"lookupExtractorFactory": {
"type": "<someExtractorFactoryType>",
"<someExtractorField>": "<someExtractorValue>"
}
}
}
}
“version”是由用戶分配的任意字符串斗忌,當(dāng)對現(xiàn)有查找進(jìn)行更新時,用戶將需要指定詞典上更高的版本聊品。
配置示例
{
"__default": {
"country_code": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"77483": "United States"
}
}
},
"site_id": {
"version": "v0",
"lookupExtractorFactory": {
"type": "cachedNamespace",
"extractionNamespace": {
"type": "jdbc",
"connectorConfig": {
"createTables": true,
"connectURI": "jdbc:mysql:\/\/localhost:3306\/Druid",
"user": "Druid",
"password": "diurd"
},
"table": "lookupTable",
"keyColumn": "country_id",
"valueColumn": "country_name",
"tsColumn": "timeColumn"
},
"firstCacheTimeout": 120000,
"injective": true
}
},
"site_id_customer1": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"847632": "Internal Use Only"
}
}
},
"site_id_customer2": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"AHF77": "Home"
}
}
}
},
"realtime_customer1": {
"country_code": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"77483": "United States"
}
}
},
"site_id_customer1": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"847632": "Internal Use Only"
}
}
}
},
"realtime_customer2": {
"country_code": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"77483": "United States"
}
}
},
"site_id_customer2": {
"version": "v0",
"lookupExtractorFactory": {
"type": "map",
"map": {
"AHF77": "Home"
}
}
}
}
}
映射中的所有條目將更新成現(xiàn)有條目飞蹂。沒有的條目將被刪除。
[6] 更新查詢
通過POST請求一個特定的查找提取器工廠/Druid/coordinator/v1/lookups/config/{tier}/{id}將更新該特定的提取器工廠翻屈。
示例請求/Druid/coordinator/v1/lookups/config/realtime_customer1/site_id_customer1
{
"version": "v1",
"lookupExtractorFactory": {
"type": "map",
"map": {
"847632": "Internal Use Only"
}
}
}
這將用上面定義的site_id_customer1替換查找到的realtime_customer1陈哑。
-
獲取所有查詢
GET請求到/Druid/coordinator/v1/lookups/config/all將返回所有已知查找的功能和所有層次。
-
查找
通過GET特定的查找提取器工廠來完成/Druid/coordinator/v1/lookups/config/{tier}/{id}
示例:一個GET請求 /Druid/coordinator/v1/lookups/config/realtime_customer2/site_id_customer2應(yīng)該返回
{ "version": "v1", "lookupExtractorFactory": { "type": "map", "map": { "AHF77": "Home" } } }
-
刪除查詢
DELETE請求/Druid/coordinator/v1/lookups/config/{tier}/{id}也可以從集群刪除查找伸眶。如果是該層中的最后一次查找惊窖,則該層也將被刪除。
-
刪除層
DELETE請求/Druid/coordinator/v1/lookups/config/{tier}會從集群中刪除該層厘贼。
-
層列表名稱
GET請求/Druid/coordinator/v1/lookups/config將在動態(tài)配置返回已知層名稱的列表界酒。除了動態(tài)配置中已知的層之外,要發(fā)現(xiàn)集群中當(dāng)前活動的層的列表嘴秸,設(shè)置discover=true 可以按照來添加參數(shù)/Druid/coordinator/v1/lookups/config?discover=true
-
列出查詢名稱
GET請求/Druid/coordinator/v1/lookups/config/{tier}會返回已知的查找該層級名稱列表毁欣。
這些端點(diǎn)可用于獲取已配置的查找到使用諸如“歷史記錄”之類的查找的進(jìn)程的傳播狀態(tài)。
[7] 查找狀態(tài)的API
-
列出所有查找的加載狀態(tài)
GET /Druid/coordinator/v1/lookups/status帶有可選的查詢參數(shù)detailed岳掐。
-
列出層中查找的負(fù)載狀態(tài)
GET /Druid/coordinator/v1/lookups/status/{tier}帶有可選的查詢參數(shù)detailed凭疮。
-
列出單次查找的加載狀態(tài)
GET /Druid/coordinator/v1/lookups/status/{tier}/{lookup}帶有可選的查詢參數(shù)detailed。
-
列出所有進(jìn)程的查找狀態(tài)
GET /Druid/coordinator/v1/lookups/nodeStatus帶有discover用于從Zookeeper發(fā)現(xiàn)層的可選查詢參數(shù)或列出的已配置查找層串述。
-
列出層中進(jìn)程的查找狀態(tài)
GET /Druid/coordinator/v1/lookups/nodeStatus/{tier}
-
列出單個進(jìn)程的查找狀態(tài)
GET /Druid/coordinator/v1/lookups/nodeStatus/{tier}/{host:port}
[8] 內(nèi)部API
Peon执解,Router,Broker和Historical進(jìn)程都可以使用查找配置纲酗。這些流程使用一個內(nèi)部API來從list/load/drop其查找內(nèi)容/Druid/listen/v1/lookups衰腌。這些返回值與集群范圍的動態(tài)配置遵循相同的約定新蟆。以下請求示例可用于調(diào)試,但不能用于其他右蕊。
-
獲取查詢
一個GET以處理在/Druid/listen/v1/lookups將返回所有在進(jìn)程當(dāng)前活躍查詢的JSON地圖琼稻。返回值將是查找到其提取器工廠的json映射。
{ "site_id_customer2": { "version": "v1", "lookupExtractorFactory": { "type": "map", "map": { "AHF77": "Home" } } } }
-
查找
GET請求/Druid/listen/v1/lookups/some_lookup_name將返回LookupExtractorFactory由確定的查找some_lookup_name尤泽。返回值將是工廠的json表示形式欣簇。
{ "version": "v1", "lookupExtractorFactory": { "type": "map", "map": { "AHF77": "Home" } } }
-
配置
要將Broker/Router/Historical/Peon配置為查找層的一部分,請使用Druid.zk.paths.lookupTier屬性坯约。
屬性 描述 默認(rèn) Druid.lookup.lookupTier 查詢層熊咽。這獨(dú)立于其他層。 __default Druid.lookup.lookupTierIsDatasource 對于諸如,為服務(wù)任務(wù)編制索引之類的事情闹丐,數(shù)據(jù)源將在任務(wù)運(yùn)行時的屬性中傳遞横殴。此選項從與任務(wù)數(shù)據(jù)源相同的值中獲取tierName。建議將其用作索引服務(wù)的Peon選項(如果有的話)卿拴。如果為true衫仑,則Druid.lookup.lookupTier不得指定 "false" 要動態(tài)配置管理器的行為,請在Coordinator上使用以下屬性:
屬性 描述 默認(rèn) Druid.manager.lookups.hostTimeout 超時(以毫秒為單位堕花,用于處理請求 2000(2秒) Druid.manager.lookups.allHostTimeout 超時(以毫秒為單位)以完成所有進(jìn)程的查找管理文狱。 900000(15分鐘) Druid.manager.lookups.period 在管理周期之間暫停多長時間 120000(2分鐘) Druid.manager.lookups.threadPoolSize 可以同時管理的服務(wù)進(jìn)程數(shù) 10
-
重啟時保存配置
可以在重新啟動之前保存配置,這樣一來缘挽,進(jìn)程將不必等待協(xié)調(diào)器操作重新填充其查找瞄崇。為此,設(shè)置以下屬性:
屬性 描述 默認(rèn) Druid.lookup.snapshotWorkingDir 用于存儲當(dāng)前查找配置快照的工作路徑壕曼,將此屬性保留為null將禁用快照/引導(dǎo)實用程序 null Druid.lookup.enableLookupSyncOnStartup 啟動時使用Coordinator啟用查找同步過程苏研。可查詢的進(jìn)程將從Coordinator獲取并加載查找腮郊,而不是等待Coordinator為其加載查找摹蘑。如果集群中未配置任何查找,則用戶可以選擇禁用此選項轧飞。 true Druid.lookup.numLookupLoadingThreads 啟動時用于并行加載查找的線程數(shù)衅鹿。啟動完成后,該線程池將被銷毀过咬。在JVM的生存期內(nèi)不保留它 可用處理器/2 Druid.lookup.coordinatorFetchRetries 在啟動時同步期間塘安,嘗試重試幾次以從Coordinator獲取查找bean列表。 3 Druid.lookup.lookupStartRetries 在啟動時同步或運(yùn)行時中援奢,嘗試重試多少次才能啟動每個查找。 3 Druid.lookup.coordinatorRetryDelay 啟動時同步期間忍捡,兩次重試之間的延遲時間(以毫秒為單位)集漾,以從Coordinator中獲取查找列表切黔。 60_000
[9] 內(nèi)省查找
如果查找類型實現(xiàn),則Broker提供用于查找自省的API LookupIntrospectHandler具篇。
GET請求/Druid/v1/lookups/introspect/{lookupId}將返回完整值纬霞。
-
如:GET /Druid/v1/lookups/introspect/nato-phonetic
{ "A": "Alfa", "B": "Bravo", "C": "Charlie", ... "Y": "Yankee", "Z": "Zulu", "-": "Dash" }
Key列表可以通過檢索GET到/Druid/v1/lookups/introspect/{lookupId}/keys
-
如:GET /Druid/v1/lookups/introspect/nato-phonetic/keys
[ "A", "B", "C", ... "Y", "Z", "-" ]
GET請求/Druid/v1/lookups/introspect/{lookupId}/values"將返回值列表。
-
如:GET /Druid/v1/lookups/introspect/nato-phonetic/values
[ "Alfa", "Bravo", "Charlie", ... "Yankee", "Zulu", "Dash" ]
十二驱显、Join查詢(Joins)
Druid對通過查詢時間查找進(jìn)行聯(lián)接的支持有限诗芜。查詢時查找的常見用例是將一個維度值(例如,字符串ID)替換為另一個值(例如埃疫,人類可讀的字符串值)伏恐。這類似于星形模式連接。
Druid尚未完全支持聯(lián)接栓霜。盡管Druid的存儲格式允許實現(xiàn)連接(對于作為維包括的列翠桦,不存在保真度的損失),但由于以下原因胳蛮,尚未完全實現(xiàn)對連接的完全支持:
- 根據(jù)我們的專業(yè)經(jīng)驗销凑,擴(kuò)展連接查詢一直是使用分布式數(shù)據(jù)庫的一個長期瓶頸。
- 與管理大量并發(fā)仅炊,連接繁重的工作負(fù)載所預(yù)期的問題相比斗幼,功能上的增量收益被認(rèn)為價值不高。
- 聯(lián)接查詢本質(zhì)上是基于一組共享鍵合并兩個或更多數(shù)據(jù)流抚垄。我們知道的聯(lián)接查詢的主要高級策略是基于哈希的策略或排序合并策略蜕窿。基于散列的策略要求除了一個數(shù)據(jù)集外督勺,其他所有數(shù)據(jù)集都可以像散列表一樣使用渠羞,然后對“主”流中的每一行對該散列表執(zhí)行查找操作。排序合并策略假定每個流按連接鍵進(jìn)行排序智哀,因此允許流的增量連接次询。但是,這些策略中的每一種都需要以排序的順序或哈希表的形式實現(xiàn)一定數(shù)量的流瓷叫。
當(dāng)聯(lián)接的所有側(cè)面都是非常大的表(> 10億條記錄)時屯吊,要實現(xiàn)預(yù)聯(lián)接流,就需要進(jìn)行復(fù)雜的分布式內(nèi)存管理摹菠。我們針對高并發(fā)盒卸,多租戶工作負(fù)載這一事實,只會加劇內(nèi)存管理的復(fù)雜性次氨。
十三蔽介、多租戶(Multitenancy considerations)
Druid通常用于增強(qiáng)面向用戶的數(shù)據(jù)應(yīng)用程序,而多租戶是其中的重要要求。本文檔概述了Druid的多租戶存儲和查詢功能虹蓄。
[1] 共享的數(shù)據(jù)源還是每個租戶的數(shù)據(jù)源犀呼?
數(shù)據(jù)源與數(shù)據(jù)庫表是等效的。多租戶工作負(fù)載可以為每個租戶使用單獨(dú)的數(shù)據(jù)源薇组,也可以使用“tenant_id”維護(hù)在多個租戶之間共享一個或多個數(shù)據(jù)源外臂。在確定要要設(shè)置的租戶和數(shù)據(jù)源的映射關(guān)系時,要考慮好每一種設(shè)置的優(yōu)缺點(diǎn)律胀。
[2] 每個租戶的數(shù)據(jù)源的優(yōu)點(diǎn):
- 每個數(shù)據(jù)源可以具有自己的架構(gòu)宋光,自己寫數(shù)據(jù),自己的分區(qū)規(guī)則以及自己的數(shù)據(jù)加載和到期規(guī)則炭菌。
- 查詢可以更快罪佳,因為要檢查典型租戶的查詢的段將更少。
- 您將獲得最大的靈活性娃兽。
[3] 共享數(shù)據(jù)源的優(yōu)點(diǎn):
- 每個數(shù)據(jù)源都需要使用自己的JVM進(jìn)行實時索引菇民。
- 每個數(shù)據(jù)源都需要自己的YARN資源才能用于Hadoop批處理作業(yè)。
- 每個數(shù)據(jù)源在磁盤上都需要其自己的段文件投储。
- 由于這些原因第练,擁有大量的小型數(shù)據(jù)源可能是浪費(fèi)資源的。
一種折衷辦法是使用多個數(shù)據(jù)源玛荞,但使用數(shù)量少于租戶娇掏。例如,您可能有一些帶有分區(qū)規(guī)則A的租戶勋眯,有些帶有分區(qū)規(guī)則B的租戶婴梧;您可以使用兩個數(shù)據(jù)源,并在兩個數(shù)據(jù)源之間拆分租戶客蹋。
[4] 對共享數(shù)據(jù)源進(jìn)行分區(qū)
如果您的多租戶群集使用共享數(shù)據(jù)源塞蹭,則大多數(shù)查詢可能會在“tenant_id”維度上進(jìn)行過濾。如果租戶對數(shù)據(jù)進(jìn)行了很好的分區(qū)讶坯,則這類查詢的效果最佳番电。有幾種方法可以完成此操作。
- 使用批索引辆琅,您可以使用一維分區(qū)按tenant_id對數(shù)據(jù)進(jìn)行分區(qū)漱办。Druid總是按時間先分區(qū),但是每個時間段內(nèi)的次分區(qū)將在tenant_id上婉烟。
- 使用實時索引娩井,您可以通過調(diào)整發(fā)送到Druid的流來實現(xiàn)。例如似袁,如果您使用的是Kafka洞辣,則可以讓您的Kafka生產(chǎn)者按tenant_id的哈希值對主題進(jìn)行分區(qū)咐刨。
[5] 定制數(shù)據(jù)分發(fā)
Druid還通過提供可配置的數(shù)據(jù)分發(fā)方式來支持多租戶∥荼耄可以將Druid的Historical過程配置為層所宰,并可以設(shè)置規(guī)則來確定哪些段進(jìn)入哪個層。一種使用情況是畜挥,與較舊的數(shù)據(jù)相比,最近的數(shù)據(jù)傾向于更頻繁地訪問婴谱。通過分層蟹但,可以將更多的最新細(xì)分托管在功能更強(qiáng)大的硬件上,以提高性能谭羔』牵可以在較便宜的硬件(不同層)上復(fù)制最近段的第二個副本,也可以將較舊的段存儲在此層上瘟裸。
[6] 支持高查詢并發(fā)
Druid的基本計算單位是 段客叉。進(jìn)程并行掃描段,并且可以設(shè)置進(jìn)程數(shù)量Druid.processing.numThreads并行掃描话告。為了并行處理更多數(shù)據(jù)并提高性能兼搏,可以將更多CPU添加到群集中。Druid段的大小應(yīng)確定為使得任何給定段上的任何計算最多應(yīng)在500毫秒內(nèi)完成沙郭。
Druid在內(nèi)部將掃描段的請求存儲在優(yōu)先級隊列中佛呻。如果給定的查詢需要掃描的段數(shù)比集群中可用處理器的總數(shù)更多,并且同時運(yùn)行著許多同樣耗時的查詢病线,則我們不希望任何查詢都被餓死吓著。Druid的內(nèi)部處理邏輯將從一個查詢中掃描一組段,并在掃描完成后立即釋放資源送挑。這允許掃描來自另一個查詢的第二組細(xì)分绑莺。通過使段計算時間保持很小,我們可以確保不斷產(chǎn)生資源惕耕,并且處理與不同查詢有關(guān)的段纺裁。
Druid查詢可以選擇priority在查詢上下文中設(shè)置標(biāo)志∩耐唬可以將低速查詢(下載或報表查詢)降低優(yōu)先級对扶,而更具交互性的查詢可以具有更高的優(yōu)先級。
broker程序也可以專用于給定的層惭缰。例如浪南,一組broker程序可以專用于快速的交互式查詢,而另一組broker程序可以專用于較慢的報告查詢漱受。Druid還提供了一個Router 進(jìn)程络凿,可以根據(jù)各種查詢參數(shù)(數(shù)據(jù)源骡送,時間間隔等)將查詢路由到不同的Broker。
十四絮记、緩存查詢(Query caching)
Druid在段和整個查詢結(jié)果級別都支持查詢結(jié)果緩存摔踱。緩存數(shù)據(jù)可以存儲在本地JVM堆中,也可以存儲在外部分布式鍵/值存儲中怨愤。在所有情況下派敷,Druid緩存都是查詢結(jié)果緩存。唯一的區(qū)別是結(jié)果是特定段的部分結(jié)果還是整個查詢的結(jié)果撰洗。在這兩種情況下篮愉,只要任何基礎(chǔ)數(shù)據(jù)發(fā)生更改,高速緩存都會失效差导;它永遠(yuǎn)不會返回過時的結(jié)果试躏。
段級別的緩存允許利用緩存,即使某些基礎(chǔ)段是可變的并且正在進(jìn)行實時提取设褐。在這種情況下颠蕴,Druid可能會緩存不可變歷史段的查詢結(jié)果,同時在每個查詢上重新計算實時段的結(jié)果助析。在這種情況下犀被,整個查詢結(jié)果級別的緩存沒有用,因為它會不斷地失效貌笨。
段級緩存確實需要Druid合并每個查詢的每個段結(jié)果弱判,即使它們是從緩存中提供的。因此锥惋,如果不存在由于實時提取而導(dǎo)致的無效問題昌腰,則整個查詢結(jié)果級別的緩存會更加高效。
[1] 使用和設(shè)置緩存
所有緩存都有一對參數(shù)膀跌,它們控制著各個查詢?nèi)绾闻c緩存交互遭商,例如“使用”緩存參數(shù)和“填充”緩存參數(shù)。這些設(shè)置必須通過運(yùn)行時屬性在服務(wù)級別啟用捅伤,以利用緩存劫流,但是可以通過在查詢上下文中進(jìn)行設(shè)置來在每個查詢的基礎(chǔ)上進(jìn)行控制〈砸洌“ use”參數(shù)顯然控制查詢是否將使用緩存的結(jié)果祠汇。“populate”參數(shù)控制查詢是否將更新緩存的結(jié)果熄诡。這些是單獨(dú)的參數(shù)可很,以允許對不常見數(shù)據(jù)的查詢使用緩存的結(jié)果,而不會以其他查詢(例如大報表或非常舊的數(shù)據(jù))不太可能重復(fù)使用的結(jié)果污染緩存凰浮。
[2] broker上的查詢緩存
broker同時支持段級緩存和整個查詢結(jié)果級緩存我抠。段級緩存由useCache和populateCache參數(shù)控制苇本。整個查詢結(jié)果級別的緩存由參數(shù) useResultLevelCache和populateResultLevelCache和運(yùn)行時屬性控制 Druid.broker.cache.*。
與在小型集群的“歷史記錄”上啟用查詢緩存相比菜拓,在Broker上啟用段級緩存可以產(chǎn)生更快的結(jié)果瓣窄。對于較小的生產(chǎn)集群(<5個服務(wù)器),這是推薦的設(shè)置纳鼎。設(shè)置在broker上的段級高速緩存是不推薦用于大型生產(chǎn)集群的俺夕,由于當(dāng)屬性Druid.broker.cache.populateCache被設(shè)置為true(和查詢上下文參數(shù)populateCache不設(shè)置為false),從Historicals查詢每個段的基礎(chǔ)上返回結(jié)果贱鄙,Historicals不會能夠進(jìn)行任何本地結(jié)果合并啥么。這降低了Druid集群的伸縮能力。
[3] 查詢Historicals緩存
歷史記錄僅支持段級緩存贰逾。段級緩存由查詢上下文參數(shù)useCache和populateCache和運(yùn)行時屬性控制 Druid.historical.cache.*。
較大的生產(chǎn)集群應(yīng)僅在歷史記錄上啟用段級緩存設(shè)置(而不在Brokers上啟用)菠秒,以避免必須使用Brokers合并所有查詢結(jié)果疙剑。在“Historicals”而不是“Brokers”上啟用緩存填充,可使“歷史記錄”進(jìn)行自己的本地結(jié)果合并践叠,從而減輕了“Brokers”的負(fù)擔(dān)言缤。
[4] 任務(wù)攝取的緩存
任務(wù)執(zhí)行程序進(jìn)程(例如Peon或?qū)嶒炐訧ndexer)僅支持段級緩存。段級緩存由查詢上下文參數(shù)useCache和populateCache 和運(yùn)行時屬性控制 Druid.realtime.cache.*禁灼。
較大的生產(chǎn)集群應(yīng)僅在任務(wù)執(zhí)行流程上啟用段級緩存填充(而不在Broker上啟用)管挟,以避免必須使用Brokers合并所有查詢結(jié)果。在“Historicals”而不是“Brokers”上啟用緩存填充弄捕,可使“歷史記錄”進(jìn)行自己的本地結(jié)果合并僻孝,從而減輕了“Brokers”的負(fù)擔(dān)。
請注意守谓,任務(wù)執(zhí)行器進(jìn)程僅支持將其數(shù)據(jù)保留在本地的caffeine緩存穿铆,例如緩存。之所以存在此限制斋荞,是因為緩存將結(jié)果存儲在攝取任務(wù)所生成的中間部分片段的級別上荞雏。這些中間部分段在各個任務(wù)副本之間不一定是相同的,因此遠(yuǎn)程高速緩存類型 例如memcached平酿,任務(wù)執(zhí)行程序進(jìn)程將忽略它們凤优。
十五、過濾查詢(Spatial filters)
Druid支持根據(jù)原點(diǎn)和界限來過濾空間索引蜈彼。
在任何數(shù)據(jù)規(guī)范中筑辨,都可以選擇提供空間維度。例如柳刮,對于JSON數(shù)據(jù)規(guī)范挖垛,可以如下指定空間尺寸:
{
"type": "hadoop",
"dataSchema": {
"dataSource": "DatasourceName",
"parser": {
"type": "string",
"parseSpec": {
"format": "json",
"timestampSpec": {
"column": "timestamp",
"format": "auto"
},
"dimensionsSpec": {
"dimensions": [],
"spatialDimensions": [{
"dimName": "coordinates",
"dims": ["lat", "long"]
}]
}
}
}
}
}
空間過濾器
屬性 | 描述 | 必要 |
---|---|---|
dimName | 空間維度名稱痒钝。空間維度可以由多個其他維度構(gòu)成痢毒,也可以作為事件的一部分存在送矩。如果空間維度已經(jīng)存在,則它必須是一個坐標(biāo)值數(shù)組哪替。 | 是 |
dims | 組成空間維度的維度名稱列表栋荸。 | 否 |
空間過濾器語法
"filter" : {
"type": "spatial",
"dimension": "spatialDim",
"bound": {
"type": "rectangular",
"minCoords": [10.0, 20.0],
"maxCoords": [30.0, 40.0]
}
}
綁定類型
-
rectangular
屬性 描述 必要 minCoords 坐標(biāo)[x,y凭舶,z晌块,…]的最小尺寸坐標(biāo)列表 是 maxCoords 坐標(biāo)[x,y帅霜,z匆背,…]的最大尺寸坐標(biāo)列表 是 -
radius
屬性 描述 必要 座標(biāo) 原點(diǎn)坐標(biāo)形式為[x,y身冀,z钝尸,…] 是 半徑 浮點(diǎn)半徑值 是 -
polygon
屬性 描述 必要 橫坐標(biāo) 多邊形角的水平坐標(biāo) 是 縱坐標(biāo) 多邊形角的垂直坐標(biāo) 是