iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
AI & Data

Tableau 輕鬆學系列 第 25

[Day25] Tableau 輕鬆學 - TabPy 使用方法 2

前言

直接將所有 Python 程式寫在工作簿內的第一種 TabPy 使用方法我們已經學會了,但這種方法的最大缺點是難以管控程式碼,無法將程式碼提供給多個工作簿共用。這裡要分享的是第二種 TabPy 使用方式,以佈署函式的方式讓我們可以將程式碼集中管理。

佈署函式

說明

第二種使用方式就是向 TabPy Server 先註冊 Python 函式來提前佈署,佈署好的函式在 TabPy 中就會被視為一個 Model,Tableau Desktop 只需要指定要用來處理資料的 Model 名稱,即可等待運算結果回傳。

流程

建立一個名稱為 TabPyTest.py 的 Python 檔案,內容如下

from tabpy.tabpy_tools.client import Client

client = Client('http://localhost:9004/')

def foo(data1, data2):
    return True

client.deploy('foo', foo, 'This is the test function.')
  • Client(url):建立一個 TabPy Client 物件,並指定對 url 連線,TabPy 目前不接受遠端佈署,只能對在 localhost 的 TabPy Server 佈署函式,所以這裡的 url 網域必為 localhost
  • foo(data1, data2):自行建立可接受兩個輸入參數的函式,與第一種 TabPy 使用方法不同的是,參數名稱可以自定義,這裡分別命名為 data1data2
  • client.deploy(model_name, function, model_description)model_name 為佈署後的 Model 名稱,可以選擇與函式不同的名稱,但建議為有意義並且容易懂的詞彙;function 為要佈署的函式;model_description 為 Model 的補充敘述。

執行佈署 (需在有安裝 TabPy 的虛擬環境中執行)

(Tableau-Python-Server) C:\Users\wrxue>python TabPyTest.py

若佈署成功,在 http://localhost:9004/ 的 Deployed Models 區域應該就會看到新增一個名為 foo 的 Model,也就是我們在 TabPyTest.py 內的 foo 函式

"foo": {
    "description": "This is the test function.",
    "type": "model",
    "version": 1,
    "dependencies": [],
    "target": null,
    "creation_time": 1626685276,
    "last_modified_time": 1626685276,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
}

使用方法

TabPy 佈署

理解佈署的概念與流程之後,便能將我們在方法一使用到的 Python 包裝成四個不同的函式來佈署,將 TabPyTest.py 修改為如下內容後執行佈署

from tabpy.tabpy_tools.client import Client

client = Client('http://localhost:9004/')

def testBool(data):
    return [x > 10000 for x in data]

def testInt(data):
    return [int(x * 2) for x in data]

def testReal(data):
    import math
    return [math.sqrt(x) for x in data]

def testStr(data1, data2):
    return [f'{x[1]} 的銷售額為 {int(x[0])}' for x in zip(data1, data2)]

client.deploy('test_SCRIPT_BOOL', testBool, 'Test SCRIPT_BOOL by deployment')
client.deploy('test_SCRIPT_INT', testInt, 'Test SCRIPT_INT by deployment')
client.deploy('test_SCRIPT_REAL', testReal, 'Test SCRIPT_REAL by deployment')
client.deploy('test_SCRIPT_STR', testStr, 'Test SCRIPT_STR by deployment')

TabPy Server 的 Deployed Models 會跟著新增 4 個 Models,分別為 test_SCRIPT_BOOLtest_SCRIPT_INTtest_SCRIPT_REALtest_SCRIPT_STR

"test_SCRIPT_BOOL": {
    "description": "Test SCRIPT_BOOL by deploy",
    "type": "model",
    "version": 1,
    "dependencies": [],
    "target": null,
    "creation_time": 1626686885,
    "last_modified_time": 1626686885,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
},
"test_SCRIPT_INT": {
    "description": "",
    "type": "model",
    "version": 1,
    "dependencies": [],
    "target": null,
    "creation_time": 1626686886,
    "last_modified_time": 1626686886,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
},
"test_SCRIPT_REAL": {
    "description": "",
    "type": "model",
    "version": 1,
    "dependencies": [],
    "target": null,
    "creation_time": 1626686886,
    "last_modified_time": 1626686886,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
},
"test_SCRIPT_STR": {
    "description": "",
    "type": "model",
    "version": 1,
    "dependencies": [],
    "target": null,
    "creation_time": 1626686886,
    "last_modified_time": 1626686886,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
}

Tableau Desktop 呼叫

修改工作簿中 4 個與 SCRIPT 函式有關的 Calculated Field

銷售額大於10000

SCRIPT_BOOL("return tabpy.query('test_SCRIPT_BOOL', _arg1)['response']", SUM([Sales]))

2倍銷售額

SCRIPT_INT("return tabpy.query('test_SCRIPT_INT', _arg1)['response']", SUM([Sales]))

銷售額平方根

SCRIPT_REAL("return tabpy.query('test_SCRIPT_REAL', _arg1)['response']", SUM([Sales]))

銷售額說明

SCRIPT_STR("return tabpy.query('test_SCRIPT_STR', _arg1, _arg2)['response']"
, SUM([Sales]), ATTR([State]))

此時的效果就與 [Day24] Tableau 輕鬆學 - TabPy 使用方法 1 的效果是一樣的,只是使用 Python 的方式不同而已。

覆蓋與移除 Model

當我們想要直接重新佈署已經存在的 Model,會出現錯誤訊息如下,大意是說已經有相同名稱的 Model 存在

RuntimeError: An endpoint with that name (test_SCRIPT_BOOL) already exists. Use "override = True" to force update an existing endpoint.

這時候我們有兩個方法讓佈署能夠成功,一個方法是直接覆蓋掉現有的 Model,另一個方法則是先移除現存的 Model 再行佈署。

覆蓋 Model

只需在 client.deploy 加上 override 參數,允許它可以覆蓋現有的 Model

client.deploy('test_SCRIPT_BOOL', testBool, 'Test SCRIPT_BOOL by deployment', override=True)

覆蓋後,若仔細觀察 Deployed Models 中的 test_SCRIPT_BOOL,會看到它的 version 變為 2,這是因為每次覆蓋會造成版次自動加 1

"test_SCRIPT_BOOL": {
    "description": "Test SCRIPT_BOOL by deployment",
    "type": "model",
    "version": 2,
    "dependencies": [],
    "target": null,
    "creation_time": 1626686885,
    "last_modified_time": 1626696002,
    "schema": null,
    "docstring": "-- no docstring found in query function --"
},

移除 Model

client.deploy 之前先呼叫移除 Model 的函式便能將 Model 名稱空出來,避免 Model 撞名導致無法佈署

client.remove('test_SCRIPT_BOOL')

結語

這裡介紹的 TabPy 使用方法讓我們可以集中管理 Python 程式碼,使工作簿可以共用相同的函式。但這種方法不容易得知有哪些工作簿使用到對應的 Model,無法快速知道若將 Model 進行更新對應需要修改的工作簿有哪些。我個人認為兩種 TabPy 方法可以並行採用,若程式碼不會被重複使用,可以考慮直接寫在工作簿內,而會被重複使用的程式碼還是以佈署的方式為主,維護上會比較方便。

工作簿原始檔案

完成的工作簿

在實作中遇到困難是難免的,這裡提供原始檔作為參考,若仍然無法解決歡迎至下方討論區留言。


上一篇
[Day24] Tableau 輕鬆學 - TabPy 使用方法 1
下一篇
[Day26] Tableau 輕鬆學 - TabPy 開發流程
系列文
Tableau 輕鬆學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言