【系統設計】統計組織架構中,各層級的人數的方案。


在業務方得到一個需求,需要統計每個組織所包含的人數。如下圖所示 ,整個集團上百家公司 4000+組織。大致結構如下圖所示:

 

 

 

首先,這是一個樹形結構,所以要統計必然要用遞歸的方式。

 

 

 

分析一下表結構,然后用最簡單的方法來思考一下,假如這個樹從上到下只有一條路徑 那么人數如圖所示:

  OrgId (主鍵Id)  |  ParentId (父組織Id)  |  count 當前組織人數 |  sumCount 包含下級組織      

        

   人數是通過員工表 對 組織ID進行分組查詢搜索出來的結果。

OK 如圖所示 就統計出來了,但如果這個組織層級極其復雜的話,就沒有這么容易了,比如想要算OrgId = 5 的組織人數,要把parentId = 5的子組織全找出來,然后這些子組織要繼續找下級組織,直到擴散到葉子節點(指沒有下級的節點)。這樣計算效率低的離譜,所以需要優化一下。

我們這里引入一個深度的字段概念!這個東西最好在添加組織的時候就保存下來。然后就計算最大深度(比如10)的所有組織人數,再遞歸計算9、8、7......深度的組織,直到最頂層。

這樣做 統計深度6的所有組織的時候,已經把7的數據都匯總完畢了,直接parentId = 深度7的組織Id,然后把數量匯總就可以了,不用繼續遞歸,因為7已經統計完了 8 9 10深度的所有人數,以此類推

員工表1W+人 , 組織表4000+,查詢時間大概是10秒左右。建議統計完所有直接把數據放入緩存中,涉及組織變更、調動、添加員工、入職、離職、都要清除緩存,下次要用的時候再重新計算。

 

代碼如下(C#):

      /// <summary>
        /// 獲取各組織數量
        /// </summary>
        public async Task<List<OrgCountCache>> GetOrgCountCache()
        {
            return (await _orgCountCache.GetOrAddAsync(CacheKyes.OrgCount, async () =>
            {
                var orgs = await GetOrganizationCache();

                // 計算出有人在其下的各組織節點數據
                var hasCount = await _employeeRepository.GetOrgCount();
                if (hasCount == null || !hasCount.Any())
                {
                    return new List<OrgCountCache>();
                }

                // 所有組織節點數據
                var allOrgCount = new List<OrgCountCache>();
                foreach(var org in orgs)
                {
                    var orgCountCache = new OrgCountCache();
                    orgCountCache.OrgId = org.OrgId;
                    orgCountCache.ParentId = org.ParentId;
                    orgCountCache.OrganizationLevel = (int)org.OrganizationLevel;

                    // 找出4000+個組織中掛了人的組織
                    var hasCountOrg = hasCount.FirstOrDefault(x => x.OrgId == org.OrgId);
                    if (hasCountOrg != null)
                    {
                        orgCountCache.Count = hasCountOrg.Count;
                        orgCountCache.SumCount = hasCountOrg.Count;
                    }
                    allOrgCount.Add(orgCountCache);
                }

                GetOrgCountRecursion(allOrgCount, 10);

                return allOrgCount;
            })).Clone();
        }

     /// <summary>
        /// 遞歸查詢每個組織的數量 先查最深的,然后遞歸查深度其次的
        /// </summary>
        public void GetOrgCountRecursion(List<OrgCountCache> allOrgCount, int organizationLevel)
        {
            if (organizationLevel == 0) // 單獨組織,沒有父級,沒有子集
            {
                foreach (var orgCount in allOrgCount)
                {
                    if (orgCount.OrganizationLevel != organizationLevel)
                        continue;
                    orgCount.SumCount = orgCount.Count;
                }
            }
            else if (organizationLevel < 0)  // 計算完畢,跳出循環
            {
                return;
            }
            else
            {
                foreach (var orgCount in allOrgCount)
                {
                    if (orgCount.OrganizationLevel != organizationLevel) 
                        continue;
                    // 計算總和SumCount = 本身Count  +  所有下一層深度節點的SumCount
                    orgCount.SumCount = orgCount.Count + allOrgCount.Where(x => x.ParentId == orgCount.OrgId).Select(x => x.SumCount).Sum();
                }
                // 遞歸調用,深度-1
                GetOrgCountRecursion(allOrgCount, organizationLevel - 1);
            }
        }

 


免責聲明!

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



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