易并行聚合算法叽躯,三角選擇原則,近似聚合算法
有些聚合分析的算法肌括,是很容易就可以并行的点骑,比如說max
有些聚合分析的算法,是不好并行的谍夭,比如說黑滴,count(distinct),并不是說紧索,在每個(gè)node上袁辈,直接就出一些distinct value,就可以的珠漂,因?yàn)閿?shù)據(jù)可能會(huì)很多晚缩,假設(shè)圖中的協(xié)調(diào)節(jié)點(diǎn)3百萬個(gè)數(shù)據(jù)去重后還剩下100萬distinct的數(shù)據(jù)尾膊,那么內(nèi)存需要來存儲(chǔ)這100萬條數(shù)據(jù),這是不可能的
es會(huì)采取近似聚合的方式荞彼,就是采用在每個(gè)node上進(jìn)行近估計(jì)的方式冈敛,得到最終的結(jié)論,cuont(distcint)鸣皂,100萬抓谴,1050萬/95萬 --> 5%左右的錯(cuò)誤率
近似估計(jì)后的結(jié)果,不完全準(zhǔn)確寞缝,但是速度會(huì)很快齐邦,一般會(huì)達(dá)到完全精準(zhǔn)的算法的性能的數(shù)十倍
# es,去重第租,cartinality metric措拇,對每個(gè)bucket中的指定的field進(jìn)行去重,取去重后的count慎宾,類似于count(distcint)
GET /tvs/sales/_search
{
"size" : 0,
"aggs" : {
"months" : {
"date_histogram": {
"field": "sold_date",
"interval": "month"
},
"aggs": {
"distinct_colors" : {
"cardinality" : {
"field" : "brand"
}
}
}
}
}
}
precision_threshold優(yōu)化準(zhǔn)確率和內(nèi)存開銷
GET /tvs/sales/_search
{
"size" : 0,
"aggs" : {
"distinct_brand" : {
"cardinality" : {
"field" : "brand",
"precision_threshold" : 100
}
}
}
}
brand去重丐吓,如果brand的unique value,在100個(gè)以內(nèi)趟据,小米券犁,長虹,三星汹碱,TCL粘衬,HTL。咳促。稚新。
在多少個(gè)unique value以內(nèi),cardinality跪腹,幾乎保證100%準(zhǔn)確
cardinality算法褂删,會(huì)占用precision_threshold * 8 byte 內(nèi)存消耗,100 * 8 = 800個(gè)字節(jié)
占用內(nèi)存很小冲茸。屯阀。。而且unique value如果的確在值以內(nèi)轴术,那么可以確保100%準(zhǔn)確
100难衰,數(shù)百萬的unique value,錯(cuò)誤率在5%以內(nèi)
precision_threshold逗栽,值設(shè)置的越大盖袭,占用內(nèi)存越大,1000 * 8 = 8000 / 1000 = 8KB,可以確保更多unique value的場景下苍凛,100%的準(zhǔn)確
field,去重兵志,count醇蝴,這時(shí)候,unique value想罕,10000悠栓,precision_threshold=10000,10000 * 8 = 80000個(gè)byte按价,80KB
doc value正排索引
搜索+聚合 是怎么實(shí)現(xiàn)的惭适?
假設(shè)是倒排索引實(shí)現(xiàn)的
GET /test_index/test_type/_search
{
"query": {
"match": {
"search_field": "test"
}
},
"aggs": {
"group_by_agg_field": {
"terms": {
"field": "agg_field"
}
}
}
}
倒排索引來實(shí)現(xiàn)是非常不現(xiàn)實(shí)的,因?yàn)槲覀兯阉鞯哪莻€(gè)字段search_field 有可能是分詞的楼镐,這就需要去掃描整個(gè)索引才能實(shí)現(xiàn)聚合操作癞志,效率是及其低下的。
正排索引結(jié)構(gòu):
doc2: agg1
doc3: agg2
1萬個(gè)doc --> 搜 -> 可能跟搜索到10000次框产,就搜索完了凄杯,就找到了1萬個(gè)doc的聚合field的所有值了,然后就可以執(zhí)行分組聚合操作了
doc value原理
1秉宿、doc value原理
(1)index-time生成
PUT/POST的時(shí)候戒突,就會(huì)生成doc value數(shù)據(jù),也就是正排索引
(2)核心原理與倒排索引類似
正排索引描睦,也會(huì)寫入磁盤文件中膊存,然后呢,os cache先進(jìn)行緩存忱叭,以提升訪問doc value正排索引的性能
如果os cache內(nèi)存大小不足夠放得下整個(gè)正排索引隔崎,doc value,就會(huì)將doc value的數(shù)據(jù)寫入磁盤文件中
(3)性能問題:給jvm更少內(nèi)存韵丑,64g服務(wù)器仍稀,給jvm最多16g
es官方是建議,es大量是基于os cache來進(jìn)行緩存和提升性能的埂息,不建議用jvm內(nèi)存來進(jìn)行緩存技潘,那樣會(huì)導(dǎo)致一定的gc開銷和oom問題
給jvm更少的內(nèi)存,給os cache更大的內(nèi)存
64g服務(wù)器千康,給jvm最多16g享幽,幾十個(gè)g的內(nèi)存給os cache
os cache可以提升doc value和倒排索引的緩存和查詢效率
2、column壓縮
doc1: 550
doc2: 550
doc3: 500
合并相同值拾弃,550值桩,doc1和doc2都保留一個(gè)550的標(biāo)識(shí)即可
(1)所有值相同豪椿,直接保留單值
(2)少于256個(gè)值携栋,使用table encoding模式:一種壓縮方式
(3)大于256個(gè)值咳秉,看有沒有最大公約數(shù)婉支,有就除以最大公約數(shù),然后保留這個(gè)最大公約數(shù)
重點(diǎn):
對分詞的field澜建,直接執(zhí)行聚合操作向挖,會(huì)報(bào)錯(cuò)炕舵,大概意思是說,你必須要打開fielddata咽筋,然后將正排索引數(shù)據(jù)加載到內(nèi)存中溶推,才可以對分詞的field執(zhí)行聚合操作,而且會(huì)消耗很大的內(nèi)存
先修改 字段的fielddata屬性為true,再查 就能查找到數(shù)據(jù)
POST /test_index/_mapping/test_type
{
"properties": {
"test_field": {
"type": "text",
"fielddata": true
}
}
}
GET /test_index/test_type/_search
{
"size": 0,
"aggs": {
"group_by_test_field": {
"terms": {
"field": "test_field"
}
}
}
}
當(dāng)然奸攻,我們也可以使用內(nèi)置field(keyword)不分詞,對string field進(jìn)行聚合,如果對不分詞的field執(zhí)行聚合操作舞箍,直接就可以執(zhí)行,不需要設(shè)置fieldata=true
GET /test_index/test_type/_search
{
"size": 0,
"aggs": {
"group_by_test_field": {
"terms": {
"field": "test_field.keyword"
}
}
}
}
分詞field+fielddata的工作原理
doc value --> 不分詞的所有field占拍,可以執(zhí)行聚合操作 --> 如果你的某個(gè)field不分詞捎迫,那么在index-time,就會(huì)自動(dòng)生成doc value --> 針對這些不分詞的field執(zhí)行聚合操作的時(shí)候窄绒,自動(dòng)就會(huì)用doc value來執(zhí)行
分詞field,是沒有doc value的蛔翅。位谋。。在index-time掏父,如果某個(gè)field是分詞的,那么是不會(huì)給它建立doc value正排索引的爵政,因?yàn)榉衷~后,占用的空間過于大钾挟,所以默認(rèn)是不支持分詞field進(jìn)行聚合的
分詞field默認(rèn)沒有doc value,所以直接對分詞field執(zhí)行聚合操作处渣,是會(huì)報(bào)錯(cuò)的
對于分詞field蛛砰,必須打開和使用fielddata黍衙,完全存在于純內(nèi)存中。琅翻。。結(jié)構(gòu)和doc value類似聂抢。棠众。。如果是ngram或者是大量term闸拿,那么必將占用大量的內(nèi)存。揽趾。苛骨。
如果一定要對分詞的field執(zhí)行聚合,那么必須將fielddata=true奔缠,然后es就會(huì)在執(zhí)行聚合操作的時(shí)候吼野,現(xiàn)場將field對應(yīng)的數(shù)據(jù),建立一份fielddata正排索引,fielddata正排索引的結(jié)構(gòu)跟doc value是類似的腰奋,
但是只會(huì)講fielddata正排索引加載到內(nèi)存中來抱怔,然后基于內(nèi)存中的fielddata正排索引執(zhí)行分詞field的聚合操作
如果直接對分詞field執(zhí)行聚合,報(bào)錯(cuò)屈留,才會(huì)讓我們開啟fielddata=true灌危,告訴我們,會(huì)將fielddata uninverted index勇蝙,正排索引,加載到內(nèi)存产雹,會(huì)耗費(fèi)內(nèi)存空間
為什么fielddata必須在內(nèi)存翁锡?因?yàn)榇蠹易约核伎家幌拢衷~的字符串馆衔,需要按照term進(jìn)行聚合,需要執(zhí)行更加復(fù)雜的算法和操作荒适,如果基于磁盤和os cache开镣,那么性能會(huì)很差
我們是不是可以預(yù)先生成加載fielddata到內(nèi)存中來?陕壹?树埠?
query-time的fielddata生成和加載到內(nèi)存,變?yōu)閕ndex-time怎憋,建立倒排索引的時(shí)候九昧,會(huì)同步生成fielddata并且加載到內(nèi)存中來毕匀,這樣的話皂岔,對分詞field的聚合性能當(dāng)然會(huì)大幅度增強(qiáng)
POST /test_index/_mapping/test_type
{
"properties": {
"test_field": {
"type": "string",
"fielddata": {
"loading" : "eager"
}
}
}
}