Как ограничить подузлы от каждого узла Neo4j Cypher

Я новичок в Neo4j, у меня следующая ситуация

введите здесь описание изображения

На приведенной выше диаграмме представлен узел с меткой user с подузлами, имеющими метку shops. У каждого из этих подузлов есть подузлы с меткой items. Каждый узел items имеет атрибут size, а узел элементов находится в порядке убывания по атрибуту size для каждого узла shops, как показано на рисунке.

Вопрос

Я хочу получить два узла items, размер которых меньше или равен 17 из каждого shops. Как это сделать? Я пытался, но это не работает так, как мне нужно

Вот что я пробовал

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

Примечание. Эти shops узлов могут иметь тысячи items узлов. Итак, как найти нужные узлы, не обходя все тысячи items узлов. Пожалуйста, помогите, заранее спасибо.


person SarathSprakash    schedule 09.03.2014    source источник
comment
эти атрибуты размера имеют тип int или они хранятся в строковой форме в атрибуте узла?   -  person Sumeet Sharma    schedule 09.03.2014
comment
атрибуты размера имеют тип int   -  person SarathSprakash    schedule 10.03.2014


Ответы (2)


Прямо сейчас Cypher недостаточно хорошо справляется с этим случаем, я бы, вероятно, сделал для этого неуправляемое расширение на основе Java.

Это будет выглядеть так:

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));
}
person Michael Hunger    schedule 10.03.2014

Вы можете избежать необходимости просматривать все предметы каждого магазина, сгруппировав их по размеру. При таком подходе ваш график выглядит так

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

Затем вы можете найти два предмета в магазине, используя

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] — это обходной путь для проблемы проверки типов, он по существу инициализирует shopItems как пустую коллекцию узлов.

person boggle    schedule 13.03.2014
comment
Спасибо за ответ, но это не то, что я хотел. Пожалуйста, прочитайте мой вопрос - person SarathSprakash; 14.03.2014
comment
Какую часть вашего вопроса я не понял? Я думаю, что невозможно эффективно выполнить ваш запрос, так как вам всегда придется сканировать все товары в магазине, пока вы не найдете те, которые имеют правильный размер (как предложил @MichaelHunger). Поэтому я предложил это решение на основе модифицированной модели данных. - person boggle; 14.03.2014
comment
Если вы хотите быть более верным своей исходной модели, вы можете вместо этого использовать отсортированный связанный список категорий, где каждая категория также содержит свои элементы. Тем не менее, любое в целом эффективное решение должно будет отделять элементы от категорий. - person boggle; 14.03.2014