面向?qū)ο缶幊虒?shí)踐--MapReduce模式

關(guān)鍵字: MapReduce模式, 關(guān)注點(diǎn)分離

MapReduce是一種編程模型,用于大規(guī)模數(shù)據(jù)集(大于1TB)的并行運(yùn)算。概念"Map(映射)"和"Reduce(歸約)",是它們的主要思想,都是從函數(shù)式編程語(yǔ)言里借來(lái)的,還有從矢量編程語(yǔ)言里借來(lái)的特性。它極大地方便了編程人員在不會(huì)分布式并行編程的情況下,將自己的程序運(yùn)行在分布式系統(tǒng)上。 當(dāng)前的軟件實(shí)現(xiàn)是指定一個(gè)Map(映射)函數(shù),用來(lái)把一組鍵值對(duì)映射成一組新的鍵值對(duì),指定并發(fā)的Reduce(歸約)函數(shù),用來(lái)保證所有映射的鍵值對(duì)中的每一個(gè)共享相同的鍵組。

上面是一般認(rèn)識(shí)的MapReduce, 主要應(yīng)用于大數(shù)據(jù)領(lǐng)域. 但是MapReduce的思想,在我們的日常編程中也是有很大的應(yīng)用, 特別是利用LINQ所帶來(lái)的處理方式改變,可以寫(xiě)出容易理解的代碼.
我們?nèi)粘L幚淼拇a很多時(shí)候都是對(duì)一個(gè)集合進(jìn)行處理,轉(zhuǎn)化(MAP),聚合(Reduce)來(lái)獲得最后的結(jié)果.
當(dāng)然我們可以利用if/foreach來(lái)達(dá)到同樣的效果, 但是太多的if/foreach 混合的計(jì)算機(jī)基礎(chǔ)邏輯和業(yè)務(wù)邏輯, 很難做到關(guān)注點(diǎn)分離. 使用MapReduce后,可以讓頂層代碼,更加面向需求方, 可以用自然語(yǔ)言和客戶解釋邏輯,確認(rèn)邏輯.

需求:####

我們有一個(gè)規(guī)則記錄節(jié), 里面每條規(guī)則有一個(gè)源表(及字段ID)和一個(gè)目標(biāo)表(及字段ID). 現(xiàn)在需要把所有規(guī)則按照源表生成一個(gè)分組結(jié)構(gòu)返回前端處理.

代碼初稿:####

            var sections = _DbContext.StudyStandardMappingSection
                .Where(p => p.MappingID == mappingID && p.DataStatus != DataStatus.刪除);

            var ret = Mapper.Map<IEnumerable<StudyStandardMappingSectionViewModel>>(sections);

            foreach (var section in ret)
            {
                section.Tables = new List<StudyStandardMappingTableViewModel>();

                //找出該分組下的規(guī)則
                var rules = _DbContext.StudyStandardMappingRule
                    .Where(p => p.MappingSectionID == section.MappingSectionID && p.DataStatus != DataStatus.刪除);

                var ruleViewModels = Mapper.Map<IEnumerable<StudyStandardMappingRuleViewModel>>(rules);

                if (rules != null)
                {
                    //將規(guī)則按表分類
                    var tables = ruleViewModels.ToLookup(s => new { s.SourceTableID, s.SourceFieldName });

                    foreach (var table in tables)
                    {
                        StudyStandardMappingTableViewModel tmp = new StudyStandardMappingTableViewModel();
                        tmp.SourceTableID = table.Key.SourceTableID;
                        tmp.SourceTableName = table.Key.SourceFieldName;
                        tmp.Rules = new List<StudyStandardMappingRuleViewModel>();

                        foreach (var rule in table)
                        {
                            tmp.SourceTableName = rule.SourceTableName;//(此處設(shè)置表名不好,待改進(jìn))

                            //將多選變量分類
                            var options = table.ToLookup(s => s.ParentID);

                            foreach (var option in options)
                            {
                                //判斷是否為多選變量規(guī)則,若是0代表不是多選變量規(guī)則
                                if (option.Key == 0)
                                {
                                    tmp.Rules.Add(rule);
                                }
                                else
                                {//將選項(xiàng)值規(guī)則加入對(duì)應(yīng)的多選變量規(guī)則中
                                    var optionRule = ruleViewModels.Where(s => s.MappingRuleID == option.Key).FirstOrDefault();
                                    optionRule.OptionValues = new List<StudyStandardMappingRuleViewModel>();

                                    foreach (var item in option)
                                    {
                                        optionRule.OptionValues.Add(item);
                                    }
                                }
                            }
                        }
                        section.Tables.Add(tmp);
                    }
                }
            }

