自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

kylin與superset集成實(shí)現(xiàn)數(shù)據(jù)可視化

大數(shù)據(jù) 數(shù)據(jù)可視化
Apache kylin是一個(gè)開源分布式引擎,提供Hadoop之上的SQL查詢接口及多維分析(OLAP)能力以支持超大規(guī)模數(shù)據(jù)。而superset是airbnb開源的一款數(shù)據(jù)可視化工具。

Apache kylin是一個(gè)開源分布式引擎,提供Hadoop之上的SQL查詢接口及多維分析(OLAP)能力以支持超大規(guī)模數(shù)據(jù)。而superset是airbnb開源的一款數(shù)據(jù)可視化工具。

kylin在超大數(shù)據(jù)規(guī)模下仍然可以提供秒級(jí)甚至毫秒級(jí)sql響應(yīng)的OLAP多維分析查詢服務(wù)。而且對(duì)服務(wù)器內(nèi)存的要求也不像spark sql那么高,經(jīng)過多方面的優(yōu)化,數(shù)據(jù)膨脹率甚至可以控制在100%以內(nèi)。它利用hive做預(yù)計(jì)算,然后建立多維的數(shù)據(jù)立方體,并存在hbase中,從而提供了實(shí)時(shí)查詢的能力。

superset也就是早先的caravel,提供了豐富的圖表供用戶配置。只要連上數(shù)據(jù)源,勾幾個(gè)簡(jiǎn)單的配置,或者寫點(diǎn)sql。用戶就可以輕易的構(gòu)建基于d3、nvd3、mapbox-gl等的炫酷圖表。

我廠也是選擇了kylin和superset,遺憾的是superset支持多種數(shù)據(jù)源,包括druid、hive、impala、sparkSQL、presto以及多種主流關(guān)系型數(shù)據(jù)庫(kù),但是并不支持kylin。于是我們對(duì)其進(jìn)行了改進(jìn)。

首先觀察superset的源碼,它后臺(tái)使用Flask App Builder搭建的,數(shù)據(jù)訪問層用sqlalchemy實(shí)現(xiàn)。也就是說,它本質(zhì)上可以支持所有數(shù)據(jù)源,只要實(shí)現(xiàn)一套kylin的dialect即可。而同時(shí)github上有一個(gè)pykylin項(xiàng)目,就是實(shí)現(xiàn)的這個(gè)dialect。這極大增強(qiáng)了我解決這個(gè)問題的信心。

正好前幾周,superset出了一個(gè)新的prod版本airbnb_prod.0.15.5.0。裝好它和pykylin之后,導(dǎo)入kylin數(shù)據(jù)源,成功!

但是點(diǎn)開sqllab想敲點(diǎn)sql驗(yàn)證一下時(shí),卻出了異常。

Debug了pykylin代碼,發(fā)現(xiàn)get_table_names方法的入?yún)onnection實(shí)際已經(jīng)是sqlalchemy的Engine對(duì)象了,這可能是最新sqlalchemy的版本升級(jí)造成的??傊?,將原來的代碼:

  1. def get_table_names(self, connectionschema=None, **kw):  
  2. return connection.connection.list_tables() 

改成:

  1. def get_table_names(self, engine, schema=None, **kw): 
  2. connection = engine.contextual_connect() 
  3. return connection.connection.list_tables() 

即可。

