本文說明在 Spanner Graph 上執行演算法的最佳做法。涵蓋下列主題:
演算法適用的圖表結構定義最佳做法
如果您在 Spanner Graph 中使用了自訂標籤和屬性,建議一律將元素鍵公開為屬性。這樣一來,您就能在演算法查詢的 RETURN 子句中存取這些鍵屬性,並使用這些屬性找出演算法產生輸出內容的圖表元素。
處理演算法輸出內容
本節將說明演算法輸出內容的傳回建議,以及傳回結果的保存位置。
需退回的項目
如果演算法的輸出簽章包含圖表元素,Spanner Graph 可讓您傳回這些元素的任何屬性。為降低處理成本,建議您盡量減少要傳回的屬性清單。舉例來說,只傳回元素的鍵屬性,因為鍵是識別元素時的必要條件。
保留位置
Spanner Graph 支援將演算法查詢結果保留在 Cloud Storage 中,或保留在您啟動查詢的相同 Spanner Graph 執行個體中。
將資料存回 Spanner 後,所有 Spanner 作業都能以原生方式存取演算法輸出內容。舉例來說,您可以執行 WeaklyConnectedComponent,將 cluster_id 持久儲存回圖表。隨後,針對具有特定 cluster_id 的輸入圖表執行 PageRank。
Spanner 的變更串流等功能會將新演算法輸出內容傳播至下游系統。如要在 Spanner 中使用演算法輸出內容,建議將內容保留在 Spanner 中。雖然 Spanner Graph 會以有效率的方式批次處理演算法輸出內容,並將其保存至 Spanner,但所有寫入作業都必須透過相同的領導者副本。如果重要工作負載已佔用領導者容量,建議您錯開演算法執行時間,避免與重要工作負載競爭。
如果您不打算在 Spanner 中使用演算法輸出內容,或想在將演算法輸出內容擷取至主要資料來源前進行評估,請考慮將輸出內容保存至 Cloud Storage。請參閱支援的檔案格式。
擴增圖表的資料模型注意事項
本節將討論將演算法輸出內容保存至 Spanner 時,需要考量的一些資料模型。
屬性與邊緣
演算法可產生各種洞察資料,包括:
- 節點層級指標 (例如中心度分數)。這些屬性可以保留為節點上的新屬性。
- 成對洞察 (例如兩個節點之間的相似度)。這些值可以做為兩個節點之間的新邊緣,並以邊緣屬性形式保存輸出值。
- 社群偵測演算法會找出圖表中的邏輯社群,並將一或多個社群指派給特定節點。您可以將社群成員資格視為節點上的新屬性,方法是為每個成員節點標記其所屬社群的 ID。您也可以將社群成員資格建模為新的子圖,並將邏輯社群儲存為圖中的新型節點,邊緣會將這些節點連結至成員節點。如果您想在存取節點時瞭解節點所屬的社群,社群屬性可能就已足夠。如要依社群瀏覽 (例如尋找與起始節點位於同一社群的節點),社群子圖可能更適合。視您打算運用社群資訊的方式而定,您可以選擇其中一項或兩項。
預先定義的結構定義與彈性結構定義
將演算法輸出內容保留回 Spanner 之前,請透過下列任一方式,在結構定義中定義目的地資料欄或資料表:
- 如果演算法的使用情境穩定且已知,您可以預先新增其他資料欄或表格。
- 如果您要疊代及實驗不同的洞察資料擷取方式 (例如嘗試不同的演算法、參數、輸入子圖),您可能需要彈性的方式來保存及區分多項實驗的輸出內容,而不必為每次執行更新 Spanner 結構定義。在這種情況下,您可以考慮將演算法產生的新屬性和邊緣儲存在一般子資料表中。
如要將演算法產生的新屬性和邊緣儲存在一般子資料表中,請按照下列步驟操作:
步驟 1:建立一般子表格
-- Create `AccountAlgoProperty` as a child table of `Account`, to store all
-- properties produced by algorithms for `Account`.
-- `algo_run_id`: a unique ID for a given algorithm run.
-- `int_val`: column to store integer algorithm output.
-- `float_val`: column to store float algorithm output.
CREATE TABLE AccountAlgoProperty (
id INT64 NOT NULL,
algo_run_id STRING(200) NOT NULL,
int_val INT64,
float_val FLOAT64
) PRIMARY KEY(id, algo_run_id),
INTERLEAVE IN PARENT Account;
-- Create `AccountAlgoEdge` as a child table of `Account`, to store all
-- outgoing edges produced by algorithms for `Account`.
-- `algo_run_id`: a unique ID for a given algorithm run.
-- `to_id`: destination `Account` id.
-- `int_val`: column to store integer algorithm output.
-- `float_val`: column to store float algorithm output.
CREATE TABLE AccountAlgoEdge (
id INT64 NOT NULL,
algo_run_id STRING(200) NOT NULL,
to_id INT64 NOT NULL,
int_val INT64,
float_val FLOAT64,
CONSTRAINT FK_AccountId FOREIGN KEY (to_id) REFERENCES Account (id) NOT ENFORCED,
) PRIMARY KEY(id, algo_run_id, to_id),
INTERLEAVE IN PARENT Account;
步驟 2:將演算法產生的屬性和邊緣儲存為子項資料表列,以及產生這些屬性和邊緣的專屬 algo_run_id。
-- Store PageRank score as property in child table.
EXPORT DATA
OPTIONS (format = "CLOUD_SPANNER",
table = "AccountAlgoProperty",
write_mode = 'upsert_ignore_all' ) AS
GRAPH FinGraph
CALL PageRank(node_labels => ['Account'], edge_labels => ['Transfers'])
RETURN node.id, "page_rank_123" AS algo_run_id, score As float_val;
-- Store ShortestPath output as edge in child table.
EXPORT DATA
OPTIONS (format = "CLOUD_SPANNER",
table = "AccountAlgoEdge",
write_mode = 'upsert_ignore_all' ) AS
GRAPH FinGraph
CALL ShortestPath(
source_nodes => ARRAY {
MATCH (n:Account {id: 7})
RETURN n
},
target_nodes => ARRAY {
MATCH (n:Account {id: 16})
RETURN n
}
) YIELD source_node, target_node, path, cost
RETURN source_node.id AS id, "shortest_path_456" AS algo_run_id,
target_node.id AS to_id, PATH_LENGTH(path) AS int_val, cost AS float_val;
步驟 3:使用 GRAPH_TABLE 存取演算法輸出內容
SELECT acct.id, prop.float_val AS page_rank_score
FROM GRAPH_TABLE(
FinGraph
MATCH (n:Account)
RETURN n.id
) acct JOIN AccountAlgoProperty prop ON acct.id = prop.id
AND prop.algo_run_id = 'page_rank_123';
SELECT acct.id, edge.to_id, edge.int_val AS path_len, edge.float_val AS cost
FROM GRAPH_TABLE(
FinGraph
MATCH (n:Account)
RETURN n.id
) acct JOIN AccountAlgoEdge edge ON acct.id = edge.id
AND edge.algo_run_id = 'shortest_path_456';
步驟 4:(選用) 建立以演算法產生的屬性和邊緣擴增的邏輯圖表,方便存取演算法輸出內容。
-- Create a view that aggregates non-null algorithm properties per node into
-- name-value pairs in JSON.
CREATE OR REPLACE VIEW AccountWithAlgoProperties SQL SECURITY INVOKER AS
SELECT
n.id, ANY_VALUE(n.create_time) AS create_time,
ANY_VALUE(n.is_blocked) AS is_blocked, ANY_VALUE(n.nick_name) AS nick_name,
JSON_OBJECT(
IF(COUNT(c.algo_run_id) = 0, [], ARRAY_AGG(c.algo_run_id)),
IF(COUNT(c.algo_run_id) = 0, [], ARRAY_AGG(
COALESCE(
IF (c.int_val IS NULL, NULL, TO_JSON(c.int_val)),
IF (c.float_val IS NULL, NULL, TO_JSON(c.float_val))
)))) AS algo_props
FROM Account AS n LEFT JOIN AccountAlgoProperty AS c ON n.id = c.id
GROUP BY n.id;
-- Create FinGraphAugmented with algorithm generated properties and edges.
CREATE OR REPLACE PROPERTY GRAPH FinGraphAugmented
NODE TABLES (
AccountWithAlgoProperties AS Account
KEY(id)
LABEL Account PROPERTIES(
create_time,
id,
is_blocked,
nick_name,
algo_props),
Person
)
EDGE TABLES (
PersonOwnAccount
SOURCE KEY (id) REFERENCES Person (id)
DESTINATION KEY (account_id) REFERENCES Account (id)
LABEL Owns,
AccountTransferAccount
SOURCE KEY (id) REFERENCES Account (id)
DESTINATION KEY (to_id) REFERENCES Account (id)
LABEL Transfers,
AccountAlgoEdge
SOURCE KEY (id) REFERENCES Account (id)
DESTINATION KEY (to_id) REFERENCES Account (id)
);
然後直接存取演算法屬性,並在圖形查詢中瀏覽演算法產生的邊緣:
-- Retrieve PageRank score property in graph query.
GRAPH FinGraphAugmented
MATCH (a:Account)
RETURN a.id, a.algo_props.page_rank_123 AS page_rank
ORDER BY page_rank DESC
LIMIT 5;
-- Navigate through ShortestPath edge in graph query.
GRAPH FinGraphAugmented
MATCH (s:Account {id: 7})-[e:AccountAlgoEdge {algo_run_id : 'shortest_path_456'}]->(d:Account)
RETURN s.id AS src, d.id AS dst, e.int_val AS path_len, e.float_val AS cost
針對大型工作負載指定 machine_category
對於大多數工作負載,default machine_category 都很合適。如果輸入圖形有超過 10 億個節點和超過 100 億條邊緣,建議您明確選擇 large 做為 machine_category。
重複使用運算資源,加快疊代速度
如果您要對小型資料集進行不同演算法或不同輸入參數的實驗,以便快速疊代,建議使用 max_idle_time。較大的 max_idle_time Spanner Graph 可讓您重複使用已為更多演算法工作負載佈建的運算資源。這可減少隨選運算冷啟動的負擔,並降低因暫時缺乏容量而無法佈建運算的風險。請注意,演算法運算閒置時仍會計費。
區分輸出內容中的元素類型
如果演算法輸出內容包含多種元素類型,您可能會想在輸出內容中加入 ELEMENT_DEFINITION_NAME,以便區分這些類型。例如:
EXPORT DATA OPTIONS (
uri = "gs://bucket-name/page_rank.csv",
format = "csv",
overwrite = TRUE) AS
GRAPH FinGraph
CALL PageRank()
YIELD node, score
RETURN ELEMENT_DEFINITION_NAME(node) AS node_type, node.id, score;