正如我們在AnyLogic中數據庫應用的小陷阱(Part 1)——數據刷新中看到的那樣,?Anylogic 的內部數據庫是有一些小陷阱的......
在這篇文章中,我們想讓您了解在使用Excel作為外部數據源時數據庫的一些其他值得注意的地方,并指出一種更可靠的數據導入方法。
通常,在為客戶創建模型時,仿真模型所需的重要輸入數據通常會以Excel文件的形式提供。可能是輪班計劃、生產計劃或客戶訂單等等。確實,Excel不是處理數據的最佳選擇,但大多數公司都在使用這種簡單易用的軟件來準備和收集數據。因此,仿真項目的客戶大多要求以Excel作為管理仿真模型輸入數據的首選工具。
所以,對于仿真建模人員來說,能夠熟練地將基于Excel的數據輸入到模型中,不必費事和繞道而行,是一項必備技能。
但是要如何做到這一點呢?
使用內置數據庫訪問Excel文件
您可能已經猜到了:使用Anylogic的內置數據庫!只需從Anylogic建立到Excel文件的連接,所有數據都將被提取并加載到數據庫中,從而加載到您的模型中。聽起來太簡單太好了以至于感覺不像是真的?但這絕對是真的!
在大多數情況下,標準連接可以充分發揮作用,尤其是當您熟悉使用AnyLogic時。但如果您是一名顧問,客戶的具體需求往往會有所不同。。。大多數客戶希望在無需AnyLogic軟件的情況下使用該模型,因此交付成果會是導出的獨立版本或云版本。在這兩種情況下,只能通過仿真前端或正在使用的excel文件調整輸入數據。很多時候,第二種選擇更受青睞,因為大多數客戶已經熟悉Excel。因此,構建盡可能穩健的數據導入非常重要。
我們設置了一個示例Excel工作表來重現和解決一些常見問題。在下圖中,左側為Excel文件,右側為AnyLogic中導入的數據。
我們可以調整每一列中的條目,當啟用自動更新時,AnyLogic通常會在仿真啟動時更新這些條目。但這里存在第一個陷阱:如果輸入文件的結構或數據類型發生重大更改,AnyLogic DB將不再刷新數據庫,甚至更糟的是,這個過程不會向用戶發出任何錯誤消息或通知,因此可能會導致具有誤導性的仿真結果。
我們總結了一些可能導致此問題發生的案例:
向表中添加帶有標題的新列:通常,在excel文件中的其他列中執行某些計算時不會出現問題,但如果向這些列添加新標題,則刷新此文件中的數據將不再有效。
更改列的數據類型:例如,如果我們將小數添加到預定義的整數列中,表也不會刷新。因此,如果將來此列中可能有小數,則必須將任何僅包含整數值的列定義為雙精度。
使用VLOOKUP:就其本身而言,在表中沒有“#N/A”值的情況下,使用VLOOKUP是沒有問題的(“#N/A”值也表示會導致數據庫停止更新的不同數據類型)。例如,可以通過在返回正確數據類型的VLOOKUP周圍封裝IFERROR語句來避免這種情況。
那現在怎么辦呢?
方法1:
刪除其他標題,并且整數列再次僅包含整數值時,此表才正常刷新。基本上,就是直至恢復原始格式。之后,表就會再次按預期工作和更新。
因此,在使用外部數據源時,如果僅依賴自動更新功能,則需要小心。更新失敗很可能會被忽視,并最終危及模型的質量。因此,我們更推薦使用excel數據輸入的第2種方法,可以在數據庫更新失敗時,讓用戶可以接收到反饋。
方法2:
如果要使用內部更新功能并想要注意可能的錯誤,可以使用以下代碼。實際上,它本身并不能解決問題,但至少在表更新失敗時,您會收到相應的錯誤消息提醒。
首先,定義ImportableDataonStartup函數,需要將下面這段代碼添加到相應智能體的附加類代碼:
1.public void importTableDataOnStartup(java.sql.Connection internalDatabaseConnection) throws Exception {
2.try (DatabaseDescriptorRegistry r = new DatabaseDescriptorRegistry()) {
3.java.sql.Connection cachedSourceConnection;
4.cachedSourceConnection = r.getConnection(DatabaseDescriptorFactory.createFileDescriptor(Utilities.findExistingFile("excelfile.xlsx"), null, ""));
5.?UtilitiesDatabase.copyDatabaseTable(cachedSourceConnection, internalDatabaseConnection, "\"EXCEL-TABLE-NAME\"",
6."INTERNAL AL DB TABLE NAME");
之后,用下面的代碼調用importableDataonStartup函數,以下代碼必須在實驗屬性的Java行動“仿真運行前”中用于初始的實驗更新,或在智能體屬性的智能體行動“啟動時”中用于與智能體相關的更新。如果在初始化例程中需要使用數據,則在初始化main類之前執行更新是很重要的。否則,初始化將基于過時的數據進行。
1.try {
2.// this will call the additional class code
3.? ? ? ?importTableDataOnStartup( getDatabaseConnection() );
4.} catch ( Exception e ) {
5.// this will generate an error message to let the user know that there are some issues
6.? ? ? ?e.printStackTrace();
7.}
為了確保即使客戶錯誤處理導入文件,您的模型也會更新并因此正常工作,您可以使用AnyLogic連接面板中的數據庫模塊。這樣,您就可以在任何Excel文件上使用類似sql的SELECT FROM語句。但是,這同樣有一些非常重要的缺點需要注意:
l?您可以添加WHERE語句,但在沒有任何通知的情況下不會考慮這些語句。這意味著“SELECT material FROM mat_db WHERE density > 5”的將檢索列表中的所有材質,而不僅僅是密度大于5的材質。
l?數據中的任何公式都不會得到結果。您將收到一個包含公式本身的字符串
因此,這種變通方法可能只在一些比較少見的用例中使用,其中
l?excel文件中的列位置可能會頻繁更改,
l?列不包含任何公式
l?如果在檢索數據之前不需要過濾數據(顯然,可以在從文件中檢索數據集之后過濾數據,但這可能會導致大量數據的性能問題。因此,我們一般不推薦這種方法)
最后介紹的方法使用AnyLogic連接面板的Excel文件模塊。通過此操作,您可以使用行號和列號的組合來訪問Excel文件的任何填充單元格。要將其用于類似數據庫的數據調用,必須開發相對復雜的訪問函數。如果您以適當的方式執行此操作,您就可以真正根據自己的需求創建一個強大而靈活的界面。
作為客座作者,我們將使用Excel文件模塊方法用于非常復雜的客戶項目,以確保模型的生命周期能夠持續很長時間,而無需客戶提出任何額外的支持請求。我們明確建議僅對高級用戶和復雜客戶請求使用此方法。最佳實踐是將內部數據庫的更新方法與我們的擴展代碼一起使用,如果AnyLogic在更新過程中出現問題,都會得到通知。
原文作者:
Maximillian Selmair?和?Patrick W?he相關文章