應(yīng)用MapReduce模式后代碼:####


            var sections = _DbContext.StudyStandardMappingSection
                                        .Include("Rules")//取出子規(guī)則
                                        .Where(p => p.MappingID == mappingID)//只要某個(gè)映射下的所有節(jié)
                                        .ExcludeDeleteData()//排除刪除的節(jié)
                                        .ToList()//排除數(shù)據(jù)庫(kù)的影響,轉(zhuǎn)化為list,以便后續(xù)處理
                                        .Select(p => RenderOneSectionViewModel(p, p.Rules));//構(gòu)建一個(gè)分組節(jié)


        private StudyStandardMappingSectionViewModel RenderOneSectionViewModel(StudyStandardMappingSection section, IEnumerable<StudyStandardMappingRule> rules)
        {
            var ret = Mapper.Map<StudyStandardMappingSectionViewModel>(section);

            ret.Tables = rules.ExcludeDeleteData()//排除刪除的規(guī)則
                                .GroupBy(p => new { p.SourceTableID, p.SourceTableName })//按照源表ID和表名分組
                                .Select(p => CreateOneMappingTableViewModel(p.Key.SourceTableID, p.Key.SourceTableName, p))//按照表名,表ID依次為每張表構(gòu)建ViewModel
                                .ToList();
            return ret;
        }

        private StudyStandardMappingTableViewModel CreateOneMappingTableViewModel(string sourceTableID, string sourceTableName, IEnumerable<StudyStandardMappingRule> rules)
        {
            return new StudyStandardMappingTableViewModel
            {
                SourceTableID = sourceTableID,     //更新表ID
                SourceTableName = sourceTableName, //更新表名
                Rules = rules
                            .ExcludeDeleteData()   //排除已刪除的規(guī)則
                            .UpdateRuleChildOption() //更新規(guī)則的選項(xiàng)值列表
                            .Where(p => p.ParentID <= 0)   //選擇非選項(xiàng)的規(guī)則                            
                            .Select(p => Mapper.Map<StudyStandardMappingRuleViewModel>(p)) //轉(zhuǎn)化為ViewModel
                            .ToList(),
            };
        }

        public static IEnumerable<StudyStandardMappingRule> UpdateRuleChildOption(this IEnumerable<StudyStandardMappingRule> rules)
        {
            return rules.Select(p => p.UpdateOptions(rules.Where(p => p.ParentID == mappingRuleID)));
        }

點(diǎn)評(píng):

哪一種方法更好了? 直接看,初稿代碼似乎更好,每個(gè)邏輯判斷都直接在代碼里面,似乎很清楚. 但是,每次看代碼的時(shí)候, 都要不停的混合代碼邏輯(if,else,foreach)和業(yè)務(wù)邏輯(如何構(gòu)造表分組).每次看懂這個(gè)代碼都要10幾分鐘.
第二種方法,基本上都是業(yè)務(wù)的語(yǔ)言來(lái)構(gòu)建邏輯, 不用一分鐘就知道代碼在干什么,很容易發(fā)現(xiàn)業(yè)務(wù)邏輯是否有問(wèn)題, 也容易跟隨業(yè)務(wù)變化而變化. 但是底層算法都被保證在外部代碼或者小函數(shù)里面, 調(diào)試起來(lái)還是挺麻煩的. 當(dāng)然,這里還有一個(gè)非常大的好處,就是代碼復(fù)用, 原來(lái)的代碼很難復(fù)用,導(dǎo)致在幾個(gè)地方重復(fù),改造后,只需要調(diào)用相關(guān)邏輯算法就好.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容