摘? 要:機票售后系統(tǒng)中費用的計算與航空公司銷售策略緊密結(jié)合,業(yè)務(wù)相對穩(wěn)定,規(guī)則調(diào)整頻繁,規(guī)則數(shù)量逐年增大,管理和維護比較困難。結(jié)合系統(tǒng)原始規(guī)則運算機制,參考主流的Drools規(guī)則引擎特點,重新設(shè)計了適合業(yè)務(wù)要求的機票售后管理引擎。系統(tǒng)通過規(guī)則元數(shù)據(jù)的配置,樹形結(jié)構(gòu)的規(guī)則存儲,結(jié)合規(guī)則執(zhí)行流程,利用JVM對Groovy代碼的支持得以實現(xiàn)。該系統(tǒng)實現(xiàn)了方便、高效、靈活的機票售后業(yè)務(wù)更新,降低了售后規(guī)則管理難度,提高了工作效能。
關(guān)鍵詞:機票售后管理;規(guī)則引擎;信息系統(tǒng)
中圖分類號:TP311.5? ? ? 文獻標(biāo)識碼:A 文章編號:2096-4706(2020)05-0008-04
Design of Air Tickets After-sales System Based on Rule Engine
HUANG Liefu
(Shanghai Qianshan Network Technology Development Co.,Ltd.,Shanghai? 201203,China)
Abstract:The calculation of the cost in the civil aviation after-sales system is closely combined with sales strategy of the airline companies. The business is relatively stable,the rules are adjusted frequently,the number of rules is increased year by year,so that the management and maintenance of the rules are difficult. This paper redesigns the management engine suitable for the business requirements of the airline companies,combining the original rule mechanism of the system,refering to characteristics of the popular rule engine Drools. The redesigned air ticket after-sales management engine is suitable for the business requirements. Through the configuration of rule metadata,the rule storage of tree structure,and the rule execution process,the system uses the JVM to support Groovy code. The system realizes convenient,efficient and flexible after-sales business update of air tickets,reduces the difficulty of after-sales rule management,and improves work efficiency.
Keywords:after-sales management of air ticket;rule engine;information system
0? 引? 言
民航機票系統(tǒng)中,退票和改票是核心售后系統(tǒng),其重要功能包括計算機票退、改服務(wù)的稅費。影響稅費的因素很多[1],包括客票艙位等級、客票購買價格、客票購買時間、客票是否部分使用、客票是否超期、改后客票價格、旅客級別等。為了實現(xiàn)業(yè)務(wù)計算功能,在商業(yè)數(shù)據(jù)庫大量使用后已經(jīng)不再使用通過大量if-else形式的傳統(tǒng)硬編碼做法。一般是根據(jù)實際業(yè)務(wù)情況,將影響因子抽象為規(guī)則表,計算時將存儲在數(shù)據(jù)庫表的規(guī)則和實際參數(shù)進行計算比對。這種方式實現(xiàn)難度較小,有一定的業(yè)務(wù)靈活性,適用于規(guī)則變化小、變動頻次低的情況。該方法規(guī)則展示不夠靈活,對業(yè)務(wù)人員不友好,新業(yè)務(wù)開發(fā)成本高。目前民航業(yè)競爭日益激烈,航空公司的商業(yè)策略調(diào)整愈加頻繁,規(guī)則也越來越復(fù)雜,每次調(diào)整的難度越來越大。一方面,隨著商業(yè)規(guī)則的增多,要考慮到調(diào)整后的規(guī)則與之前規(guī)則的兼容性;另一方面,每次調(diào)整帶來的應(yīng)用修改成本也越來越高。為了提高部門整體效能、提高需求實現(xiàn)效率、減少開發(fā)成本、提高開發(fā)者技能,需要引入規(guī)則引擎[2]?;谝?guī)則引擎的機票售后系統(tǒng)的設(shè)計成為系統(tǒng)建設(shè)的方向,可以為航空公司業(yè)務(wù)人員提供友好的規(guī)則配置界面,幫助業(yè)務(wù)人員快速、清晰地配置售后業(yè)務(wù)規(guī)則,并將業(yè)務(wù)規(guī)則與應(yīng)用系統(tǒng)代碼分離,實現(xiàn)了規(guī)則計算和其他業(yè)務(wù)的解構(gòu)。
1? 規(guī)則引擎原理
規(guī)則引擎要解決一類如圖1所示的大量if-else結(jié)構(gòu)分支的問題,一組完整的條件定義和功能處理稱為一個規(guī)則庫或者知識庫。
條件定義一般又稱為左手部分(left hand side,LHS)或者模式部分,功能處理一般又稱為右手部分(right hand side,RHS)或者執(zhí)行邏輯。具體實現(xiàn)還需要事實集(fact set),包括需要計算的系統(tǒng)入?yún)ⅰh(huán)境變量以及一些中間計算結(jié)果等。規(guī)則引擎的模塊結(jié)構(gòu)設(shè)計如圖2所示,計算引擎操作事實集的數(shù)據(jù),同時從知識庫讀入規(guī)則以及相關(guān)的數(shù)據(jù),然后對規(guī)則模式和事實進行計算,匹配成功后,將結(jié)果輸出到結(jié)果集或者議程,最后解決結(jié)果集中的沖突,得到最終結(jié)果[3]。
當(dāng)業(yè)務(wù)計算的事實實例數(shù)量增多,需要多個事實同時滿足業(yè)務(wù)需求,且存在多個沖突結(jié)論時,需要引入推理機。推理機最典型的Rete算法,是一種高效的推理算法,它實現(xiàn)了前向推理計算的功能[4]。Rete算法將知識庫構(gòu)建成一個規(guī)則網(wǎng)絡(luò),網(wǎng)絡(luò)中包括根節(jié)點、類型節(jié)點、α節(jié)點、β節(jié)點和終端節(jié)點,其構(gòu)建過程保證了相同規(guī)則的節(jié)點不重復(fù),節(jié)約了空間。類型節(jié)點用于將事實進行分類,引導(dǎo)事實進入對應(yīng)的α節(jié)點;α節(jié)點通過固定的模式匹配,過濾部分事實,提高網(wǎng)絡(luò)匹配效率;β節(jié)點用于匹配事實與事實的關(guān)系,并保存中間事實結(jié)果,是推理的重要步驟。事實集從規(guī)則網(wǎng)絡(luò)的根節(jié)點沿著有向路徑進行匹配,直到所有的事實匹配到終端節(jié)點,終端節(jié)點數(shù)據(jù)進入議程,消除議程中的所有沖突后得到最終結(jié)果。
2? 系統(tǒng)技術(shù)選擇評估
系統(tǒng)的首選方案本來是業(yè)界著名的產(chǎn)品Drools,它是在優(yōu)化后的Rete算法基礎(chǔ)上實現(xiàn)的,能夠很好地將規(guī)則從業(yè)務(wù)中分離解耦,在各行業(yè)有廣泛的應(yīng)用[5]。Drools技術(shù)應(yīng)用流程如下:工程師根據(jù)業(yè)務(wù)員提交的需求,編寫DSL規(guī)則并發(fā)布到規(guī)則庫,Drools引擎讀取規(guī)則后計算用戶輸入的事實,最終匹配規(guī)則并計算結(jié)果。但是,Drools使用了腳本語言作為DSL規(guī)則,學(xué)習(xí)成本高,配置工作必須由軟件研發(fā)工程師來完成;當(dāng)規(guī)則數(shù)量變多之后,規(guī)則的維護很困難,管理難度較高;Drools對嵌套規(guī)則不友好,實現(xiàn)較復(fù)雜業(yè)務(wù)時有局限性。最終,自建引擎而非Drools成為系統(tǒng)建設(shè)的技術(shù)選擇。
自建的規(guī)則引擎需要適合民航業(yè)務(wù)特別是機票售后業(yè)務(wù)。從民航業(yè)務(wù)形態(tài)分析,每一筆售后業(yè)務(wù)數(shù)據(jù)的計算,與其他的業(yè)務(wù)數(shù)據(jù)不產(chǎn)生耦合,從今后的業(yè)務(wù)數(shù)據(jù)量發(fā)展來看,業(yè)務(wù)壓力增長較快,規(guī)則引擎模型的建立主要考慮規(guī)則配置的靈活性以及規(guī)則運行的高效性。Rete算法在業(yè)內(nèi)被眾多研究者改進,比如對空間、網(wǎng)絡(luò)方面的改造和優(yōu)化[6],但是機票售后計算業(yè)務(wù)暫不需要使用Rete算法的核心機制即推理機。考慮到Rete算法實現(xiàn)相對復(fù)雜,后續(xù)維護的成本風(fēng)險較高,故沒有采用該算法。
業(yè)務(wù)要求規(guī)則具備編輯后即時生效的能力,即動態(tài)加載和編譯的能力。目前業(yè)界的Groovy、Janino、Aviator等腳本化的方案都可以實現(xiàn)。鑒于Groovy語法完備,編譯后可直接在JVM上運行,執(zhí)行效率高,技術(shù)成熟,并且可以在運行時動態(tài)加載和卸載,因此將其作為引擎規(guī)則的基礎(chǔ)表述語言。
3? 系統(tǒng)設(shè)計原理
3.1? 計算單元
系統(tǒng)將規(guī)則定義為計算單元的組合。在圖1所示的規(guī)則中,condition和function都是計算單元,condition是結(jié)果為布爾值的計算單元,function是返回值可以是任何類型的計算單元。計算單元內(nèi)部可以調(diào)用其他的計算單元,甚至嵌套其他規(guī)則。普通的計算單元可以返回數(shù)據(jù),也可以設(shè)置復(fù)雜入?yún)⒌闹?,既不返回?shù)據(jù)又不設(shè)置復(fù)雜入?yún)⒅档挠嬎銌卧遣缓戏ǖ?。為了表達邏輯條件判斷,系統(tǒng)提供如表1所示的操作符。
3.2? 規(guī)則元數(shù)據(jù)
規(guī)則元數(shù)據(jù)分為基礎(chǔ)常量數(shù)據(jù)、復(fù)雜數(shù)據(jù)結(jié)構(gòu)以及函數(shù)定義。復(fù)雜數(shù)據(jù)結(jié)構(gòu)是由簡單數(shù)據(jù)結(jié)構(gòu)和其他復(fù)雜數(shù)據(jù)結(jié)構(gòu)構(gòu)成。函數(shù)定義則是手動填寫函數(shù)代碼,函數(shù)依賴于基礎(chǔ)常量數(shù)據(jù)和復(fù)雜數(shù)據(jù)結(jié)構(gòu)。計算單元可以是一個簡單或者復(fù)雜類型的值,也可以是一個最終轉(zhuǎn)化為函數(shù)的表達式。其中,除簡單類型的值以外,其他的計算單元都依賴規(guī)則元數(shù)據(jù)或其他計算單元。復(fù)雜數(shù)據(jù)結(jié)構(gòu)在業(yè)務(wù)層被依賴,可以被規(guī)則中的函數(shù)方法使用。本系統(tǒng)常用的復(fù)雜數(shù)據(jù)結(jié)構(gòu)的規(guī)則元數(shù)據(jù)包括用戶信息、航班信息、價格信息、稅費信息、座位信息、支付信息、商品信息等,這些元數(shù)據(jù)都會在規(guī)則定義的時候被依賴,在規(guī)則執(zhí)行的時候被使用。
3.3? 業(yè)務(wù)規(guī)則組
圖1中描述的一組規(guī)則,通常將一個condition及其對應(yīng)的function定義為一個規(guī)則,圖1中的所有分支共同處理同一個業(yè)務(wù),是一個知識庫,本系統(tǒng)定義為業(yè)務(wù)規(guī)則組。規(guī)則間的關(guān)系根據(jù)不同的業(yè)務(wù)要求會有不同的處理方案,即規(guī)則沖突策略。根據(jù)民航售后業(yè)務(wù)特點,本系統(tǒng)參考權(quán)重處理的方法[7],將業(yè)務(wù)規(guī)則組中規(guī)則間的關(guān)系確定為互斥關(guān)系,當(dāng)滿足一個條件并執(zhí)行對應(yīng)的操作之后直接返回結(jié)果,即條件按照優(yōu)先級權(quán)重進行排序,優(yōu)先級高的策略優(yōu)先計算匹配,匹配成功則完成功能處理。
根據(jù)上述規(guī)則處理策略,將完整的業(yè)務(wù)規(guī)則組存儲為1棵樹(如圖3所示),根節(jié)點表示業(yè)務(wù)邏輯的起點;兄弟節(jié)點表示為多重條件判斷if-else的關(guān)系,父子節(jié)點表示為條件判斷邏輯“并且”關(guān)系,葉子節(jié)點表示滿足條件后的function。規(guī)則條件之間如果有“或者”關(guān)系,則按照else-if的方式來處理。中間節(jié)點必須有子節(jié)點存在,中間節(jié)點的兄弟節(jié)點不能是葉子節(jié)點,葉子節(jié)點沒有兄弟節(jié)點。圖3展示了某航空公司國內(nèi)航班機票改期收費的簡化規(guī)則的存儲結(jié)構(gòu)圖,旅客航班改期時,改期收費的業(yè)務(wù)條件匹配是從根節(jié)點開始,按順序逐步進入下一層節(jié)點,最終匹配到某一個葉子節(jié)點,計算得到改期費額。該規(guī)則中,因為銷售日期決定了售后規(guī)則的版本,故最新銷售策略的規(guī)則按照日期存放在第一級中間節(jié)點,且最新規(guī)則的優(yōu)先級最高,這樣保證了規(guī)則匹配的命中率。
3.4? 規(guī)則執(zhí)行流程
單個業(yè)務(wù)規(guī)則組的單次執(zhí)行,無法保證實際業(yè)務(wù)處理的完整性,系統(tǒng)參考Drools的規(guī)則流[8],引入了規(guī)則流程塊。結(jié)合業(yè)務(wù)的實際處理情況,系統(tǒng)設(shè)計了順序塊、分支塊和循環(huán)塊3種流程塊,它們分別支持業(yè)務(wù)的順序、分支、循環(huán)執(zhí)行邏輯。業(yè)務(wù)規(guī)則組被封裝到流程塊中,業(yè)務(wù)流程通過這3種流程塊組織起來,配合完成完整的業(yè)務(wù)功能,其存儲結(jié)構(gòu)如圖4的(a)(b)(c)部分所示。其中分支模塊在實際存儲過程中,根據(jù)實際分支的數(shù)量建立多個分支節(jié)點,每個分支節(jié)點存儲滿足分支條件的業(yè)務(wù)規(guī)則組,每個分支節(jié)點都會有2個出口指針。其中true指針指向判斷成功并執(zhí)行本規(guī)則功能后的下一個業(yè)務(wù)流程塊,所有true指針都指向同一個業(yè)務(wù)流程塊;false指針指向判斷失敗后的下一個分支流程塊,最后一個分支塊的false指針是空。圖4的(d)部分展示了航空公司在使用該規(guī)則引擎時規(guī)則執(zhí)行流程的存儲結(jié)構(gòu),退票計算需要分別完成對用戶的航段費用、稅收扣減、座位扣減等計算功能,這些功能都在各自的業(yè)務(wù)規(guī)則組下完成計算,每個規(guī)則組在循環(huán)塊的控制下,對一組各自獨立的事實參數(shù)進行計算,最后得到完整的退票數(shù)據(jù)明細和結(jié)果。
3.5? 規(guī)則翻譯
規(guī)則保存完畢后,系統(tǒng)通過規(guī)則翻譯模塊,將圖3所示的樹形結(jié)構(gòu)翻譯為Groovy語言的業(yè)務(wù)函數(shù)代碼。模塊首先讀入根節(jié)點,獲取規(guī)則基本信息,比如包名、業(yè)務(wù)名稱、參數(shù)類型、返回類型等,然后通過深度遍歷方法,讀取每個節(jié)點,將分支第一個中間子節(jié)點翻譯為if(c),將其余中間子節(jié)點翻譯為else if(c),將每個節(jié)點的后代翻譯為處理執(zhí)行部分{…},將葉子節(jié)點翻譯為配置的業(yè)務(wù)計算單元。函數(shù)可能是規(guī)則元數(shù)據(jù)中定義的函數(shù),也可能是匿名函數(shù),還可能是其他業(yè)務(wù)規(guī)則。業(yè)務(wù)人員使用時會根據(jù)業(yè)務(wù)特征,將發(fā)生概率高的規(guī)則模式配置在前面,保證業(yè)務(wù)執(zhí)行效率,規(guī)則樹會保存規(guī)則的優(yōu)先級特征,翻譯時兄弟節(jié)點按照優(yōu)先順序被讀取、構(gòu)建,保證了代碼構(gòu)建的順序,深度遍歷簡化了Groovy代碼的生成。
如圖4存儲的規(guī)則執(zhí)行流程,也會被翻譯為Groovy函數(shù),順序模塊直接翻譯為調(diào)用將其封裝的業(yè)務(wù)規(guī)則組的代碼函數(shù);一組分支模塊會實現(xiàn)為if-else if的代碼,并在執(zhí)行部分調(diào)用業(yè)務(wù)規(guī)則組的代碼函數(shù),當(dāng)分支模塊的false出口指針為空時,表示分支結(jié)束;循環(huán)模塊會根據(jù)配置的循環(huán)條件,建立for循環(huán)的代碼。業(yè)務(wù)請求是從規(guī)則執(zhí)行流程總?cè)肟陂_始的,逐塊執(zhí)行每個流程塊里封裝的業(yè)務(wù)規(guī)則組代碼,最終完成完整的業(yè)務(wù)功能。
3.6? 規(guī)則管理引擎整體執(zhí)行流程
規(guī)則管理引擎的具體執(zhí)行流程如圖5所示,圖中細箭頭為規(guī)則數(shù)據(jù)流動的方向,粗箭頭為規(guī)則處理步驟的方向。業(yè)務(wù)人員根據(jù)業(yè)務(wù)需求在規(guī)則配置模塊管理規(guī)則庫,包括定義規(guī)則元數(shù)據(jù)、展示業(yè)務(wù)規(guī)則組和規(guī)則樹、編輯規(guī)則內(nèi)容、保存規(guī)則歷史、定義業(yè)務(wù)的規(guī)則執(zhí)行流程。翻譯驗證模塊,用于規(guī)則的自動翻譯和測試驗證,將規(guī)則庫中的業(yè)務(wù)規(guī)則組和規(guī)則執(zhí)行流程翻譯為Groovy語言代碼,并經(jīng)過產(chǎn)品業(yè)務(wù)人員的加載測試,確定規(guī)則配置的正確性,業(yè)務(wù)員確認通過后的規(guī)則才能進入后續(xù)的發(fā)布狀態(tài)。版本發(fā)布模塊管理各規(guī)則的歷史版本,并幫助發(fā)布各版本規(guī)則,將指定的規(guī)則版本發(fā)布到指定的規(guī)則執(zhí)行模塊和運行規(guī)則庫中;因各種原因需要撤回已經(jīng)發(fā)布的規(guī)則版本,也由本模塊負責(zé)處理,將需要的歷史版本重新推送,更新到執(zhí)行模塊和運行規(guī)則庫,并將撤回的規(guī)則版本下架,下架后的規(guī)則必須經(jīng)過重新翻譯和驗證才能再次發(fā)布。規(guī)則執(zhí)行模塊是規(guī)則引擎的主體部分,模塊在啟動時從運行規(guī)則庫中讀取翻譯成Groovy的規(guī)則代碼,當(dāng)有通知發(fā)布時,接受來自發(fā)布模塊的請求并更新加載模塊內(nèi)的規(guī)則;執(zhí)行模塊內(nèi)部結(jié)構(gòu)如圖2所示,當(dāng)業(yè)務(wù)請求進入時,引擎讀入事實,生成上下文,并執(zhí)行業(yè)務(wù)規(guī)則流程,得到最后的計算結(jié)果。
4? 系統(tǒng)優(yōu)勢和后續(xù)工作
目前,系統(tǒng)能方便快捷地適應(yīng)民航在線機票退改業(yè)務(wù)快速變更的需求,以及其他非推理領(lǐng)域的大量在線業(yè)務(wù)場景。通過實際生產(chǎn)數(shù)據(jù)的實驗比對,本系統(tǒng)運行效率遠高于Drools。通過樹形結(jié)構(gòu)的頁面規(guī)則配置,能夠方便業(yè)務(wù)人員對業(yè)務(wù)規(guī)則的管理,降低規(guī)則配置的難度,減小錯誤配置的概率;規(guī)則通過計算單元的引入,方便在規(guī)則執(zhí)行中嵌套規(guī)則;通過Groovy代碼翻譯,能夠高效地在JVM平臺上運行;通過規(guī)則驗證和版本控制,支持了在線業(yè)務(wù)的安全投產(chǎn)。
本系統(tǒng)在規(guī)則翻譯、驗證、發(fā)布方面是基于優(yōu)先級控制的樹形結(jié)構(gòu)的規(guī)則集實現(xiàn)的,系統(tǒng)在這三方面留有規(guī)則沖突的策略接口,便于后續(xù)擴展;規(guī)則執(zhí)行流程目前只完成了對業(yè)務(wù)規(guī)則組的封裝,后續(xù)需要完成對規(guī)則流程的封裝,即實現(xiàn)規(guī)則執(zhí)行流程的嵌套。此外,推理型的規(guī)則引擎在某些場景下還有實現(xiàn)的價值,這也是后續(xù)開發(fā)工作需要關(guān)注的要點。
5? 結(jié)? 論
筆者對航空公司機票退改業(yè)務(wù)需求進行了充分的研究,查閱相關(guān)文獻后,發(fā)現(xiàn)以樹形結(jié)構(gòu)設(shè)計的規(guī)則引擎尚未應(yīng)用于國內(nèi)航空公司機票售后領(lǐng)域,因此本研究開發(fā)設(shè)計的系統(tǒng)填補了這一空白。基于規(guī)則引擎的機票售后系統(tǒng)能夠很好地幫助機票業(yè)務(wù)人員根據(jù)實際業(yè)務(wù)需求便捷地完成規(guī)則配置,使大多數(shù)航空公司能快速解決機票售后業(yè)務(wù)中的稅費計算問題。樹形結(jié)構(gòu)的規(guī)則存儲和視圖呈現(xiàn),降低了業(yè)務(wù)人員的管理難度,減少了繁瑣的工作量,提高了部門整體工作效能。規(guī)則流程化配置,保證了業(yè)務(wù)流程處理的完整性。規(guī)則能夠通過Java類加載器實時發(fā)布新的規(guī)則,保證了業(yè)務(wù)的連續(xù)性。規(guī)則發(fā)布后,以Groovy代碼的形式在JVM上運行,保證了系統(tǒng)運行的高效性。
參考文獻:
[1] 宋加強.我國民航客運機票定價研究 [D].北京:對外經(jīng)濟貿(mào)易大學(xué),2014.
[2] 李國樂.Java規(guī)則引擎與其API(JSR-94) [EB/OL].(2005-07-01)[2019-12-26].https://www.ibm.com/developerworks/
cn/java/j-java-rules/.
[3] 張寧.從0到1:構(gòu)建強大且易用的規(guī)則引擎 [EB/OL].(2017-06-09)[2019-12-22].https://tech.meituan.com/maze_framework.html.
[4] 汪成亮,溫鑫.智能環(huán)境下分布式Rete算法 [J].計算機應(yīng)用,2016,36(7):1893-1898.
[5] 周里程,熊碧輝,裘瑞清,等.Drools規(guī)則引擎的發(fā)展及應(yīng)用 [J].電子技術(shù)與軟件工程,2017(21):62-63.
[6] 孫新,嚴西敏,尚煜茗,等.一種基于共享度模型的改進Rete算法 [J].自動化學(xué)報,2017,43(9):1571-1579.
[7] 余軍陽,曹世華,朱駿,等.基于權(quán)重優(yōu)先的業(yè)務(wù)規(guī)則引擎應(yīng)用 [J].計算機應(yīng)用,2015,35(S1):174-177+182.
[8] 李春芳,譚慶平.面向業(yè)務(wù)的Drools規(guī)則引擎改進 [J].計算機應(yīng)用與軟件,2015,32(5):20-23+29.
作者簡介:黃烈甫(1982.09-),男,漢族,四川隆昌人,軟件工程師,碩士,研究方向:大數(shù)據(jù)應(yīng)用、分布式計算、軟件工程。
收稿日期:2020-02-09