如果关系不存在,返回节点

我试图创建一个查询使用密码,将“找到”缺失的配料,厨师可能有,我的图表是这样设置的:

(ingredient_value)-[:is_part_of]->(ingredient)

(ingredient)的键/值为 name = “ color”。(ingredient_value)的键/值可以为 value = “ red”,并且“ is part of”为 (ingredient, name="dye colors")

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)

我使用这个查询来获取菜谱所需的所有 ingredients,但不是它们的实际值,但是我希望只返回厨师没有的 ingredients,而不是每个菜谱所需的所有原料。我尽力了

(chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)<-[:has_ingredient*0..0]-chef

但是没有任何回报。

这是可以通过 Cypher/neo4j 实现的,还是可以通过返回所有成分并自己对它们进行分类来最好地处理的?

另外,还有一种方法可以使用密码将厨师拥有的所有值与菜谱所需的所有值进行匹配。到目前为止,我只返回了由 chef-[:has_value]->ingredient_value<-[:requires_value]-recipe返回的所有部分匹配并自己聚合结果。

86065 次浏览

The last query should be:

START chef = node(..)
MATCH (chef)-[:has_value]->(ingredient_value)<-[:requires_value]-(recipe)-[:requires_ingredient]->(ingredient)
WHERE (ingredient)<-[:has_ingredient]-chef
RETURN ingredient

This pattern: (ingredient)<-[:has_ingredient*0..0]-chef

Is the reason it didn't return anything. *0..0 means that the length of the relationships must be zero, which means that ingredient and chef must be the same node, which they are not.

I completed this task using gremlin. I did

x=[]


g.idx('Chef')[[name:'chef1']].as('chef')
.out('has_ingredient').as('alreadyHas').aggregate(x).back('chef')
.out('has_value').as('values')
.in('requires_value').as('recipes')
.out('requires_ingredient').as('ingredients').except(x).path()

This returned the paths of all the missing ingredients. I was unable to formulate this in the cypher language, at least for version 1.7.

Update 01/10/2013:

Came across this in the Neo4j 2.0 reference:

Try not to use optional relationships. Above all,

don’t use them like this:

MATCH a-[r?:LOVES]->() WHERE r IS NULL where you just make sure that they don’t exist.

Instead do this like so:

MATCH a WHERE NOT (a)-[:LOVES]->()

Using cypher for checking if relationship doesn't exist:

...
MATCH source-[r?:someType]-target
WHERE r is null
RETURN source

The ? mark makes the relationship optional.

OR

In neo4j 2 do:

...
OPTIONAL MATCH source-[r:someType]-target
WHERE r is null
RETURN source

Now you can check for non-existing (null) relationship.

I wrote a gist showing how this can be done quite naturally using Cypher 2.0

http://gist.neo4j.org/?9171581

The key point is to use optional match to available ingredients and then compare to filter for missing (null) ingredients or ingredients with the wrong value.

Note that the notion is declarative and doesn't need to describe an algorithm, you just write down what you need.

For fetching nodes with not any relationship

This is the good option to check relationship is exist or not

MATCH (player)
WHERE NOT(player)-[:played]->()
RETURN player

You can also check multiple conditions for this It will return all nodes, which not having "played" Or "notPlayed" Relationship.

MATCH (player)
WHERE NOT (player)-[:played|notPlayed]->()
RETURN player

To fetch nodes which not having any realtionship

MATCH (player)
WHERE NOT (player)-[r]-()
RETURN player

It will check node not having any incoming/outgoing relationship.

If you need "conditional exclude" semantic, you can achieve it this way.

As of neo4j 2.2.1, you can use OPTIONAL MATCH clause and filter out the unmatched(NULL) nodes.

It is also important to use WITH clause between the OPTIONAL MATCH and WHERE clauses, so that the first WHERE defines a condition for the optional match and the second WHERE behaves like a filter.

Assuming we have 2 types of nodes: Person and Communication. If I want to get all Persons which have never communicated by the telephone, but may have communicated other ways, I would make this query:

MATCH (p: Person)
OPTIONAL MATCH p--(c: Communication)
WHERE c.way = 'telephone'
WITH p, c
WHERE c IS NULL
RETURN p

The match pattern will match all Persons with their communications where c will be NULL for non-telephone Communications. Then the filter(WHERE after WITH) will filter out telephone Communications leaving all others.

References:

http://neo4j.com/docs/stable/query-optional-match.html#_introduction_3 http://java.dzone.com/articles/new-neo4j-optional

For new versions of Neo4j, you'll have this error:

MATCH (ingredient:Ingredient)
WHERE NOT (:Chef)-[:HAS_INGREDIENT]->(ingredient)
RETURN * LIMIT 100;

This feature is deprecated and will be removed in future versions. Coercion of list to boolean is deprecated. Please consider using NOT isEmpty(...) instead.

To fix it:

MATCH (ingredient:Ingredient)
WHERE NOT EXISTS((:Chef)-[:HAS_INGREDIENT]->(ingredient))
RETURN * LIMIT 100;