順便我們看到這里它擴(kuò)展了sqlalchemy的list_tables方法,sqllab左上方的table選擇區(qū)還有列出所有schema的下拉框,于是我們順帶把list_schama方法也實(shí)現(xiàn)。connection.py添加:

  1. def list_schemas(self):   
  2.         route = 'tables_and_columns' 
  3.         params = {'project': self.project} 
  4.         tables = self.proxy.get(route, params=params) 
  5.         return [t['table_SCHEM'for t in tables] 

dialect.py添加:

  1. def get_schema_names(self, engine, schema=None, **kw):  
  2. connection = engine.contextual_connect()  
  3. return connection.connection.list_schemas() 

之后執(zhí)行sql還是有錯(cuò):

pykylin在每次調(diào)用kylin的api時(shí)會(huì)首先登錄,以獲得JSESSIONID,并存入cookie中,這里是登錄失敗,檢查代碼,發(fā)現(xiàn)這里問題還挺多的,首先proxy.py中的login方法作者寫的是self.password = user應(yīng)改成password。dialect.py中create_connect_args方法改為:

  1. def create_connect_args(self, url):   
  2.         opts = url.translate_connect_args() 
  3.         api_prefix = 'kylin/api/' 
  4.         args = { 
  5.             'username': opts['username'], 
  6.             'password': opts['password'], 
  7.             'endpoint''http://%s:%s/%s' % (opts['host'], opts['port'], api_prefix) 
  8.         } 
  9.         args.update(url.query) 
  10.         return [], args 

這樣大部分sql查詢沒有問題,但是有的查詢結(jié)果有部分值是null,這樣也會(huì)出錯(cuò)。修改cursor.py的_type_mapped方法:

  1. def _type_mapped(self, result):   
  2.         meta = self.description 
  3.         size = len(meta) 
  4.         for i in range(0, size): 
  5.             column = meta[i] 
  6.             tpe = column[1] 
  7.             val = result[i] 
  8.             if val is None: 
  9.                 pass 
  10.             elif tpe == 'DATE'
  11.                 val = parser.parse(val) 
  12.             elif tpe == 'BIGINT' or tpe == 'INT' or tpe == 'TINYINT'
  13.                 val = int(val) 
  14.             elif tpe == 'DOUBLE' or tpe == 'FLOAT'
  15.                 val = float(val) 
  16.             elif tpe == 'BOOLEAN'
  17.                 val = (val == 'true'
  18.             result[i] = val 
  19.         return result 

這樣在sqllab中執(zhí)行sql基本沒問題了。

下一步開始自定義slice,定制自己的可視化dashboard。

在這里再次遇到問題,superset會(huì)自動(dòng)把count函數(shù)計(jì)算的列設(shè)置別名叫count,而count是kylin的關(guān)鍵字,因此導(dǎo)致查找失敗。修改superset的models.py的sqla_col方法:

  1. @property 
  2.    def sqla_col(self): 
  3.        name = self.metric_name 
  4.        if name == 'count'
  5.            name = 'total_count' 
  6.        return literal_column(self.expression).label(name

另外在slice中還經(jīng)常會(huì)遇到pandas拋出的KeyError異常。這是因?yàn)樵趕uperset里面所有的關(guān)鍵字都是小寫,然而kylin返回的所有的數(shù)據(jù)metadata全是大寫,導(dǎo)致superset在kylin的返回結(jié)果中查詢關(guān)鍵字的時(shí)候出現(xiàn)找不到關(guān)鍵字的錯(cuò)誤。

修改pykylin的cursor.py的execute方法。

  1. def execute(self, operation, parameters={}, acceptPartial=True, limit=None, offset=0):   
  2.         sql = operation % parameters 
  3.         data = { 
  4.             'sql': sql, 
  5.             'offset': offset, 
  6.             'limit': limit or self.connection.limit, 
  7.             'acceptPartial': acceptPartial, 
  8.             'project': self.connection.project 
  9.         } 
  10.         logger.debug("QUERY KYLIN: %s" % sql) 
  11.         resp = self.connection.proxy.post('query', json=data) 
  12.  
  13.         column_metas = resp['columnMetas'
  14.  
  15.         for c in column_metas: 
  16.             c['label'] = str(c['label']).lower() 
  17.             c['name'] = str(c['name']).lower() 
  18.  
  19.         self.description = [ 
  20.             [c['label'], c['columnTypeName'], 
  21.              c['displaySize'], 0, 
  22.              c['precision'], c['scale'], c['isNullable']] 
  23.             for c in column_metas 
  24.         ] 
  25.  
  26.         self.results = [self._type_mapped(r) for r in resp['results']] 
  27.         self.rowcount = len(self.results) 
  28.         self.fetched_rows = 0 
  29.         return self.rowcount 

最后,我發(fā)現(xiàn)在查找的字段包含kylin中的date類型時(shí)也會(huì)出錯(cuò)。點(diǎn)擊slice頁面右上角的query按鈕,可以查看superset最終發(fā)送的sql。

將它直接拷貝到kylin的insight頁面去執(zhí)行,發(fā)現(xiàn)報(bào)錯(cuò)。原來kylin的date類型只支持年月日,而superset在添加日期搜索條件時(shí)為了實(shí)現(xiàn)定時(shí)刷新圖表而在sql的日期條件中都精確到了時(shí)分秒。關(guān)于這個(gè)我原先是在superset中做了修改。

在superset的models.py的get_query_str方法中:

  1. time_filter = dttm_col.get_time_filter(from_dttm, to_dttm) 

改為

  1. if engine.name == 'kylin':   
  2.     time_filter = dttm_col.get_date_filter(from_dttm, to_dttm) 
  3. else:   
  4.     time_filter = dttm_col.get_time_filter(from_dttm, to_dttm) 

添加get_date_filter,dt_sql_literal函數(shù):

  1. def get_date_filter(self, start_dttm, end_dttm):   
  2.         col = self.sqla_col.label('__time'
  3.         return and_( 
  4.             col >= text(self.dt_sql_literal(start_dttm)), 
  5.             col <= text(self.dt_sql_literal(end_dttm)), 
  6.         ) 
  7.  
  8. def dt_sql_literal(self, dttm):   
  9.         return "'{}'".format(dttm.strftime('%Y-%m-%d')) 

這樣對(duì)于所有kylin數(shù)據(jù)源的查找時(shí)間范圍條件都將轉(zhuǎn)為年月日的格式。

不過我一直感覺這個(gè)改動(dòng)不是很完美,是一種典型的打補(bǔ)丁的做法。后來我發(fā)現(xiàn)superset支持在列的設(shè)置頁面為一個(gè)日期列添加自定義的格式轉(zhuǎn)換函數(shù)

于是我在這里設(shè)置日期列格式

  1. TO_DATE(‘{}’, ‘yyyy-MM-dd’) 

然后可以看到slice這里sql中的該列都變成了to_date函數(shù)形式

最后的工作就是修改kylin源碼,添加對(duì)日期函數(shù)的支持。hive sql是支持to_date等日期格式轉(zhuǎn)換函數(shù)的,kylin憑什么不支持?

大致debug了一下kylin的源碼,kylin處理sql的入口在server-base模塊下的QueryController.java的query方法中。我發(fā)現(xiàn)在最終調(diào)用jdbc驅(qū)動(dòng)執(zhí)行sql之前,kylin會(huì)調(diào)QueryUtil類的massageSql方法來優(yōu)化sql。主要是加上limit和offset參數(shù)。最后調(diào)內(nèi)部類DefaultQueryTransformer的transform方法改掉sql中的一些通病,比如SUM(1)改成count(1)等。日期轉(zhuǎn)換函數(shù)的處理放在這后面我覺得是最合適的。

添加正則表達(dá)式,以匹配日期函數(shù):

  1. private static final String TO_DATE = "(to_date|TO_DATE)\\(['|\"]([^'|\"]*)['|\"],\\s?['|\"]([^'|\"]*)['|\"]\\)" 
  2. private static final Pattern FN_TO_DATE = Pattern.compile(TO_DATE); 

添加日期轉(zhuǎn)行函數(shù)解析:

  1. private String executeFN(String sql) {   
  2.             Matcher m; 
  3.             while (true) { 
  4.                 m = FN_TO_DATE.matcher(sql); 
  5.                 if (!m.find()) 
  6.                     break; 
  7.                 String dateTime = m.group(2); 
  8.                 String format = m.group(3); 
  9.                 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
  10.                 Date dt = null
  11.                 try { 
  12.                     dt = sdf.parse(dateTime); 
  13.                 } catch (ParseException e) { 
  14.                     logger.error("Parse date error", e); 
  15.                 } 
  16.                 sdf = new SimpleDateFormat(format); 
  17.                 String date = sdf.format(dt); 
  18.                 String begin = sql.substring(0, m.start()); 
  19.                 String end = sql.substring(m.end(), sql.length()); 
  20.                 sql = begin + "'" + date + "'" + end
  21.             } 
  22.             return sql; 
  23.         } 

然后kylin就可以支持上面sql的執(zhí)行了

最后,讓我們多嘗試一些可視化圖表吧,把它們做成dashboard

結(jié)論:kylin很好地支持了我廠每天上百GB數(shù)據(jù)的立方體建模和實(shí)時(shí)查找,結(jié)合superset的方案,作為我廠內(nèi)部的可視化工具,收到了很好地效果。

責(zé)任編輯:武曉燕 來源: 36大數(shù)據(jù)
相關(guān)推薦

2017-10-14 13:54:26

數(shù)據(jù)可視化數(shù)據(jù)信息可視化

2020-03-11 14:39:26

數(shù)據(jù)可視化地圖可視化地理信息

2018-01-02 11:13:20

數(shù)據(jù)可視化SupersetMetabase

2014-05-28 15:23:55

Rave

2017-02-07 15:54:14

數(shù)據(jù)可視化數(shù)據(jù)分析

2022-09-29 11:16:21

Python數(shù)據(jù)可視化

2018-03-07 11:35:49

Python可視化數(shù)據(jù)

2017-07-12 16:07:49

大數(shù)據(jù)數(shù)據(jù)可視化

2015-08-20 10:00:45

可視化

2021-09-27 08:31:01

數(shù)據(jù)可視化柱狀圖折現(xiàn)圖

2014-08-19 10:47:11

數(shù)據(jù)可視化大數(shù)據(jù)

2020-10-22 08:52:52

Python數(shù)據(jù)集可視化

2012-04-10 15:31:06

HTML 5

2023-11-30 09:34:14

數(shù)據(jù)可視化探索

2017-06-19 08:30:35

大數(shù)據(jù)數(shù)據(jù)可視化報(bào)表

2022-08-26 09:15:58

Python可視化plotly

2017-02-23 09:42:53

大數(shù)據(jù)數(shù)據(jù)可視化技術(shù)誤區(qū)

2023-05-08 16:29:34

2009-04-21 14:26:41

可視化監(jiān)控IT管理摩卡

2022-02-23 09:50:52

PythonEchartspyecharts
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)