LiteFlow決策系統的策略模式,順序、最壞、投票、權重

個人博客:無奈何楊(wnhyang)

個人語雀:wnhyang

共享語雀:在線知識共享

Github:wnhyang - Overview


image

想必大家都有聽過或做過職業和性格測試吧,尤其是現在的畢業生,在投了簡歷之后經常會收到一個什么測評,那些測評真的是又臭又長,做的簡直讓人崩潰,很多時候都是邊罵邊做,都什么玩意!?

然而,本篇就由此出發,把整個測評作為一個策略的話,其中每一項都是一條規則,通常每一條規則(問答)需要我們輸入一個類似1-9的分數,1和9分別代表兩個極端,最終這個策略會結合所有的問答結果計算出我們的性格/職業。這是如何做的呢?其實就是一種分類算法,就拿二維平面直角坐標系舉例吧!

如下二維平面直角坐標系下分出了4個區域,性格/職業測評的每條問答可以理解為其中一條經過原點的直線,1-9分別指示兩個方向,你的答案最終會是一個由原點出發的n條直線,這n條直線可以繪成一個多邊形,而這個多邊形就構成了最終結果,長得有點類似雷達圖。

image

image

image

當然這只是二維平面直角坐標系的例子,實際上現實往往比這個更復雜,高于三維的我也舉不出例子啊🙂???

總之最后結果絕大多數情況下都會是一個不規則的東西(我實在不知道更高維的該怎么描述),這種測評會取出凸點作為我們的傾向性格/職業。

好吧,關于文章開篇就到這里了,下面就可以正式開始了。不過我還是想講一個題外話,小時候接觸的數學函數(方程)可以很輕易的表示在二維直角坐標系下,隨著對于數學的深入探索,出現了越來越多的奇奇怪怪的字母和方程,有人也講“數學的盡頭是字母”🤔然而當我們換一個坐標系,這些是不是也會變個模樣呢?所以說有時候換個角度看問題就會有不同收獲,或者說換個角度問題就會迎刃而解。

策略

策略組件大致實現如下,編排時會使用p_cn.tag("code"),運行FOR(p_fn).DO(r_cn).BREAK(p_bn);FOR(p_fn).parallel(true).DO(r_cn);,前者適用于順序模式,其他皆適用于后者。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.POLICY_COMMON_NODE, nodeType = NodeTypeEnum.COMMON, nodeName = "策略普通組件")
public void policy(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.PolicyCtx policy = PolicyConvert.INSTANCE.convert2Ctx(policyMapper.selectByCode(bindCmp.getTag()));policyContext.addPolicy(policy.getCode(), policy);log.info("當前策略(code:{}, name:{}, code:{})", policy.getCode(), policy.getName(), policy.getCode());if (PolicyMode.ORDER.equals(policy.getMode())) {bindCmp.invoke2Resp(LFUtil.P_F, policy.getCode());} else {bindCmp.invoke2Resp(LFUtil.P_FP, policy.getCode());}
}

循環次數組件p_fn如下,查詢策略下的所有規則(規則還沒做版本控制,后面再改),返回規則列表大小。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_FOR, nodeId = LFUtil.POLICY_FOR_NODE, nodeType = NodeTypeEnum.FOR, nodeName = "策略for組件")
public int policyFor(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);String policyCode = bindCmp.getSubChainReqData();List<PolicyContext.RuleCtx> ruleList = RuleConvert.INSTANCE.convert2Ctx(ruleMapper.selectByPolicyCode(policyCode));policyContext.addRuleList(policyCode, ruleList);return ruleList.size();
}

循環中斷組件p_bn如下,當策略上下文中有命中風險規則時就可以停止循環了。

@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_BOOLEAN, nodeId = LFUtil.POLICY_BREAK_NODE, nodeType = NodeTypeEnum.BOOLEAN, nodeName = "策略break組件")
public boolean policyBreak(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);String policyCode = bindCmp.getSubChainReqData();return policyContext.isHitRisk(policyCode);
}

另外在使用異步循環編排時需要注意并發操作問題,尤其是對上下文的操作。

剩下的規則組件r_cn和策略上下文PolicyContext請往下看。

順序:按部就班、循序漸進

