朱明超,宋 暉
(東華大學 計算機科學與技術學院,上海 201620)
近幾年,越來越多的學者將目光聚焦在認知智能上,知識圖譜受到越來越廣泛的關注。隨著知識圖譜在各個領域中展現出價值,領域知識圖譜構建成為智能應用系統的重要組成部分。在領域知識圖譜構建過程中面對的首要問題是:領域數據的及時采集。知識圖譜構建最常用的數據采集方式是網絡數據采集。文獻[2]通過人工操作方式從網頁下載數據,文獻[3]通過解析相關網頁獲得企業股票代碼列表等企業信息。
領域數據通常有多個數據來源,獲取途徑相對分散,往往需要通過多渠道多次獲取,費時費力。而且采集的數據無法及時與數據源同步。針對不同的數據源,采集任務的執行周期也不同,因此需要一個可從多數據源定時采集數據的系統。
本文針對領域數據采集問題,基于機器人流程自動化技術設計了支持數據定時采集和多任務并發處理的數據采集系統。此系統結合數據采集腳本和Celery定時任務實現了數據的定時采集,實現了Celery配置文件的動態加載與更新,使默認單線程的 Celery定時任務能夠支持多任務并行。該系統基于Django開發框架及Docker容器技術進行開發和部署,提供了任務監控和數據管理功能。
本系統采用Django快速開發框架搭建,使用Docker進行系統部署。數據采集最常使用的工具有Python爬蟲工具庫、爬蟲框架和Selenium[5]自動化工具。本系統采用Selenium自動化工具進行數據采集。
已有的數據采集系統通常是單任務、面向特定需求的,如煤礦安全[6]、學科發展狀態[10]和醫療數據等,可復用性弱。已有的面向多數據源的采集系統,不能保障多任務并行且無法保證數據的及時性。針對知識圖譜數據獲取的問題,本文參考分布式數據采集的實現思路[13]設計實現了多任務數據采集系統。
本系統基于Django框架開發實現。系統分為任務管理和數據采集兩大模塊。
任務管理模塊,將對特定數據源的采集腳本封裝為任務。系統提供對任務的管理,包括任務定義、定時執行和多任務并發控制。
數據采集模塊,包括數據采集、采集容錯機制和數據存儲。系統采用 MySQL和 Neo4j數據庫分別存放任務信息和知識圖譜的關系數據。系統架構如圖1所示。

圖1 系統架構Fig.1 System structure
本系統使用Selenium自動化工具調用瀏覽器驅動,訪問數據源網頁,定位目標數據在網頁結構中的位置以采集所需數據。此方式可以準確的采集頁面中的目標數據。
系統的核心功能是定時任務、多任務并發控制、數據監控和數據管理。在Django框架下通常將數據采集任務封裝為線性執行的函數,這種執行方式面臨3個問題:(1)任務開始執行后,如果任務采集的數據太多或頻繁切換網頁會導致任務執行時間過長。采用線性執行方式會使系統前端頁面一直處于等待狀態,前端等待時間過長會導致頁面長時間卡頓甚至報錯,使得用戶使用體驗極差;(2)線性執行方式無法保證采集的數據與數據源同步更新,需頻繁人工啟動任務執行;(3)線性執行方式沒有任務并發管理機制,多任務并行會導致采集報錯。
為解決以上問題,本系統采用Django框架下最常用的定時任務實現工具 Celery。Celery中定時任務控制器Beat、中間件Broker和任務執行單元Worker分別負責任務分發,路由管理,具體任務執行。Celery定時任務流程為:Beat定時將任務派發給任務隊列,任務隊列和Worker的映射關系為路由,任務隊列根據路由將任務分配給相應Worker執行。Celery默認只有一個隊列和Worker,即只有一組路由。本系統以Celery定時任務為基礎,設計實現了系統的核心功能。
設置定時任務的關鍵步驟是任務注冊和任務綁定。在采集腳本前加上“@app()”,將此采集腳本注冊為Celery可識別的Task。在定時任務綁定頁面從Celery已有Task列表中選擇對應的采集腳本,設定執行間隔,定時任務名等參數。點擊保存后將此Task的定時執行信息添加在定時任務表。如圖2所示。

