1

I am new to Neo4j,I have the following situation

enter image description here

In the above diagram represented a node with label user with sub-nodes having label shops. Each of these sub-nodes have sub-nodes with label items. Each node items has attribute size and the items node is in descending order by size attribute for each node shops as represented in the figure.

Question

I want to get two items node whose size is less than or equal to 17 from each shops . How to do that? I tried, but its not working the way I need

Here is what I have tried

match (a:user{id:20000})-[:follows]-(b:shops)
with b
match (b)-[:next*]->(c:items)
where c.size<=17
return b
limit 2

Note- These shops node can have thousands of items nodes. So how to find the desired nodes without traversing all thousands of items nodes. Please help , thanks in advance.

SarathSprakash
  • 4,614
  • 2
  • 19
  • 35

2 Answers2

3

Right now Cypher does not handle this case well enough, I would probably do a java based unmanaged extension for this.

It would look like this:

public List<Node> findItems(Node shop, int size, int count) {
   List<Node> results=new ArrayList<>(count);
   Node item = shop.getSingleRelationship(OUTGOING, "next").getEndNode();
   while (item.getProperty("size") > size && results.size() < count) {
       if (item.getProperty("size") <= size) result.add(item);
       item = item.getSingleRelationship(OUTGOING, "next").getEndNode();
   }
   return result;
}


List<Node> results=new ArrayList<>(count*10);
for (Relationship rel = user.getRelationships(OUTGOING,"follows")) {
   Node shop = rel.getEndNode();
   results.addAll(findItems(shop,size,count));
}
Michael Hunger
  • 41,339
  • 3
  • 57
  • 80
0

You can avoid having to traverse all items of each shop by grouping them according to size. In this approach, your graph looks like this

(:User)-[:follows]-(:Shop)-[:sells]-(:Category {size: 17})-[:next]-(:Item)

You could then find two items per shop using

match (a:User {id: 20000})-[:follows]-(s:Shop)-[:sells]-(c:Category)
where c.size <= 17
with *
match p = (c)-[:next*0..2]-()
with s, collect(tail(nodes(p))) AS allCatItems
return s, reduce(shopItems=allCatItems[..0], catItems in allCatItems | shopItems + catItems)[..2]

shopItems=allCatItems[..0] is a workaround for a type checking problem, this essentially initializes shopItems to be an empty Collection of nodes.

boggle
  • 221
  • 3
  • 3
  • Thanks for your response, but this is not what I wanted. Please read my question – SarathSprakash Mar 14 '14 at 06:02
  • What part of your question did I not understand? I think it is not possible to efficiently execute your query as you will always have to scan all shop items until you find the ones that have the correct size (as suggested by @MichaelHunger). Hence I suggested this solution based on a modified data model. – boggle Mar 14 '14 at 13:28
  • If you wanted to be truer to your original model, you could instead use a sorted, linked list of categories where each category also holds its items. Still, any generally efficient solution will have to separate items from categories. – boggle Mar 14 '14 at 13:36