順序模式是最好理解,就是順序運行策略下的所有規則,默認在第一條設定的風險規則觸發后結束,其實更準確的叫法應該是首次。如下表在順序模式下執行,到規則2就結束了,因為默認pass之外的才是風險規則。

規則是否命中處置方式
1truepass
2truereject
3falsesms
4truereview

最壞:未雨綢繆,防患未然

與順序模式不同,需要執行所有的規則,綜合最壞的作為結果。如下表在最壞模式下,最終結果是reject(因為reject>review>pass,這個是配置的)。

規則是否命中處置方式
1truepass
2truereject
3falsesms
4truereview

投票:集體智慧,共同決策

同上,需要執行完所有規則,以命中規則的結果最多的作為最終結果。如下表在投票模式下,結果是pass

規則是否命中處置方式
1truepass
2truereject
3falsereview
4truepass

可以使用這樣的計數器,但是考慮到策略集下有不一樣的策略集,想必還要再包一層Map<String,ConcurrentHashMap<String, AtomicInteger>>,以策略code作為鍵。

private final ConcurrentHashMap<String, AtomicInteger> counters = new ConcurrentHashMap<>();/*** 增加指定 key 的計數值。* 如果 key 不存在,則初始化為 1;如果存在,則將當前值加 1。*/
public void increment(String key) {// 使用 computeIfAbsent 方法來確保只在第一次遇到該 key 時創建新的 AtomicIntegercounters.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet();
}/*** 獲取指定 key 的當前計數值。* 如果 key 不存在,則返回 0。*/
public int get(String key) {// 獲取指定 key 的 AtomicInteger,并調用 get() 方法獲取其值AtomicInteger counter = counters.get(key);return (counter != null) ? counter.get() : 0;
}

本來考慮的是在規則True組件中根據策略不同做不同的事情,但后來放棄了,還是統一放在上下文中吧,且往下看。

image

權重:量化評估,科學分配

一樣,需要運行完所有規則,綜合權重模式閾值配置得出最終結論。如下表在權重模式下,結果是23+21+20=64,注意!!!這里只是得到一個數字,在策略設置為權重模式后額外還需要配置一個閾值表,拿這個數字去匹配對應的閾值區間得出最終結論。當然這只是個最簡單例子,下面將展開,討論其豐富的應用場景和更靈活的使用方法。

規則是否命中得分
1true23
2true21
3false30
4true20

閾值配置表

得分結果
(-214,20]pass
(20,45]review
(45,70]sms
(70,900)reject

設計過程

階段一:規則增加簡單的分數屬性,命中時累計就好,如:規則1命中時+10,規則2命中時-2,這樣最為簡單,也因此適用場景最少,最不靈活。

階段二:固定公式計算,如下規則附加這些屬性,在規則命中時計算一下,這種只適合簡單的線性相關的規則計算。

/*** 計算公式為:base + al aOpType(加/減/乘/除) ${value}(取決于opType類型,是指標還是字段),結果范圍[lowerLimit,upperLimit]** @author wnhyang* @date 2024/12/9**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Weight {private Double base; // 基礎權重private Double al; // 權重調整因子private String aOpType; // 操作類型:加/減/乘/除private String opType; // 指標還是字段private String value; // 指標名稱或字段名稱private Double upperLimit; // 上限private Double lowerLimit; // 下限/*** 計算最終權重** @param trueValue 實際值,當 opType 為 "zb" (指標) 時使用* @return 最終計算出的權重*/public double compute(double trueValue) {if (al == null || trueValue == 0 && ("/".equals(aOpType))) {throw new IllegalArgumentException("Invalid parameters for computation.");}double adjustment = 0;switch (aOpType) {case "+":adjustment = al + trueValue;break;case "-":adjustment = al - trueValue;break;case "*":adjustment = al * trueValue;break;case "/":adjustment = al / trueValue;break;default:throw new UnsupportedOperationException("Unsupported operation type: " + aOpType);}double result = base + adjustment;return Math.min(upperLimit, Math.max(lowerLimit, result));}public static void main(String[] args) {Weight weight = new Weight(10.41, -2.154, "*", "zb", "count", 5000.545, -56.654);double compute = weight.compute(25.21);System.out.println("Computed weight: " + compute);}
}