圖2 定時任務綁定頁Fig.2 Timed task binding page
基于Celery設計的定時采集任務,在任務執行中還需添加數據采集容錯機制,解決數據重復采集問題。采集腳本在網頁加載完成,網頁中各元素的相對位置確定后,才能成功定位目標數據。當采集任務數據源響應慢或網絡延遲時會導致頁面數據定位失敗等問題,為此系統設計了對應的容錯機制,當捕獲報錯后,任務將主動等待一段時間后再次執行。任務重試次數和等待時間可在任務配置文件中設置。
Celery定時任務中同一任務多次執行時,如果每次執行沒有標識,將導致每次采集的數據重復。為解決重復采集問題,本系統以數據發布日期來區分同一任務的多次執行。網頁數據帶有發布日期,在任務的配置文件中加入開始日期“start_date”和時間跨度“interval_time”兩個參數,分別表示開始采集的數據日期和單次采集任務的時間跨度。采集任務把數據發布日期作為標識,本次任務執行開始日期取上次任務執行結束時的數據日期,若當前為第一次執行則取“start_date”。采集任務采集完一個日期的數據后,日期自增,任務采集下一日期數據,以上步驟循環“interval_time”次,完成此次采集任務。則每次采集任務是對上次采集任務的增量更新,數據源發布新數據時,新數據對應最新日期,下次采集時可增量采集新數據。采集任務按任務日期的時序采集數據,可以避免重復采集和對新數據的查詢判斷,保證數據采集的及時和高效。
使用定時任務方式執行采集腳本,Worker執行任務時最終是執行一個線性函數。當多個采集任務同時執行,默認都在系統的主進程執行,系統會因多個任務爭用唯一的瀏覽器驅動而報錯。同時Celery默認只有一個任務隊列和一個Worker,多個任務并發會使任務隊列阻塞。
本系統采用新的定時任務執行策略和新的Celery路由更新邏輯解決瀏覽器驅動爭用和任務隊列阻塞問題。
3.2.1 定時任務執行策略
默認的執行方式是 Worker執行任務時在系統的主進程中執行任務函數。新的策略是系統主進程中不再執行采集任務,采集任務在獨立的線程中執行,每個線程有自己的上下文,互不影響。
3.2.2 Celery路由更新邏輯
Celery默認所有任務發送給唯一的默認任務隊列,交由默認Worker執行。為了解決多任務并行隊列阻塞問題,系統在新任務創建時為 Celery添加除默認路由之外的新路由,使其可以同時執行多個任務。Celery默認的路由更新方式是在Celery配置文件“celeryconfig.py”中手動添加路由。此種方式用戶友好性很差,新的路由更新邏輯在新的定時任務創建時自動為此任務創建任務獨占的路由,將其和原有路由一并寫入新的路由字典,在配置文件“celeryconfig.py”中以文件讀取的方式訪問路由文件,讀取新的路由字典替換原有的路由信息。
為了方便用戶了解任務的執行情況,在系統主頁上展示任務執行信息,并實時更新。系統調用Celery監控工具Flower提供的API獲取每個任務狀態的信息,并返回給前端,并將任務執行結果存入任務執行日志表中。調用Flower獲取任務狀態數據的API如圖3所示。

圖3 任務狀態APIFig.3 T ask status api
不同任務采集的數據不同,格式難以統一,數據存儲時無法根據數據類型管理。為了統一管理,具體的數據如文字,pdf等作為附件以文件形式保存,不存入數據庫,將數據保存的路徑存入數據庫。
為了使系統具備功能調整和擴展的能力,系統的功能修改和添加更加彈性化,本系統采用Docker容器技術在服務端進行動態部署,并使用Nginx+Uwsgi替換 Django自帶的 Web服務。部署時根據系統包含的服務進行了容器劃分,在docker-compose文件中編排容器。圖4展示了服務端的Docker容器劃分。(1)Web容器是主容器,運行基于 Django項目構建的Web鏡像,包含項目的主要邏輯代碼;(2)Nginx容器是Django自帶Web服務的替代容器,提供對外的Web服務;(3)Selenium容器是數據采集支持容器,用于屏蔽系統環境對采集腳本的影響;(4)MySQL和Neo4j是兩個數據庫,分別在不同容器,為系統提供數據存取服務。

圖4 容器劃分Fig.4 Container division
系統主要頁面包括主頁、任務添加頁、定時任務綁定頁和數據查詢展示頁。主頁如圖5所示。左邊三個板塊分別是任務相關頁面、數據相關頁面和數據查詢展示頁面。主頁中間是已有任務的信息及系統支持的對任務的操作,包括任務開始和停止、修改、刪除和數據展示。主頁下方是任務的執行狀態信息。

圖5 主頁Fig.5 Homepage
本文針對領域知識圖譜構建過程中遇到的領域數據采集難點,設計實現了多任務數據采集系統,給出了系統的架構設計和系統核心功能的設計與實現。最后展示了系統在服務端基于Docker容器的部署。