2016-10-30 62 views
1

我正在嘗試創建一組關係,其中Foo是'IN'Bar的一系列時間範圍。neo4j CREATE UNIQUE看起來很慢

我的基本的查詢看起來是這樣的:

MERGE (f:Foo {id: 123}) 
MERGE (b111:Bar {id: 111}) 
CREATE UNIQUE (f) - [:IN { from:130958270580000000, to: 130958975440000000 } ] -> (b111) 

此功能不正是我之後我,但我可以添加創建語句的查詢變得非常緩慢。循環這個聲明也很慢。

如:

MERGE (f:Foo {id: 123}) 
MERGE (b111:Bar {id: 111}) 
MERGE (b222:Bar {id: 222}) 
CREATE UNIQUE (f) - [:IN { from:130958270580000000, to: 130958975440000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130954640800000000, to: 130954728070000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130954563680000000, to: 130954563920000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130954559880000000, to: 130954559900000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130954557300000000, to: 130954559300000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130954556860000000, to: 130954557100000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130953825060000000, to: 130954554060000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130953080610000000, to: 130953807160000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130948659890000000, to: 130952852200000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130947989650000000, to: 130948493470000000 } ] -> (b111) 
CREATE UNIQUE (f) - [:IN { from:130947129060000000, to: 130947675200000000 } ] -> (b222) 

例如,如果我創建400個關係,這樣就需要23S

我跑天寒以上,它看起來就像是做了很多分貝的命中率爲本聲明(158毫秒總共586分貝命中),這似乎很奇怪。這似乎隨​​着我添加更多的CREATE語句而呈指數增長。

我曾嘗試給Foo和Bar添加索引,但它們似乎沒有任何區別。

我是neo4j的超級新手,所以我可能在做一些愚蠢的事情或在某處作出錯誤的假設,但是我無法弄清楚爲什麼這個查詢應該如此緩慢。

回答

3

減速與節點上的匹配不匹配,它來自您的關係上的CREATE UNIQUE(MERGE也會遭受同樣的緩慢)。它所涉及的是neo4j中的非索引屬性訪問可能很昂貴。

關係中沒有索引,所以任何CREATE UNIQUE或MERGE操作都像上面的那樣必須掃描該類型的所有關係並比較屬性值以查看該關係是否已存在。顯然,成本會隨着當前類型關係的數量而增長。

有幾種方法可以緩解這種情況。

如果您知道這些與這些特定屬性的關係尚不存在的事實,只需使用CREATE而不是CREATE UNIQUE即可。你可以運行一個查詢來檢查你的關係創建的結尾,如果你在任何地方欺騙並且有可以刪除的副本。

另一種方法是調整模型。而不是讓關係本身具有屬性,請在Foo和:Bar節點之間創建一個自己的標籤的中間節點,並使用它來保持您的屬性。您需要對這些屬性進行索引以避免MERGE或CREATE UNIQUE變慢。

我建議有一箇中間節點,特別是如果您打算使用涉及這些時間屬性的查詢,以及是否存在其中的很多問題。如果這些屬性只存在於關係中,則無法利用索引來加快查詢速度,這可能會在以後出現問題。

編輯

的中間節點的用法可能是這樣的(假設上的索引:Foobar的(從)和:Foobar的(地)):

MERGE (f:Foo {id: 123}) 
MERGE (f2:Foo {id: 456}) 
MERGE (b111:Bar {id: 111}) 
MERGE (b222:Bar {id: 222}) 
MERGE (f) - [:IN] -> (fb:Foobar{ from:130958270580000000, to: 130958975440000000 }) 
MERGE (fb) - [:IN] -> (b111) 
WITH f, f2, b111, b222 
// merge with same :Foobar values on f2...should create a new node 
// instead of reusing the one attached to f. 
MERGE (f2) - [:IN] -> (fb:Foobar{ from:130958270580000000, to: 130958975440000000 }) 
MERGE (fb) - [:IN] -> (b111) 
WITH f, f2, b111, b222 
MERGE (f) - [:IN] -> (fb:Foobar{ from:130954640800000000, to: 130954728070000000 }) 
MERGE (fb) - [:IN] -> (b111) 
WITH f, f2, b111, b222 
MERGE (f) - [:IN] -> (fb:Foobar{ from:130954563680000000, to: 130954563920000000 }) 
MERGE (fb) - [:IN] -> (b111) 
... 

當然,你可能需要重命名關係和標籤更合理,如果可能的話。

使用,這可能是這樣的查詢:

// find which :Bar f was in at a particular instance 
WITH {params.instance} as instance 
MATCH (f:Foo {id: 123})-[:IN]->(fb:Foobar) 
WHERE fb.from <= instance <= fb.to 
WITH fb 
MATCH (fb)-[:IN]->(b:Bar) 
RETURN b 

EDIT改變的插入查詢強制執行的唯一性:Foobar的節點至相應的:富節點,這將防止MERGE從上現有的匹配:Foobar節點已被另一個使用:Foo。

+0

謝謝,這很有道理。我嘗試將它改爲CREATE(沒有唯一的),但它對時代基本沒有影響。關於將其分割爲單獨的節點,我認爲我不能輕易地做到這一點,實際的唯一性就是這種關係(例如foo:1在這兩個時間間隔內爲2)。我不能想出任何明智地將它分解成新節點的方法嗎?我認爲在新實體的foo和bar上添加一些標識符以提供唯一性會很愚蠢? –

+0

實際上由於某些原因,它仍然很慢,但數據庫命中已經大幅下降與CREATE(不唯一) –

+1

不確定有關緩慢,但我添加了使用和查詢使用中間節點的一些例子。請記住,雖然數據庫創建時間是一個問題,但您最關心的是查詢性能,因此將其用作要使用哪種建模的更好基準。 PROFILE是你的朋友。 – InverseFalcon