2015-04-03 43 views
2

我正在Neo4j 2.0.4中編寫一個Cypher查詢,它試圖獲取選定節點的入站和出站關係的總數。當我只能用這個查詢一個節點 - 在 - 一時間,像這樣我可以很容易地做到這一點:使用與多個子句匹配導致奇數結果

MATCH (g1:someIndex{name:"name1"}) 
MATCH g1-[r1]-() 
RETURN count(r1); 
//Returns 305 

MATCH (g2:someIndex{name:"name2"}) 
MATCH g2-[r2]-() 
RETURN count(r2); 
//Returns 2334 

但是當我嘗試運行與2個節點查詢到一起(即獲得總數g1和g2的關係),我似乎得到了一個奇怪的結果。

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 
//Returns 1423740 

由於某些原因,這個數量遠遠大於305 + 2334的總數。

好像其他Neo4j的用戶已經使用多個MATCH條款時遇到奇怪的問題,所以我通讀邁克爾飢餓的在https://groups.google.com/d/msg/neo4j/7ePLU8y93h8/8jpuopsFEFsJ解釋,勸告Neo4j的用戶管使用WITH一場比賽的結果,以避免「標識的唯一性」 。然而,當我運行下面的查詢,它只是超時:

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"}) 
MATCH g1-[r1]-() 
WITH r1 
MATCH g2-[r2]-() 
RETURN count(r1)+count(r2); 

我懷疑這查詢不回來,因爲有通過r1返回了很多紀錄。在這種情況下,我將如何操作2個節點上的「關係獲取數量」查詢?我只是使用了一些不正確的語法,或者是我的「2節點一次」查詢的邏輯有一些基本問題?

回答

3

你的第一個問題是,當你做,你正在返回笛卡爾積這樣的:

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 

如果存在的r1 305個實例,並且,你回來的r2 2334個實例(305 * 2334)= = 711870行,因爲你正在總結這(count(r1)+count(r2))你得到一共有711870 + 711870 = = 1423740.

你的第二個問題是,你是不是該查詢的WITH子句中結轉g2

MATCH (g1:gene{name:"SV422_HUMAN"}),(g2:gene{name:"BRCA1_HUMAN"}) 
MATCH g1-[r1]-() 
WITH r1 
MATCH g2-[r2]-() 
RETURN count(r1)+count(r2); 

g2第一MATCH子句中的匹配,但後來你離開它後面時,你只在第3行然後WITH子句中結轉r1,在第4行,當你在g2-[r2]-()符合您所匹配從字面上看你的圖中的所有內容,因爲g2已被解除綁定。

讓我使用Neo4j瀏覽器附帶的電影數據集解決問題,因爲您尚未提供示例數據。假設我想獲得湯姆漢克斯和雨果織造的關係總數。

作爲單獨的查詢:

MATCH (:Person {name:'Tom Hanks'})-[r]-() 
RETURN COUNT(r) 

=> 13

MATCH (:Person {name:'Hugo Weaving'})-[r]-() 
RETURN COUNT(r) 

=> 5

如果我嘗試做你的方式,我會得到(13 * 5) * 2 == 90,這是不正確的:

MATCH (:Person {name:'Tom Hanks'})-[r1]-(), 
     (:Person {name:'Hugo Weaving'})-[r2]-() 
RETURN COUNT(r1) + COUNT(r2) 

=> 90

同樣,這是因爲我在r1r2的所有組合中匹配,其中有65個(13 * 5 == 65),然後將其總和,得出總數爲90(65 + 65 == 90)。

的解決方案是使用DISTINCT

MATCH (:Person {name:'Tom Hanks'})-[r1]-(), 
     (:Person {name:'Hugo Weaving'})-[r2]-() 
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2) 

=> 18

顯然,DISTINCT改性劑只計算每個實體的不同實例。

您還可以WITH做到這一點,如果你想:

MATCH (:Person {name:'Tom Hanks'})-[r]-() 
WITH COUNT(r) AS r1 
MATCH (:Person {name:'Hugo Weaving'})-[r]-() 
RETURN r1 + COUNT(r) 

=> 18

TL; DR - 當心笛卡爾產品。 DISTINCT是你的朋友:

MATCH (:someIndex{name:"name1"})-[r1]-(), 
     (:someIndex{name:"name2"})-[r2]-() 
RETURN COUNT(DISTINCT r1) + COUNT(DISTINCT r2); 
+0

謝謝妮可!我不知道我目前的查詢是使用交叉產品;這使得現在更有意義。 – 2015-04-03 16:42:44

3

你看到可以很容易得出的爆炸解釋說:

MATCH (g1:someIndex{name:"name1"}), (g2:someIndex{name:"name2"}) 
MATCH g1-[r1]-(), g2-[r2]-() 
RETURN count(r1)+count(r2); 
//Returns 1423740 

在2號線從g1任何關係的每個組合與g2任何關係結合,這解釋了自1423740 = 305 * 2334 * 2以來的數字。所以你在這裏基本上評估了一個交叉產品。

計算所有關係的總和name1name2正確的做法是:

MATCH (g:someIndex)-[r]-() 
WHERE g.name in ["name1", "name2"] 
RETURN count(r) 
+0

謝謝Stefan!這現在有道理。 +1 – 2015-04-03 20:45:55