2016-11-26 165 views
2

我在寫一個查詢食譜的查詢。我想用匹配查詢的食譜返回當前的用戶交互(喜歡等)。Cypher查詢在查找多個記錄時不返回關係

該查詢返回正確的當前用戶的所有交互:

MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
RETURN reaction 

然而,當我在比賽添加到現有的搜索查詢,該reaction變量是空的每一條記錄:

MATCH (recipe:Recipe) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
WHERE ALL(
    ingredient IN ['tomato', 'banana'] 
    WHERE (recipe)-[:CONTAINS]->(:Ingredient {name: ingredient}) 
) 
AND ALL(
    category IN ['smoothie'] 
    WHERE (recipe)-[:IS]->(:Category {name: category}) 
) 
RETURN DISTINCT recipe, 
{username: u.username, cuid: u.cuid} AS author, 
{love: reaction.love, favorite: reaction.favourite} AS interactions, 
collect(DISTINCT {name: i.name, amount: a.amount}) AS ingredients, 
collect(DISTINCT {name: c.name}) AS categories 

查詢我用來獲取單個食譜的ID儘管它應該如此:

MATCH (recipe:Recipe {cuid: {recipeCuid}}) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: {beholderCuid}}) 
RETURN recipe, 
{username: u.username, cuid: u.cuid} AS author, 
{love: reaction.love, favorite: reaction.favorite} AS interactions, 
collect(DISTINCT {name: i.name, amount: a.amount}) AS ingredients, 
collect(DISTINCT {name: c.name}) AS categories 

任何指向我在做什麼錯的?

+0

1.如果從查詢中刪除WHERE子句,結果如何?也許'WHERE'子句過濾掉了'reaction'不爲空的所有匹配項。 2.這可能沒有什麼區別,但在你的第一個查詢中,你沒有指定'recipe'應該有一個'Recipe'標籤。 –

+0

它在我刪除where子句時起作用!任何想法,我可以如何使它與'WHERE'子句一起工作? – Amygdaloideum

+0

如果只保留'WHERE'子句中的一個條件,即只檢查'ingredient'還是僅檢查'category',會發生什麼? –

回答

3

的Gabor的查詢是一個很好的一步,因爲它移動你的WHERE後WITH而不是與可選MATCH保持它...這是你無法得到正確的結果的主要原因。

但是,查詢還需要一些提高效率。對於一個,如果您不立即運行聚合,則連續出現多個MATCH或OPTIONAL MATCH,特別是那些將返回多行(成分,類別)的MATCH或OPTIONAL MATCH會影響剩餘MATCH或可選MATCH的效率。例如,對於具有3個成分和2個類別的單一配方,在您的前兩個可選匹配完成時排出的是3 x 2 = 6行,這意味着其他可選匹配需要在所有6個配方中執行的行,但你的意圖是他們只能爲每個配方執行一次,而不是多次。

這就是爲什麼儘快進行聚合是有用的,因爲它可以將每個配方的行數減少到一個,而不是多個(對於配方和配料以及類別的每個組合,配方只有一個配料和一個類別)。

此外,你只過濾下來(基於成分和類別)您在所有剩下的唯一匹配後,意味着你在那肯定會被過濾掉行運行許多可選的匹配。這是浪費工作,浪費分貝點擊。儘可能快地做你的過濾,然後在你知道你將要返回的行上運行你需要的額外的可選匹配。

最後,因爲你只能似乎想回行與某些成分,只有某些類別的食譜,我們應該用火柴成分和類別,不是可有可無的匹配。

我建議是這樣的一種改進的查詢:

MATCH (cat:Category) 
WHERE cat.name IN ['smoothie'] 
WITH COLLECT(cat) as desiredCategories 
MATCH (i:Ingredient) 
WHERE i.name IN ['tomato', 'banana'] 
WITH desiredCategories, COLLECT(i) as desiredIngredients 
MATCH (recipe:Recipe) 
WHERE ALL(
    category IN desiredCategories 
    WHERE (recipe)-[:IS]->(category) 
) 
AND ALL(
    ingredient IN desiredIngredients 
    WHERE (recipe)-[:CONTAINS]->(ingredient) 
) 
WITH recipe 
MATCH (recipe)-[:IS]->(c:Category) 
WITH recipe, COLLECT(c) as categories 
MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
WITH recipe, categories, COLLECT({name: i.name, amount: a.amount}) as ingredients 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
// only one author, so okay to use optional matches back to back 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
RETURN recipe, 
    {username: u.username, cuid: u.cuid} AS author, 
    {love: reaction.love, favorite: reaction.favourite} AS interactions, 
    ingredients, 
    categories 

你應該能夠看到,運行我們收集()之後我們做的比賽返回多個行,我們保持建每個配方將每行添加到1個集合(集合是單行,而未收集時是多行)。

你也應該能夠看到,因爲我們過濾掉沒有所需類別或成分的食譜,因此作者和反應的結尾的可選匹配將僅適用於具有所需類別的食譜以及配料,而不是無用的食譜,將被過濾掉。

編輯

我注意到了,晚了,有與你檢查類別和成分的方式有問題,你不能在節點直接與您的數組名稱進行比較。您可能在以下物料上有name財產:成分和類別節點,我們應該使用它來匹配必要的成分和類別,然後在開始時過濾食譜,以便我們只使用這些類別的食譜配料。這也可以讓我們避免匹配和收集類別和成分,直到我們完成過濾。我已經更新了相應的查詢。

+0

還在collect()中添加了成分的數量。 – InverseFalcon

+0

謝謝!我將需要研究這個查詢來充分理解它。但是在運行時,我得到'Variable'c'not defined',嘗試將其更改爲'cat',但無論如何都得到相同的錯誤。 – Amygdaloideum

+0

發現錯誤,我沒有更新我的匹配:類別。它應該現在運行。至於研究查詢,通常有助於查看查詢是如何逐個構建的。你可以在不同的地方用RETURN代替WITH(刪除查詢的其餘部分)來看看我們如何建立結果。 – InverseFalcon

2

嘗試收集的成分和分類收集,並進行對這些藏品的檢查。 RETURN子句有點簡化,但讓我們先看看它是否起作用。

MATCH (recipe:Recipe) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
WITH recipe, collect(i) AS ingredients, collect(c) AS categories, u, reaction, beholder 
WHERE ALL(
    ingredient IN ['tomato', 'banana'] 
    WHERE ingredient in ingredients 
) 
AND ALL(
    category IN ['smoothie'] 
    WHERE category in categories 
) 
RETURN DISTINCT recipe, 
    {username: u.username, cuid: u.cuid} AS author, 
    {love: reaction.love, favorite: reaction.favourite} AS interactions, 
    ingredients, 
    categories