Search code examples
neo4jcypher

Neo4j cypher return all nodes where property and relationship matches any array element


I've used an image classifier AI to create a Neo4j database. There are 30 Category nodes with an id property. The CLASSIFIED_AS relationships have a weight property between 0 and 1.

I have two arrays for category id and relationship weight: [14, 17, 20, 21], [0.9, 0.7, 0.5, 0.4].

I know how to return images that fall into one of the categories in my array.

MATCH (i:Image)-[:CLASSIFIED_AS]->(c:Category)
WHERE c.id IN [14, 17, 20, 21]
RETURN i LIMIT 100

But how do I filter images by both category and corresponding relationship weight?

So in this example, I require:

  1. Images that are in category 14 with a CLASSIFIED_AS weight between 0.9 to 1
  2. And that are in category 17 with a CLASSIFIED_AS weight between 0.7 to 1
  3. And that are in category 20 with a CLASSIFIED_AS weight between 0.5 to 1
  4. And that are in category 21 with a CLASSIFIED_AS weight between 0.4 to 1

How is this possible with arrays of varying lengths?


Solution

  • [UPDATE]

    This update should satisfy the example at the bottom of your question.

    For simplicity, I will assume that Category id values are strings. I will also assume you pass this $input parameter value:

    {
      14: {lo: 0.9, hi: 1},
      17: {lo: 0.7, hi: 1},
      20: {lo: 0.5, hi: 1},
      21: {lo: 0.4, hi: 1}
    }
    

    This query will find the Images that satisfy all the constraints in $input:

    MATCH (i:Image)-[r:CLASSIFIED_AS]->(c:Category)
    WHERE $input[c.id].lo <= r.weight <= $input[c.id].hi
    WITH i, COUNT(DISTINCT c) AS catCount
    WHERE catCount = SIZE(KEYS($input))
    RETURN i LIMIT 100
    

    [ORIGINAL]

    Assuming you pass the lists as the parameters $ids and $weights, this should work:

    MATCH (i:Image)-[r:CLASSIFIED_AS]->(c:Category)
    WHERE c.id IN $ids AND r.weight IN $weights
    RETURN DISTINCT i LIMIT 100
    

    But if you actually want to specify a weight range, then pass a $range parameter in this format: {lo: 0.9, hi: 1}, and use this query:

    MATCH (i:Image)-[r:CLASSIFIED_AS]->(c:Category)
    WHERE c.id IN $ids AND $range.lo <= r.weight <= $range.hi
    RETURN DISTINCT i LIMIT 100