簡體   English   中英

Neo4j Cypher查詢查找未連接的節點太慢

[英]Neo4j Cypher query to find nodes that are not connected too slow

鑒於我們有以下Neo4j架構(簡化但它顯示了重要的一點)。 有兩種類型的節點NODEVERSION VERSION通過VERSION_OF關系連接到NODE VERSION節點都具有兩個屬性fromuntil該表示的有效性時間跨度-一方或雙方可NULL (在Neo4j的條件不存在)表示無限 NODE可以通過HAS_CHILD關系連接。 同樣,這些關系具有兩個屬性fromuntil該表示的有效性時間跨度-一方或雙方可NULL (在Neo4j的條件不存在)表示無限

編輯VERSION節點和HAS_CHILD關系的有效日期是獨立的(即使示例巧合地顯示它們是對齊的)。

在此輸入圖像描述

該示例顯示了兩個NODE AB. A有兩個VERSION s AV1直到6/30/17和AV2從7/1/17開始,而B只有一個版本BV1無限制。 B通過HAS_CHILD關系連接到A ,直到6/30/17。

現在的挑戰是在一個特定時刻查詢所有不是節點(即根節點)的節點。 鑒於上面的例子中,查詢應該返回剛才b。如果查詢日期,例如17年6月1日,但它應該返回BA,如果查詢的日期是如17年8月1日(因為A是不是一個孩子B截至7/1/17更多)。

今天的當前查詢大致類似於那個:

MATCH (n1:NODE)
OPTIONAL MATCH (n1)<-[c]-(n2:NODE), (n2)<-[:VERSION_OF]-(nv2:ITEM_VERSION)
WHERE (c.from <= {date} <= c.until)
AND (nv2.from <= {date} <= nv2.until)
WITH n1 WHERE c IS NULL 
MATCH (n1)<-[:VERSION_OF]-(nv1:ITEM_VERSION)
WHERE nv1.from <= {date} <= nv1.until
RETURN n1, nv1 
ORDER BY toLower(nv1.title) ASC 
SKIP 0 LIMIT 15

這個查詢通常工作得相對較好,但是當它用在大型數據集上時(與真實的生產數據集相比),它開始變慢。 使用20-30k NODE (大約是VERSION的兩倍),(實際)查詢在Mac OS X上運行的小型docker容器上大約需要500-700 ms),這是可以接受的。 但是使用1.5M NODE (並且大約是VERSION的兩倍),(真實的)查詢在裸機服務器上運行時間超過1分鍾(除了Neo4j之外別無其他)。 這不是真的可以接受。

我們可以選擇調整此查詢嗎? 是否有更好的方法來處理NODE的版本控制(我懷疑這里是性能問題)還是關系的有效性? 我知道關系屬性無法編入索引,因此可能有更好的模式來處理這些關系的有效性。

非常感謝任何幫助甚至是絲毫的暗示。

邁克爾·亨格回答后編輯:

  1. 根節點的百分比:

    使用當前示例數據集(1.5M節點),結果集包含大約2k行。 那不到1%。

  2. 第一個MATCH ITEM_VERSION節點:

    我們使用的ITEM_VERSION nv2來篩選結果集ITEM有沒有聯系其他節點ITEM在給定的時間節點。 這意味着要么不存在對於給定日期有效的關系,要么連接的項目不能具有對給定日期有效的ITEM_VERSION 我試圖說明這一點:

     // date 6/1/17 // n1 returned because relationship not valid (nv1 ...)->(n1)-[X_HAS_CHILD ...6/30/17]->(n2)<-(nv2 ...) // n1 not returned because relationship and connected item n2 valid (nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...) // n1 returned because connected item n2 not valid even though relationship is valid (nv1 ...)->(n1)-[X_HAS_CHILD ...]->(n2)<-(nv2 ...6/30/17) 
  3. 不使用關系類型:

    這里的問題是該軟件具有用戶定義的模式, ITEM節點通過自定義關系類型連接。 由於我們不能在關系上有多個類型/標簽,這種關系的唯一共同特征是它們都以X_開頭。 這里沒有簡化的例子。 使用謂詞type(r) STARTS WITH 'X_'幫助嗎?

你正在使用什么Neo4j版本。

在您的示例日期,您的1.5M節點中有多少百分比將作為根發現,如果您沒有限制,那么有多少數據會返回? 也許這個問題不是在匹配中,而是在最后的排序中?

我不確定為什么你的第一部分中有VERSION節點,至少你沒有將它們描述為確定根節點的相關性。

你沒有使用關系類型。

MATCH (n1:NODE) // matches 1.5M nodes
// has to do 1.5M * degree optional matches
OPTIONAL MATCH (n1)<-[c:HAS_CHILD]-(n2) WHERE (c.from <= {date} <= c.until)
WITH n1 WHERE c IS NULL
// how many root nodes are left?
// # root nodes * version degree (1..2)
MATCH (n1)<-[:VERSION_OF]-(nv1:ITEM_VERSION)
WHERE nv1.from <= {date} <= nv1.until
// has to sort all those
WITH n1, nv1, toLower(nv1.title) as title
RETURN n1, nv1
ORDER BY title ASC 
SKIP 0 LIMIT 15

我認為改進的良好開端是使用索引匹配節點,這樣您就可以快速獲得較小的相關節點子集進行搜索。 您現在的方法必須每次都檢查您的所有:NODE以及它們之間的所有關系和模式,正如您所發現的那樣,它們不會隨您的數據而擴展。

現在,圖中唯一具有日期/時間屬性的節點是:ITEM_VERSION節點,所以讓我們從這些節點開始。 您將需要一個索引:ITEM_VERSION的from和until屬性用於快速查找。

空值對於查找會有問題,因為任何針對空值的不等式都會返回null,並且大多數使用空值的變通方法(使用COALESCE()或多個AND / OR用於空案例)似乎會阻止使用索引查找,這是我特別建議的要點。

我鼓勵你用min和max值替換你的null,直到min和max值,這可以讓你利用索引查找來查找節點:

MATCH (version:ITEM_VERSION)
WHERE version.from <= {date} <= version.until
MATCH (version)<-[:VERSION_OF]-(node:NODE)
...

這應該至少可以在開始時快速訪問較小的節點子集以繼續查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM