Neo4j Cypher node filtering by pattern comprehension

爷,独闯天下 提交于 2019-12-25 16:00:13

问题


I have a following SDN 4 entities:

Decision, Characteristic and Value:

@NodeEntity
public class Value extends Votable {

    private final static String SET_FOR = "SET_FOR";
    private final static String SET_ON = "SET_ON";
    private final static String CONTAINS = "CONTAINS";

    @Relationship(type = SET_FOR, direction = Relationship.OUTGOING)
    private Decision decision;

    @Relationship(type = SET_ON, direction = Relationship.OUTGOING)
    private Characteristic characteristic;

    @Index(unique = false)
    private Object value;

    ...
}

I have created 3 Decicion(Decicion1, Decision2, Decisison3) nodes and 1 Characteristic(Characteristic1). For Decicion1, Decicion2 and Characteristic1 I have created a Double Value, for example:

Decision1 + Characteristic1 = Value(500d)
Decision2 + Characteristic1 = Value(1000d)
Decicion3 doesn't have any Value on Characteristic1

I need to create a query that will return all Decision which have Value in the defined range, for example 100 <= value <= 50000

Based on the example above this query should return Decision1 and Decicion2 only.

Right now I have a following query:

MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User) 
    WHERE id(parentD) = {decisionId} 
        AND ALL(key IN keys({rangeFilters}) 
            WHERE size(
                [(childD)<-[:SET_FOR]-(filterValue)-[:SET_ON]->(filterCharacteristic) WHERE id(filterCharacteristic) = toInt(key) AND ({rangeFilters}[key])[0] <= filterValue.value <= ({rangeFilters}[key])[1] | 1]
            ) > 0)  
RETURN ru, u, childD AS decision SKIP 0 LIMIT 100 

where rangeFilters is a Map<String, Double[]> where key is a Characteristic ID and value new Double[] { new Double(100.d), new Double(50000d) }

But this query returns all 3 Decision, even the Decision3 that don't have any values associated with Characteristic1 .

How to fix this query in order to return only Decisions that match a condition ?

UPDATED

This is an example that highlights the issue: http://console.neo4j.org/?id=6bv9y5

UPDATED

I'm tried to apply solution described by Tezra. This is my curent query:

MATCH (parentD)-[:CONTAINS]->(childD:Decision)-[ru:CREATED_BY]->(u:User) 
WHERE id(parentD) = {decisionId} 
MATCH (childD)<-[:SET_FOR]-(filterValue)-[:SET_ON]->(filterCharacteristic) 

WHERE  

ALL(key IN keys({equalFilters}) WHERE id(filterCharacteristic) = toInt(key) AND filterValue.value = ({equalFilters}[key]))  

AND  

ALL(key IN keys({rangeFilters}) WHERE id(filterCharacteristic) = toInt(key) AND ({rangeFilters}[key])[0] <= filterValue.value <= ({rangeFilters}[key])[1])  

RETURN ru, u, childD AS decision SKIP 0 LIMIT 100

Unfortunately assertion in my tests fails on this query.

This query works fine only when I specify the single filter condition, for example:

ALL(key IN keys({equalFilters}) WHERE id(filterCharacteristic) = toInt(key) AND filterValue.value = ({equalFilters}[key]))  

or

ALL(key IN keys({rangeFilters}) WHERE id(filterCharacteristic) = toInt(key) AND ({rangeFilters}[key])[0] <= filterValue.value <= ({rangeFilters}[key])[1]) 

but doesn't work when both of them are present. What am I doing wrong ?


回答1:


Based on the example data, you just need to link all the checks correctly. (the parent stuff isn't in the example, but I think it was just the key-range part messing you up)

WITH {c1:[100,50000]} AS rangeFilters
MATCH (childD:Decision)<--(fv:FilterValue)-->(c:FilterCharacteristic) 
WHERE ALL(key IN keys(rangeFilters) 
    WHERE c.id=key AND rangeFilters[key][0] < fv.value < rangeFilters[key][1]) 
RETURN childD

Although you could also make FilterValue a relationship since relationships can have properties too.

UPDATE:

As for your problem with WHERE ALL( equals...) AND ALL(in_range...); That reads "Where all equal filters are true and all range filters are true". So I'm guessing that you actually want is any of them to be true which would be WHERE ANY (equals...) OR ANY(in_range) (available predicates), as it is impossible for filter.value to equal 7 and 9 at the same time.

Also, as a side note, don't use id() in your queries, as Neo4j reserves the right to change those as much or little as it likes. Set your own id fields, and use a UUID instead. A UUID is also much more reliable if you need to merge data sets.



来源:https://stackoverflow.com/questions/43855265/neo4j-cypher-node-filtering-by-pattern-comprehension

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!