階段三:靈活公式,使用QLExpress實現。如下講計算公式作為規則的一個屬性,通過getOutVarNames獲取需要用到的外部變量名,在運行表達式之前通過LiteFlow上下文取值塞到QLExpress的上下文中。

當然還有可以優化的地方,1、設計上下文時實現QLExpressIExpressContext接口,也就不用獲取后在塞,直接拿LiteFlow上下文作為QLExpress上下文用就行;2、還有就是min(upperLimit, max({}, lowerLimit))是否要放在表達式中,其實也是沒必要,可以放在表達式計算完成之后嘛。3、是否要計算平均值,現在是權重之和,是否要做加權平均呢?4、等等

@Test
public void test3() throws Exception {ExpressRunner runner = new ExpressRunner();DefaultContext<String, Object> context = new DefaultContext<>();String fun = "base + al * value";String express = StrUtil.format("min(upperLimit, max({}, lowerLimit))", fun);log.info(express);String[] outVarNames = runner.getOutVarNames(express);log.info(Arrays.toString(outVarNames));context.put("base", 45.434);context.put("al", 3.352);context.put("value", 24.3264);context.put("lowerLimit", -35.342);context.put("upperLimit", 3463.57);Object r = runner.execute(express, context, null, true, false);log.info("{}", r);
}

注意點

對于像這種可輸入的、腳本類的、在系統中運行的,一定要做好安全性校驗,避免直接操作系統資源,稍微不注意控制就會有安全漏洞。在保證安全的前提下,再考慮如何優化用戶使用體驗,如用戶需要使用一些系統字段時,在編輯器文本域輸入特殊字符(像“@”或“#”),監聽到輸入后顯示候選列表,可以關鍵詞匹配并選擇需要的字段,一旦選中,這個將作為一個整體,只能整體操作,就像我們在發郵件,或者聊天時輸入“@”一樣,另外再做一個內置運算符的提示符,這樣編輯公式就更加便捷,且能降低出錯率。再進一步就是做一個常用公式庫,提示列表中有直接選中就行,剩下的就是填充需要的字段就行。

image

應用場景

比如在做密碼登錄時,設置了兩條規則,一條正向規則y1=f(x1)x1表示最近人臉登錄成功次數,其與結果負相關,人臉登錄成功次數越多得到的負數越大;一條反向規則y2=f(x2)x2表示最近密碼登錄失敗次數,其與結果正相關,密碼登錄失敗次數越多得到的分數越大,而且保證其“增長率”大于f(x1)

可以大致表示為下面的曲線,最近人臉登錄成功次數少時,風險高一些,多時也會存在上限,因為再多也沒有意義了;最新密碼登錄錯誤次數少時風險低,但密碼登錄次數越多風險急劇增加,這樣的話在整合y=y1+y2=f(x1)+f(x2)后,風險受密碼登錄錯誤次數的影響更大。

image

當然將兩個公式整合到一塊做為一個規則也是可以的,差別就是是否需要獨立的規則條件。

條件公式
不合并condition1f(x1)
condition2f(x2)
合并condition1f(x1)+f(x2)

還有就是在信貸計算信用時,需要計算收入穩定性+信用歷史+就業情況+債務水平+資產情況的場景時,當然這依賴多方數據,而且一般的信用評估不是簡單的規則配置能解決的。

模型:智能學習,進化升級

最終都將到這一步的,雖然現在做的項目中還沒有集成模型,但是我之后一定會做。先立flag嘛,實現不是實現另說吧🧐可別連立flag的勇氣都沒有了!

關于模型我也不是專業的,也是僅有一點點了解。我一直認為學習能力、看待、解決問題的思想是最重要的,特別是我看了幾個關于機器學習的視頻后,雖然其中很多的公式我都不懂,但是能理解到其看待、解決問題的思路方法,很受益,很有啟發。

規則

以下分別是規則組件(包含isAccess實現)、命中規則、未命中規則組件。在規則命中時額外計算規則配置的權重表達式。

@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS, nodeId = LFUtil.RULE_COMMON_NODE, nodeType = NodeTypeEnum.COMMON)
public boolean ruleAccess(NodeComponent bindCmp) {String policyCode = bindCmp.getSubChainReqData();int index = bindCmp.getLoopIndex();PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = policyContext.getRule(policyCode, index);return !RuleStatus.OFF.equals(rule.getStatus());
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_COMMON_NODE, nodeType = NodeTypeEnum.COMMON, nodeName = "規則普通組件")
public void rulProcess(NodeComponent bindCmp) {String policyCode = bindCmp.getSubChainReqData();int index = bindCmp.getLoopIndex();PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = policyContext.getRule(policyCode, index);bindCmp.invoke2Resp(StrUtil.format(LFUtil.RULE_CHAIN, rule.getCode()), rule);
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_TRUE, nodeType = NodeTypeEnum.COMMON, nodeName = "規則true組件")
public void ruleTrue(NodeComponent bindCmp) {PolicyContext policyContext = bindCmp.getContextBean(PolicyContext.class);PolicyContext.RuleCtx rule = bindCmp.getSubChainReqData();log.info("命中規則(name:{}, code:{})", rule.getName(), rule.getCode());if (RuleStatus.MOCK.equals(rule.getStatus())) {policyContext.addHitMockRuleVO(rule.getPolicyCode(), rule);} else {// 權重if (PolicyMode.WEIGHT.equals(policyContext.getPolicy(rule.getPolicyCode()).getMode())) {try {Double value = (Double) QLExpressUtil.execute(rule.getExpress(), bindCmp.getContextBean(FieldContext.class));rule.setExpressValue(value);} catch (Exception e) {log.error("規則表達式執行異常", e);}}policyContext.addHitRuleVO(rule.getPolicyCode(), rule);}
}@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = LFUtil.RULE_FALSE, nodeType = NodeTypeEnum.COMMON, nodeName = "規則false組件")
public void ruleFalse(NodeComponent bindCmp) {log.info("規則未命中");
}

