.net函数查询_特来电智能分析平台动态查询架构创新实践
一、業務背景及痛點
?目前主流互聯網智能分析平臺中,數據查詢作為基礎的設施服務支撐著基礎數據及業務分析的功能展現。隨著數據量的增長,數據存儲方式多元化,相對靜態數據可能存儲到關系型數據庫中,訂單類動態數據可能存儲到ElasticSearch、Greenplum數據庫中,實時類數據可能存儲到Druid、Redis中,每種數據庫都有各自的優勢及局限。
傳統的數據服務實現面臨很多需求、技術挑戰,存在諸多痛點,數據查詢需要從多個、多種數據庫中讀取數據進行邏輯處理,過程中存在必不可少的篩選、遍歷、關聯、合并、拼接、轉換等處理,代碼實現一般采用ORM組件把從數據庫中查詢的數據反射為強類型的對象列表,然后使用LINQ進行對象列表的查詢處理,實現過程邏輯比較繁瑣,并且類似的業務數據在各個產品應用中不可避免的存在重復冗余的處理代碼,當業務需求發生變動后需要修改代碼并重新部署文件,而且數據量比較大時可能存在性能上的問題,這樣的軟件產品可維護性、靈活性、通用性、拓展性、開發效率上比較差。
為解決以上痛點,提升開發效率、降低維護成本以及提高系統響應及時性,針對這類查詢業務,特來電云平臺數據分析BI組設計實現了通用數據查詢服務平臺,通過簡單的查詢配置即可從多種、多個數據庫中拉取數據,并根據配置進行相關業務數據的篩選聯查拼接等處理,開發、部署簡單輕量,當業務發生變化時無需編碼調整,可以快速應對需求的變更。平臺實現使用C# DataTable的DataColumn.Expression表達式、DataSet的DataRelation提升了數據處理的靈活性及通用性,使用微軟開源的.Net下的Javascript腳本引擎ClearScript降低查詢條件轉換、計算字段等業務的復雜度及耦合度。
二、平臺架構整體實現
1.???查詢請求請求信息中要有該查詢的內碼或編碼,同時需要有本次查詢的參數信息,前端傳入單層結構的json對象,后臺可轉為Dictionary,這樣參數信息的數據結構拓展性比較好些。2.???配置讀取、校驗查詢的配置包括查詢信息、數據源信息、參數轉換信息、結果字段信息、參數轉換函數信息,配置信息設計維護時存儲到Sql Server,運行時從Redis或進程內存中讀取,采用定時、實時更新機制。查詢配置的數據結構如下:3.???參數轉換查詢的參數最終需要附加到查詢SQL或結果上,報表分析、Grafana等查詢分析界面傳入的參數格式各異,例如開始時間,查詢的參數值可能是yyyyMMdd格式,如果從ES查詢的話需要轉為yyyy-MM-dd并附加+08:00,從Sql Server不需要轉換,等等情況,參數的轉換需要有非常靈活的機制,強識別并不明智,使用JavaScript引擎ClearScript非常完美的達到目的。4.???數據組合數據的讀取原則上采用執行SQL語句方式,SQL字符串語句方式比較靈活通用,轉換后的參數、分頁、排序最終轉換為SQL片段附加到要執行的SQL語句上,根據數據源類型采用工廠模式實現參數轉換、數據讀取,目前可以從Sql Server、ES、Druid數據庫中拉取數據,后繼可再添加其它數據庫類型的支持類。5.???字段計算處理過程主要是如何把查詢字段附加到主數據源表,字段可能是直接取值、Column表達式、JavaScirpt表達式,最后進行數據結構轉換,并根據查詢結果結構返回。6.???轉換處理數據返回前要根據查詢設置需要的數據結構進行轉換,例如返回結果類似于強類型數據結構,不經轉換DataTable無法滿足要求,另外如果主數據源為ES,可能沒有任何行的情況下返回的數據為空,不滿足前臺使用要求,等等情況下有必要進行一次DataTable轉List>,然后再處理為查詢配置要求的數據結構類型。三、關鍵技術亮點
1.???巧用JavaScript引擎動態語言特性,實現動態配置軟件實現平臺化時需要整合同類邏輯處理為通用的實現過程,例如查詢服務的參數處理,把入參處理為可執行的SQL片段,業務要求非常簡單,但是邏輯處理情況非常多,整合過程中對業務的強識別并不明智,有時候強識別也不現實,該類邏輯處理一般都有相似的輸入及輸出,我們可以把業務處理過程寫到一個字符串然后能動態執行后返回想要的結果,例如我們通常會用SQL來編寫一些數據庫對象如:存儲過程、觸發器之類的對象,這些對象通過腳本來描述然后被解析成一個個實實在在的可執行體,這些可執行體是通過一系列預處理、詞法分析、語法分析等編譯環節最終形成可執行體,當我們使用的時候能快速的進行調用,這樣大大增加了我們的運行效率及軟件實現的通用性及靈活性。c#是靜態語言,編譯后才可以使用,所以首先想到的是動態編譯生成dll文件后反射調用,但是不能每次調用都進行動態編譯,需要進行規則判斷,而且第一次調用編譯時耗時較長,性能上也達不到要求,易用性、靈活性、可維護性上也差強人意,動態字符串的執行JavaScript有一個Eval函數可以實現,c#也可以動態執行腳本語言,這樣我們可以編寫易讀性、靈活性強的腳本代碼實現不可預測的邏輯處理,然后使用ClearScript? JavaScript引擎執行腳本動態字符串達到我們的目的。ClearScript引擎可以將腳本功能添加到 .NET 應用程序(.NET Framework 4 或更高版本),ClearScript 支持 VBScript、JavaScript 和 V8。V8 是由 Google 創建的開源JavaScript 引擎,并且與 Chrome 集成。V8 是高性能的 JavaScript 引擎,且非常適用于多線程和異步操作處理。ClearScript將 JavaScript 或 VBScript 表達式傳遞到引擎,而且并不只是可以使用純腳本對象,如數組、JSON 對象和基元類型,同時可以集成外部JavaScript 庫和腳本托管的c#類庫。使用ClearScript時可以先從NuGet安裝包查找添加引用,簡單的調用示例如下:using Microsoft.ClearScript.JavaScript;object result =null;using (var engine = new JScriptEngine( )){ result = engine.Execute(@"var a = 3; var b = 5; function add(a, b) { return a + b; } return add(a, b);");}性能測試如下:ClearScript可以集成外部腳本托管的c#對象,測試代碼如下:using ( var engine = new JScriptEngine( ) ){ //添加主機的模式,以便js可以調用主機這邊的c#Console函數 engine.AddHostType( "Console" ,typeof( Console ) ); engine.Execute("Console.WriteLine('{0} is an interesting number.', Math.PI)" ); //添加主機的模式,以便js可以調用主機這邊的c#random函數 engine.AddHostObject( "random", new Random( ) ); engine.Execute("Console.WriteLine(random.NextDouble())" ); //添加主機的模式,以便js可以調用主機這邊的c#System.Core類庫 engine.AddHostObject( "lib" ,new HostTypeCollection( "mscorlib" , "System.Core" ) ); engine.Execute("Console.WriteLine(lib.System.DateTime.Now)" ); //創建C#時間對象 engine.Execute( @" birthday = newlib.System.DateTime(2007, 5, 22); Console.WriteLine(birthday.ToLongDateString()); " ); //創建Dictionary對象 engine.Execute( @" Dictionary =lib.System.Collections.Generic.Dictionary; dict = new Dictionary(lib.System.String,lib.System.Int32); dict.Add('foo', 123); " );}可見無論靈活性、可用性、性能上ClearScript都非常理想,參數轉換動態執行以及特殊字段處理我們可以引入到數據查詢平臺中使用。2.???舊瓶裝新酒,重用DataColumn.Expression數據庫存儲設計一般只是對基礎字段進行存儲,對于動態計算后的字段需要業務代碼邏輯實現,例如用戶信息存儲中只是存儲用戶的出生日期,并不會存儲用戶年齡,如果界面要顯示用戶的年齡,需要后臺根據當前時間計算,當然關系型數據庫可用直接查詢,但是其它類型數據庫未必支持,更為復雜的業務邏輯可能數據庫SQL也不一定能編寫實現,假設需要我們后臺邏輯處理,一般的處理邏輯是執行SQL返回DataTable或ORM組件后的List<強類型>,然后DataTable添加需要的業務列,遍歷每一行計算賦值,或者遍歷List<強類型>計算賦值,這樣實現后假設業務列的計算規則調整,需要我們重新編譯代碼,然后重新部署,靈活性、可維護性非常差,而且當數據量超出一定數值后性能上也比較差, CPU占用比較高。ORM架構有其優點也存在缺點,數據庫的數據到內存首先基本都是DataSet,數據處理前的數據類型我們建議還是使用DataTable,對于計算列的處理我們采用DataColumn.Expression方式,我們可以設置計算列的表達式實現復雜的業務邏輯處理,該方式可以整列計算或者關聯計算,而非行遍歷處理,靈活性、可維護性、性能上非常理想。DataColumn.Expression表達式功能非常強大,除一般的計算表達式、一對多、多對一父子級關系外還支持聚合、函數等實用性非常強的功能。計算表達式:DataTable dtMain = new DataTable( );dtMain.Columns.Add( "price" ,typeof( double ) );dtMain.Rows.Add( "30");dtMain.Rows.Add( "90");dtMain.Columns.Add( "tax" ,typeof( double ) , "price * 0.0862" );dtMain.Columns.Add( "total" ,typeof( double ) , "price + tax" );父/子關系引用在表達式中,可以通過使用 Parent追加列名稱來引用父表。例如,Parent.Price 引用名為 Price的父表的列。當子級具有多個父行時,請使用Parent (RelationName)。ColumnName. 例如,Parent (RelationName)。價格通過關系引用名為Price 的父表的列。通過使用 Child追加列名稱,可以在表達式中引用子表中的列。但是,由于子關系可能返回多行,因此必須在聚合函數中包含對子列的引用。 例如,Sum(Child.Price) 將返回子表中名為 Price 的列的總和。如果表具有多個子元素,則語法為:Child(RelationName)。3.???內存關系型數據處理的利器:DataSet. Relations有時候我們需要的結果需要匯總多個數據源并聯查合并后才能得出,一般的處理方式還是遍歷、篩選取值計算,這種處理方式不可取,一般從數據庫中讀取的第一數據類型是DataSet,然后我們取第一個表DataTable進行數據處理,對于DataSet我們很少利用它的特性,DataSet是從數據源檢索的數據的內存中緩存,是ADO.NET 體系結構的主要組件。DataSet 包含 DataTable 對象的集合,這些對象可以與 DataRelation 對象相關聯,也就是DataSet相當于是內存中的關系型數據庫,我們可以利用這個特性,定義數據關聯表達式,動態添加DataRelation,配合DataColumn.Expression實現非常通用、靈活高性能的數據關聯、篩選補充計算邏輯操作。四、?案例應用
1.? Web API數據查詢服務平臺提供了Web API服務,服務的創建只需要進行簡單的配置即可提供相關業務的Web服務,部署只需要執行配置SQL即可,目前已支持近20多個服務接口,支持特來電運維電站詳情、用戶詳情、訂單詳情、電站實時監控等業務功能。2. 報表開發?????? 查詢服務已作為報表開發平臺的一種數據源提供數據支持,對于業務不是非常復雜的報表實現了零編碼的在線開發。【查詢數據配置】【查詢配置數據源】【在線設計數據源信息】3.? Grafana數據分析Grafana作為數據分析開發工具集成了查詢服務,對于簡單設置無法實現的業務數據,通過查詢服務配置即可實現,并且支持聯查類功能數據。五、帶來的價值和提升
動態數據查詢服務在特來電監控分析產品應用以及報表開發平臺中已經大量應用,報表開發平臺中集成查詢服務作為數據源后不必再配置sql.map和編寫dll文件,實現了真正的零編碼報表開發,開發效率有了很大提升,大數據分析平臺grafana配置界面也作為數據源集成了該服務,單一配置方式無法滿足的數據業務,通過查詢服務配置得到了實現,不必再編寫部署Web API服務。采用配置化的動態查詢平臺架構,大大提升了開發、部署效率以及需求響應速度,可維護性、性能上也有很大提升,目前該服務平臺訪問量TPS比較高,服務穩定、可靠,表現良好。六、規劃和展望
目前該查詢服務平臺只支持多個數據集的關聯計算,后期規劃支持去重、合并、自定義處理等功能,并且支持Redis、HBase等數據庫中讀取數據,最終打造成零編碼的數據查詢統一平臺。總結
以上是生活随笔為你收集整理的.net函数查询_特来电智能分析平台动态查询架构创新实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: windows华硕主板如何开启vt虚拟化
- 下一篇: 如何在python中使用logbook日