篩選可以將結果縮小到重要的欄位。 聚合會將這些數據列彙整成計數、總數和平均值。 本文將示範如何在 Microsoft Fabric 中的 GQL 查詢中應用這兩種技術於圖形資料上。
範例中使用社群網路範例資料集。 關於查詢流程與語句的端對端說明,請參閱 GQL 語言指南。
本文可用於列與模式篩選、群組與非群組聚合、聚合特定篩選及條件路由。 關於構建多跳模式及選擇路徑,請參見 撰寫圖模式查詢。 關於即用的商業任務,請參見 撰寫常見的 GQL 查詢。
先決條件
使用 FILTER 篩選資料列
請使用 FILTER 來保留符合條件的行。 在FILTER後放置MATCH以縮小匹配結果。
以下查詢會回傳所有女性的姓名和生日:
MATCH (p:Person)
FILTER p.gender = 'female'
RETURN p.firstName, p.lastName, p.birthday
將多個條件與AND和OR結合。 例如,以下查詢會回傳1990年前出生的所有女性姓名:
MATCH (p:Person)
FILTER p.gender = 'female' AND p.birthday < 19900101
RETURN p.firstName, p.lastName
Tip
當條件定義哪個節點或邊可以參與比對時,請使用行內 WHERE 子句。 當條件適用於先前陳述所產生的列時,該條件會被使用 FILTER 。 謂詞的擺放可能會改變最短路徑的結果;參見 「在路徑選擇前或之後放置謂詞」。
模式匹配時的過濾器
WHERE 模式中的內嵌 MATCH 子句會限制哪些節點和邊可符合比對條件。 查詢優化器可以在掃描時套用等效的述詞,因此內嵌語法本質上並不比獨立的 FILTER 子句更快。 選擇能表達預期語意的形式。
例如,要找出1994年前出生的人及其所在公司,並將結果限制為名稱以「A」開頭的公司:
MATCH (p:Person WHERE p.birthday < 19940101)-[:workAt]->(c:Company WHERE c.name STARTS WITH 'A')
RETURN p.firstName, p.lastName, c.name
過濾邊緣屬性也是用同樣方式。 例如,只回放2000年或之後開始在公司工作的人員:
MATCH (p:Person)-[w:workAt WHERE w.workFrom >= 2000]->(c:Company)
RETURN p.firstName, p.lastName, c.name, w.workFrom
欲了解更多關於選擇內嵌過濾與後配對篩選的資訊,請參閱 優化 GQL 查詢效能。
在濾波器中處理空值
GQL 採用三值邏輯:謂詞評估結果為 TRUE、FALSE 或 UNKNOWN。 當屬性值為零時,比較會回傳 UNKNOWN。
FILTER 會 UNKNOWN 被視為不匹配,因此該列被排除。
使用 IS NULL 和 IS NOT NULL 明確測試空值:
-- Only include people whose browser is known
MATCH (p:Person)
FILTER p.browserUsed IS NOT NULL
RETURN p.firstName, p.browserUsed
當屬性可能為空時,請用 coalesce() 替換預設值:
MATCH (p:Person)
RETURN p.firstName, coalesce(p.browserUsed, 'Unknown browser') AS browser
Caution
NULL = NULL 評估為 UNKNOWN,不是 TRUE。 一定要用 IS NULL 來測試空值,而不是等式。
使用 RETURN 取得綜合結果
使用總和函數在RETURN中總結你的結果。 圖支援以下彙總函數:COUNT、、AVGSUM、 COLLECT_ONEMINMAXCOLLECT_LISTCOLLECT_ELEMENTS和 。
例如,計算圖表中的所有人數:
MATCH (p:Person)
RETURN count(*) AS totalPeople
為了計算不同價值,例如有多少家不同公司雇用了員工:
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN count(DISTINCT c) AS companyCount
單一彙總的篩選輸入
在聚合後加 FILTER (WHERE predicate) 法,只過濾該聚合的輸入。 同一 RETURN 組的其他聚合體仍會接收所有輸入列。
MATCH (p:Person)
RETURN count(*) AS allPeople,
count(*) FILTER (WHERE p.birthday < 19900101) AS peopleBornBefore1990
在彙總篩選器中加入 LIMIT,以最多使用該數量的符合條件資料列。 查詢在集合特定限制之前套用謂詞。
MATCH (p:Person)
RETURN count(*) FILTER (WHERE p.birthday < 19900101 LIMIT 100) AS sampleCount
彙總專用的 FILTER 和 LIMIT 不會從查詢的其餘部分移除資料列。 當你想篩選列串流時,可以使用 FILTER 陳述句或匹配層級 WHERE 子句。
收集價值
使用 COLLECT_LIST 為每個輸入值傳回一個清單元素,包括 null 值。 新增 DISTINCT 以移除重複內容。
MATCH (p:Person)
RETURN collect_list(DISTINCT p.browserUsed) AS browsers
COLLECT_ONE 回傳一個非空輸入值。 所選值並非確定性,因此只有在群組中任一值都可接受時才使用。
COLLECT_ELEMENTS 接受列表值輸入,並將其元素串接成一個列表:
MATCH (p:Person)
RETURN collect_elements([p.firstName, p.lastName]) AS names
若沒有分組欄位,則在沒有輸入資料列時,彙總查詢會從 COLLECT_ELEMENTS 和 COLLECT_LIST 傳回空清單,並從 COLLECT_ONE 傳回 null。
使用 GROUP BY 來分組結果
使用 GROUP BY 並在 RETURN 中按共享值為資料列分組,然後在每個群組內計算彙總數據。 此群組即為 GQL 中相當於 SQL GROUP BY的 。
例如,計算每家公司員工數:
MATCH (p:Person)-[:workAt]->(c:Company)
LET companyId = c.id, companyName = c.name
RETURN companyId, companyName, count(*) AS employeeCount
GROUP BY companyId, companyName
ORDER BY employeeCount DESC
依多欄分組,並同時計算多個聚合。 例如,將人數和生日範圍依性別和瀏覽器分類,回傳 10 種最常見的組合:
MATCH (p:Person)
LET gender = p.gender
LET browser = p.browserUsed
RETURN gender,
browser,
count(*) AS personCount,
min(p.birthday) AS earliestBirthday,
max(p.birthday) AS latestBirthday
GROUP BY gender, browser
ORDER BY personCount DESC
LIMIT 10
Note
所有非 RETURN 聚合表達式必須出現在 GROUP BY中。 不在 GROUP BY 中的表達式必須使用聚合函數。
排序並限制彙總結果
使用 ORDER BY 和 LIMIT 搭配 GROUP BY 來尋找前N名的結果。
例如,要找到依居民數量排名前五的城市:
MATCH (p:Person)-[:isLocatedIn]->(city:City)
LET cityId = city.id, cityName = city.name
RETURN cityId, cityName, count(*) AS residentCount
GROUP BY cityId, cityName
ORDER BY residentCount DESC
LIMIT 5
這很重要
將ORDER BY放在LIMIT之前。
LIMIT 總是適用於已排序的結果集。
以條件語句路由列
使用條件語句將每個輸入的列路由到第一個匹配的分支。 輸入可以來自任何前置查詢階段,而不僅僅是聚合。 例如,以下查詢是在計算員工人數後對公司進行分類:
MATCH (p:Person)-[:workAt]->(c:Company)
LET companyId = c.id, companyName = c.name
RETURN companyId, companyName, count(*) AS employeeCount
GROUP BY companyId, companyName
NEXT
WHEN employeeCount >= 100u THEN
RETURN companyId, companyName, employeeCount, 'Large' AS category
WHEN employeeCount >= 10u THEN
RETURN companyId, companyName, employeeCount, 'Medium' AS category
ELSE
RETURN companyId, companyName, employeeCount, 'Small' AS category
分支可以執行完整的查詢語句和巢狀程序,而不只是回傳表達式。 以下範例會讓三列輸入資料通過不同的分支結構。 其中一個分支執行 MATCH,另一個分支使用 UNION ALL 將兩個彙總結果合併,然後再彙總合併後的結果,而備援分支則回傳一個常數:
FOR selector IN [1, 2, 3]
RETURN selector
NEXT
WHEN selector = 1 THEN
MATCH (:Person)-[:knows]->(:Person)
RETURN count(*) AS total, 'Knows edges' AS category
WHEN selector = 2 THEN {
MATCH (:Person)-[:workAt]->(:Company)
RETURN count(*) AS partialCount
UNION ALL
MATCH (:Person)-[:studyAt]->(:University)
RETURN count(*) AS partialCount
NEXT
RETURN sum(partialCount) AS total, 'Affiliation edges' AS category
}
ELSE
RETURN 0u AS total, 'No selected metric' AS category
查詢引擎會依序評估每列的謂詞。 它只會執行第一個符合條件的分支。 若謂詞評估為 UNKNOWN,則評估會延續到下一個分支。 若沒有 ELSE,不符合 WHEN 分支的資料列會被省略。
條件語句與 CASE 表達式不同。 Graph 支援用於根據相等性選取值的簡單 CASE <expression> WHEN <value> 運算式。 搜尋表達式 CASE WHEN <predicate> 不受支援。 欲了解更多資訊,請參閱 條件語句。