『開源』插件擴展,超級高速,完全無敵 - 字符串計算 算法開源


目錄:

 

算法開發原因:

自己一直在 配置化編程 方面努力,希望 項目復雜的功能可以用 簡單的 配置來完成;

於是 在自己的網站中,使用了一個自己寫的 數據庫框架,為了給框架提速,於是就 想將 少於 5000 的數據表 進行全表緩存;

然后所有的 數據 就由框架 從緩存中 按照條件 檢索——相當於 內存檢索;

 

這時,問題就來了 —— 整個項目,Sql 腳本的 Where 條件,千變萬化;

如何判斷 某個對象 是否 符合 一個字符串的表達式,這就讓我 頭疼了;

 

於是經過搜索,得到: http://bbs.csdn.net/topics/230073145

最終的解法 是  DataTable.Compute() 函數;還有一個 是 使用微軟動態編譯技術 的解決方案(這個才是真正無敵的方法)。

 

但是確有弊端:微軟 動態編譯技術 計算字符串表達式,即時計算 “1+1”,也需要 300ms,5000個數據的檢索,這個是我所無法容忍的。

於是就想 寫一個 字符串計算 的算法;

 

 

算法版本經歷:

算法從去年5月完成,歷時 2周業余時間,完成第一版;

今年7月開始,參與了幾個 工作流項目的開發,覺着鬧心:工作流 應該和 功能分開,結果我看到,代碼中,業務代碼和工作流代碼 縱橫交錯;特別鬧心; 

於是就想 抽象一個流程設計器:讓開發人員一心一意寫業務代碼,工作流的代碼 全部使用配置,即時修改了流程,開發人員也不用 修改任何代碼;

而 流程設計器 的的手稿過程中,發現 不可避免 的有一個環節:條件判斷——這個非得使用 字符串計算算法;

於是 改版 第一版算法代碼,得到今天的第二版 Laura.Compute;

 

 

算法亮點:

新版本 算法,字符串表達式 兼容 SQL腳本(和SQL腳本類似的 字符串格式);

新版本 算法,支持 動態參數(就像 SQL中  WHERE FName=@FName 一樣);

新版本 支持 預分析,分析一次 多次執行(可用不同參數);

運算速度 達到  (分析+計算)*20000次 = 2000ms;  分析*1次+計算*20000次 = 150ms;

順手實現了 字符串表達式 的內存檢索(Word LIKE '%cat%'),50000單詞,內存檢索時間 800ms;

順手實現了 字符串表達式 的 內存排序(Word DESC, ID ASC),50000單詞,內存排序時間 2400ms;

 

 

算法思想:

 

 

算法用法:

 

使用代碼:

 

//分析一個 表達式,得到 表達式結構 對象
ExpressSchema expressSchema3 = ExpressSchema.Create("\"ShuXiaolong\" IN (\"ShuXiaolong\",\"ZhangSan\")"); //給定參數,計算這個 表達式結構 對象 在指定參數下 的運行結果
object value = expressSchema3.Compute(null); Console.WriteLine(value);

 

計算結果:

 

 

 

其他用法:

以上只是 一個簡單的 表達式:判斷 某個 字符串 是否在 一個 數組中。

以下即為 其他 功能(這些功能 全都是 算法的 插件,任何開發人員都可以 在 任意程序集 中 擴展本算法):

 插件名稱: 關鍵字: 運算優先級: DateAddComputeMethod DATEADD    1000000 DateConvertComputeMethod CONVERTDATE 1000000 DateDiffComputeMethod DATEDIFF     1000000 DateFormatComputeMethod DATEFORMAT    1000000 DateNowComputeMethod GETDATE 1000000 DatePartComputeMethod DATEPART 1000000 GuidNewComputeMethod NEWID 1000000 StringLengthComputeMethod LEN 1000000 StringReplaceComputeMethod REPLACE 1000000 PowComputeSymbol ^                      100000 MultiplyComputeSymbol *                      10000 RemainComputeSymbol %                      10000 DivideComputeSymbol /                      10000 PlusComputeSymbol +                      1000 MinusComputeSymbol -                      1000 LikeEqualComputeSymbol LIKE 700 LessThanEqualComputeSymbol <=                     685 GreaterThanEqualComputeSymbol >=                     680 LessThanComputeSymbol <                      675 GreaterThanComputeSymbol >                      670 StrictEqualComputeSymbol ===                    610 EqualComputeSymbol ==                     605 BaseEqualComputeSymbol =                      600 AndComputeSymbol AND 525 AndSignComputeSymbol &&                     525 OrComputeSymbol OR 520 OrSignComputeSymbol ||                     520 TernaryComputeSymbol ?:                     100 InComputeMethod IN 未定(默認為 0)

 