策略上下文

直接上代碼了。

/*** @author wnhyang* @date 2024/4/3**/
public class PolicyContext {/*** 處置方式集合*/private final Map<String, DisposalCtx> disposalMap = new ConcurrentHashMap<>();/*** 策略集*/private PolicySetCtx policySet;/*** 初始化** @param disposalCtxList 處置方式集合* @param policySet       策略集*/public void init(List<DisposalCtx> disposalCtxList, PolicySetCtx policySet) {for (DisposalCtx disposalCtx : disposalCtxList) {disposalMap.put(disposalCtx.getCode(), disposalCtx);}this.policySet = policySet;}/*** 策略集合*/private final Map<String, PolicyCtx> policyMap = new ConcurrentHashMap<>();/*** 添加策略** @param policyCode 策略code* @param policy     策略*/public void addPolicy(String policyCode, PolicyCtx policy) {policyMap.put(policyCode, policy);}/*** 獲取策略** @param policyCode 策略code* @return 策略*/public PolicyCtx getPolicy(String policyCode) {return policyMap.get(policyCode);}/*** 規則集合*/private final Map<String, List<RuleCtx>> ruleListMap = new ConcurrentHashMap<>();/*** 添加規則集合** @param policyCode 策略code* @param ruleList   規則列表*/public void addRuleList(String policyCode, List<RuleCtx> ruleList) {ruleListMap.put(policyCode, ruleList);}/*** 獲取規則** @param policyCode 策略code* @param index      規則索引* @return 規則*/public RuleCtx getRule(String policyCode, int index) {return ruleListMap.get(policyCode).get(index);}/*** 命中規則集合*/private final Map<String, List<RuleCtx>> hitRuleListMap = new ConcurrentHashMap<>();/*** 添加命中規則** @param policyCode 策略code* @param rule       規則*/public void addHitRuleVO(String policyCode, RuleCtx rule) {if (!hitRuleListMap.containsKey(policyCode)) {hitRuleListMap.put(policyCode, CollUtil.newArrayList());}hitRuleListMap.get(policyCode).add(rule);}/*** 是否命中風險規則** @param policyCode 策略code* @return true/false*/public boolean isHitRisk(String policyCode) {if (CollUtil.isNotEmpty(hitRuleListMap.get(policyCode))) {for (RuleCtx ruleCtx : hitRuleListMap.get(policyCode)) {if (!DisposalConstant.PASS_CODE.equals(ruleCtx.getDisposalCode())) {return true;}}}return false;}/*** 命中模擬規則集合*/private final Map<String, List<RuleCtx>> hitMockRuleListMap = new ConcurrentHashMap<>();/*** 添加命中模擬規則** @param policyCode 策略code* @param rule       規則*/public void addHitMockRuleVO(String policyCode, RuleCtx rule) {if (!hitMockRuleListMap.containsKey(policyCode)) {hitMockRuleListMap.put(policyCode, CollUtil.newArrayList());}hitMockRuleListMap.get(policyCode).add(rule);}/*** 轉策略集結果** @return 策略集結果*/public PolicySetResult convert() {PolicySetResult policySetResult = new PolicySetResult(policySet.getName(), policySet.getCode(), policySet.getChain(), policySet.getVersion());for (Map.Entry<String, PolicyCtx> entry : policyMap.entrySet()) {PolicyCtx policy = entry.getValue();PolicyResult policyResult = new PolicyResult(policy.getName(), policy.getCode(), policy.getMode());// 最壞String maxDisposalCode = DisposalConstant.PASS_CODE;int maxGrade = Integer.MIN_VALUE;// 投票Map<String, Integer> votes = new HashMap<>();// 權重double weight = 0.0;List<RuleCtx> ruleList = hitRuleListMap.get(policy.getCode());if (CollUtil.isNotEmpty(ruleList)) {for (RuleCtx rule : ruleList) {if (PolicyMode.VOTE.equals(policy.getMode())) {// 投票votes.put(rule.getDisposalCode(), votes.getOrDefault(rule.getDisposalCode(), 0) + 1);} else if (PolicyMode.WEIGHT.equals(policy.getMode())) {// 權重weight += rule.getExpressValue();}RuleResult ruleResult = new RuleResult(rule.getName(), rule.getCode(), rule.getExpress());// 最壞和順序DisposalCtx disposal = disposalMap.get(rule.getDisposalCode());if (null != disposal) {ruleResult.setDisposalName(disposal.getName());ruleResult.setDisposalCode(disposal.getCode());if (disposal.getGrade() > maxGrade) {maxGrade = disposal.getGrade();maxDisposalCode = disposal.getCode();}}// 模擬/正式規則區分開if (RuleStatus.MOCK.equals(rule.getStatus())) {policyResult.addMockRuleResult(ruleResult);} else {policyResult.addRuleResult(ruleResult);}}}if (PolicyMode.VOTE.equals(policy.getMode())) {String maxVoteDisposalCode = DisposalConstant.PASS_CODE;int maxVoteCount = Integer.MIN_VALUE;for (Map.Entry<String, Integer> entry1 : votes.entrySet()) {if (entry1.getValue() > maxVoteCount) {maxVoteCount = entry1.getValue();maxVoteDisposalCode = entry1.getKey();}}policyResult.setDisposalName(disposalMap.get(maxVoteDisposalCode).getName());policyResult.setDisposalCode(maxVoteDisposalCode);} else if (PolicyMode.WEIGHT.equals(policy.getMode())) {List<Th> thList = policy.getThList();// 排序thList.sort(Comparator.comparing(Th::getScore));for (Th th : thList) {if (weight <= th.getScore()) {policyResult.setDisposalName(disposalMap.get(th.getCode()).getName());policyResult.setDisposalCode(th.getCode());break;}}} else {policyResult.setDisposalName(disposalMap.get(maxDisposalCode).getName());policyResult.setDisposalCode(maxDisposalCode);}policySetResult.addPolicyResult(policyResult);}// TODO 入度大于1?考慮投票、加權平均等方法:不考慮policySetResult.setDisposalName(DisposalConstant.PASS_NAME);policySetResult.setDisposalCode(DisposalConstant.PASS_CODE);return policySetResult;}
}

策略集

策略集是用來編排策略的,即前面的策略組件p_cn.tag("code"),從前面已知策略會有結果的,那么編排他們的策略集如何取這個結果呢?

這就要考慮如何設計策略集的編排了,兩種情況,入度為1,入度大于1。

如下,圖1并行運行策略1、2,并最終都返回到結束節點,這時就要考慮如何處理策略1、2的結果了,投票?加權平均?隨機選一個?還是其他什么方法?圖2通過分流結束節點只會接收到一個策略,那么此時就不會有沖突,分流到哪個就返回哪個。

當然這塊還沒想好怎么做,只是一些想法。

image

小結

本來還想分享一下項目進展的,但轉眼一看好像寫的已經有點多了,那就下次吧!

寫在最后

拙作艱辛,字句心血,望諸君垂青,多予支持,不勝感激。


個人博客:無奈何楊(wnhyang)

個人語雀:wnhyang

共享語雀:在線知識共享

Github:wnhyang - Overview

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63761.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63761.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63761.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【計算機視覺基礎CV-圖像分類】02-入門詳解圖像分類、經典數據集、比賽與冠軍圖像模型演進史

前言 圖像分類&#xff08;Image Classification&#xff09;是計算機視覺&#xff08;Computer Vision&#xff09;中一項基礎且核心的任務。簡單來說&#xff0c;就是讓計算機從給定的類別集合中&#xff0c;為一張輸入圖片分配一個正確的類別標簽。這個過程聽起來直觀&…

三子棋游戲(基礎版)

我們用 C 語言代碼實現了一個簡單的控制臺版三子棋游戲&#xff0c;代碼分為三個部分&#xff0c;分別是頭文件game.h中定義的函數聲明以及兩個源文件game.c和test.c、game.c文件。 1.頭文件&#xff08;game.h&#xff09;部分 首先包含了<stdio.h>&#xff08;用于標…

使用Chat-LangChain模塊創建一個與用戶交流的機器人

當然&#xff01;要使用Chat-LangChain模塊創建一個與用戶交流的機器人&#xff0c;你需要安裝并配置一些Python庫。以下是一個基本的步驟指南和示例代碼&#xff0c;幫助你快速上手。 安裝依賴庫 首先&#xff0c;你需要安裝langchain庫&#xff0c;它是一個高級框架&#x…

嵌入式驅動開發詳解20(IIO驅動架構)

文章目錄 前言IIO子系統簡介主要結構體主要API函數 IIO子系統實現SPI框架IIO框架IIO通道詳解通道結構體分析通道命名分析icm20608設備通道實現 讀取函數寫入函數 測試測試效果命令行讀取應用程序讀取 后續參考文獻 前言 IIO 全稱是 Industrial I/O&#xff0c;翻譯過來就是工業…

Linux 網絡維護相關命令簡介

目錄 零. 概要一. ping二. ip命令2.1 ip address2.2 ip route2.3 ip neighbour 三. traceroute四. DNS查詢4.1 nslookup4.2 dig 五. ss 查看網絡連接狀態 零. 概要 ?在Linux系統中有2套用于網絡管理的工具集 net-tools 早期網絡管理的主要工具集&#xff0c;缺乏對 IPv6、網…

Jenkins持續集成部署——jenkins安裝

前言 Jenkins 是一個開源的自動化服務器&#xff0c;主要用于持續集成&#xff08;CI&#xff09;和持續交付&#xff08;CD&#xff09;。它為軟件開發團隊提供了一個易于使用的平臺來自動化構建、測試和部署應用程序的過程。 Jenkins 主要功能 1. 持續集成 (CI) 自動構建…

PYG - Cora數據集加載 (自動加載+手動實現)

本文從Cora的例子來展示PYG如何加載圖數據集。 Cora 是一個小型的有標注的圖數據集&#xff0c;包含以下內容&#xff1a; data.x&#xff1a;2708 個節點&#xff08;即 2708 篇論文&#xff09;&#xff0c;每個節點有 1433 個特征&#xff0c;形狀為 (2708, 1433)。data.ed…

《 火星人 》

題目描述 人類終于登上了火星的土地并且見到了神秘的火星人。人類和火星人都無法理解對方的語言&#xff0c;但是我們的科學家發明了一種用數字交流的方法。這種交流方法是這樣的&#xff0c;首先&#xff0c;火星人把一個非常大的數字告訴人類科學家&#xff0c;科學家破解這…

機器學習基礎算法 (二)-邏輯回歸

python 環境的配置參考 從零開始&#xff1a;Python 環境搭建與工具配置 邏輯回歸是一種用于解決二分類問題的機器學習算法&#xff0c;它可以預測輸入數據屬于某個類別的概率。本文將詳細介紹邏輯回歸的原理、Python 實現、模型評估和調優&#xff0c;并結合垃圾郵件分類案例進…

BiTCN-BiGRU基于雙向時間卷積網絡結合雙向門控循環單元的數據多特征分類預測(多輸入單輸出)

Matlab實現BiTCN-BiGRU基于雙向時間卷積網絡結合雙向門控循環單元的數據多特征分類預測&#xff08;多輸入單輸出&#xff09; 目錄 Matlab實現BiTCN-BiGRU基于雙向時間卷積網絡結合雙向門控循環單元的數據多特征分類預測&#xff08;多輸入單輸出&#xff09;分類效果基本描述…

云備份項目--工具類編寫

4. 文件工具類的設計 4.1 整體的類 該類實現對文件進行操作 FileUtil.hpp如下 /* 該類實現對文件進行操作 */ #pragma once #include <iostream> #include <string> #include <fstream> #include <vector> #include <sys/types.h> #include …

51c大模型~合集94

我自己的原文哦~ https://blog.51cto.com/whaosoft/12897659 #D(R,O) Grasp 重塑跨智能體靈巧手抓取&#xff0c;NUS邵林團隊提出全新交互式表征&#xff0c;斬獲CoRL Workshop最佳機器人論文獎 本文的作者均來自新加坡國立大學 LinS Lab。本文的共同第一作者為上海交通大…

【大學英語】英語范文十八篇,書信,議論文,材料分析

關注作者了解更多 我的其他CSDN專欄 過程控制系統 工程測試技術 虛擬儀器技術 可編程控制器 工業現場總線 數字圖像處理 智能控制 傳感器技術 嵌入式系統 復變函數與積分變換 單片機原理 線性代數 大學物理 熱工與工程流體力學 數字信號處理 光電融合集成電路…

一起學Git【第一節:Git的安裝】

Git是什么&#xff1f; Git是什么&#xff1f;相信大家點擊進來已經有了初步的認識&#xff0c;這里就簡單的進行介紹。 Git是一個開源的分布式版本控制系統&#xff0c;由Linus Torvalds創建&#xff0c;用于有效、高速地處理從小到大的項目版本管理。Git是目前世界上最流行…

消息隊列 Kafka 架構組件及其特性

Kafka 人們通常有時會將 Kafka 中的 Topic 比作隊列&#xff1b; 在 Kafka 中&#xff0c;數據是以主題&#xff08;Topic&#xff09;的形式組織的&#xff0c;每個 Topic 可以被分為多個分區&#xff08;Partition&#xff09;。每個 Partition 是一個有序的、不可變的消息…

《Mycat核心技術》第06章:Mycat問題處理總結

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章匯總&#xff1a;https://binghe.gitcode.host/md/all/all.html 星球項目地址&#xff1a;https://binghe.gitcode.host/md/zsxq/introduce.html 沉淀&#xff0c…

【day11】面向對象編程進階(繼承)

概述 本文深入探討面向對象編程的核心概念&#xff0c;包括繼承、方法重寫、this和super關鍵字的使用&#xff0c;以及抽象類和方法的定義與實現。通過本文的學習&#xff0c;你將能夠&#xff1a; 理解繼承的優勢。掌握繼承的使用方法。了解繼承后成員變量和成員方法的訪問特…

隨手記:小程序兼容后臺的wangEditor富文本配置鏈接

場景&#xff1a; 在后臺配置wangEditor富文本&#xff0c;可以文字配置鏈接&#xff0c;圖片配置鏈接&#xff0c;產生的json格式為&#xff1a; 例子&#xff1a; <h1><a href"https://uniapp.dcloud.net.cn/" target"_blank"><span sty…

6.8 Newman自動化運行Postman測試集

歡迎大家訂閱【軟件測試】 專欄&#xff0c;開啟你的軟件測試學習之旅&#xff01; 文章目錄 1 安裝Node.js2 安裝Newman3 使用Newman運行Postman測試集3.1 導出Postman集合3.2 使用Newman運行集合3.3 Newman常用參數3.4 Newman報告格式 4 使用定時任務自動化執行腳本4.1 編寫B…

工具環境 | 工具準備

搭建一套驗證環境需要的工具如下&#xff1a; 虛擬機&#xff1a;推薦virtualbox ubuntu VM好用&#xff0c;但是免費的好像木有了&#xff0c;ubuntu界面版更加容易上手。 網上找安裝教程即可&#xff0c;注意實現文件共享、復制粘貼等功能。 EDA&#xff1a;VCS Veridi 工…