支持 函數表達式,運算符表達式 ,這兩種類型的表達式 用的是 同一個 抽象思想;

 

 

算法Demo展示:

計算對象:

            Student stu01 = new Student { Name = "舒小龍", Number = "ShuXiaolong"};
            Student stu02 = new Student { Name = "張三", Number = "zhangsan" };
            Student stu03 = new Student { Name = "舒珊", Number = "ShuShan" };

            ExpressSchema expressSchema = ExpressSchema.Create("[Number] LIKE '%Shu%'");
            bool result1_1 = (bool) expressSchema.Compute(stu01);
            bool result1_2 = (bool)expressSchema.Compute(stu02);
            bool result1_3 = (bool)expressSchema.Compute(stu03);
            Console.WriteLine(result1_1 + "|" + result1_2 + "|" + result1_3);

            ExpressSchema expressSchema2 = ExpressSchema.Create("[Name] + [Number]");
            string result2_1 = (string)expressSchema2.Compute(stu01);
            string result2_2 = (string)expressSchema2.Compute(stu02);
            string result2_3 = (string)expressSchema2.Compute(stu03);
            Console.WriteLine(result2_1 + "|" + result2_2 + "|" + result2_3);

 

 

 

內存排序:

            DataSet dataSet = GetTableRecord();  //從數據庫 讀取 50000 個單詞
            DataTable dataWord = dataSet.Tables[0];

            DateTime dt7 = DateTime.Now;
            IList listResult3 = ComputeHelper.Sort("[Word],[Comment]", dataWord.Rows);  //用封裝好的 排序函數 排序
            DateTime dt8 = DateTime.Now;
            Console.WriteLine("ComputeHelper.Sort()排序時間:" + (dt8 - dt7).TotalMilliseconds);

            Console.WriteLine(listResult3);

 

 

 

內存篩選:

            DataSet dataSet = GetTableRecord();  //從數據庫 讀取 50000 個單詞
            DataTable dataWord = dataSet.Tables[0];

            DateTime dt7 = DateTime.Now;
            IList listResult3 = ComputeHelper.Filter("[Word] LIKE '%cat%'", dataWord.Rows);  //用封裝好的 篩選函數 篩選
            DateTime dt8 = DateTime.Now;
            Console.WriteLine("ComputeHelper.Filter()篩選時間:" + (dt8 - dt7).TotalMilliseconds);

            Console.WriteLine(listResult3 + " 數目:" + listResult3.Count);

 

 

算法插件擴展: 

比方說 擴展一個 三元運算符 的插件:

任何程序集任何命名空間, 任何類名稱 下,引用 Laura.Compute.dll  

 

 1 using System;
 2 
 3 namespace 任意命名空間
 4 {
 5     [Serializable]
 6     [ComputeExpress(Express = "{A} ? {A} : {A}", Keywords = new[] { "?", ":" }, Level = 100, ComputeType = typeof(TernaryComputeSymbol))]
 7     public class TernaryComputeSymbol : ComputeBase
 8     {
 9         public override object Compute(ExpressSchema expressSchema, object objOrHash)
10         {
11             bool arg1 = ArgumentsBoolean(0, expressSchema, objOrHash);  //獲取第一個 bool參數
12             //if (Arguments[1].Type != Arguments[2].Type)
13             //    throw new Exception("TernaryComputeSymbol Type Is Not Same!");
14 
15             //完全省略 多余計算
16             string value = arg1 
17                 ? ArgumentsString(1, expressSchema, objOrHash)  //計算 第一個部分 的表達式
18                 : ArgumentsString(2, expressSchema, objOrHash); //計算 第二個部分 的表達式
19 
20 
21             return value;
22         }
23     }
24 }

 

 

擴展一個插件 就這么簡單!

 

算法源代碼:

源碼在線閱讀

Ps. 最好是能將源碼 發不到某個 網絡版本控制器上,但是不知道 如何操作,也不知道哪個  哪個平台 有 SVN的版本控制器;

如果哪位有好的 網絡版本控制器,希望推薦一哈——還是放到 版本控制器中 開源 比較好;

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM