2015-10-05 2 views
7

Мне нужно сгруппировать данные из базы данных neo4j, а затем отфильтровать все, кроме верхних n записей каждой группы.Получение первых записей n для каждой группы в neo4j

Пример:

У меня есть два типа узлов: Order и статьи. Между ними есть отношение «ДОБАВЛЕНО». Отношение «ADDED» имеет свойство timestamp. То, что я хочу знать (для каждой статьи), - это то, сколько раз оно было среди первых двух статей, добавленных в заказ. То, что я пытался это следующий подход:

  1. получить все ПОРЯДКА [ADDED] -Статие

  2. сортировки результатов, начиная с шагом 1 по идентификатору заказа, как первый ключ сортировки, а затем временные метким ДОБАВЛЕННЫХ отношений как второй ключ сортировки;

  3. для каждой подгруппы из шага 2, представляющего один заказ, сохраняйте только верхние 2 строки;

  4. Подсчет отдельных идентификаторов товаров на выходе шага 3;

Моя проблема в том, что я застрял на шаге 3. Возможно ли получить две верхние строки для каждой подгруппы, представляющей заказ?

Спасибо,

Тибериу

+0

Не могли бы вы показать нам свою модель? – MicTech

+0

Вы ищете что-то вроде этого http://stackoverflow.com/questions/32907134/return-top-n-results-for-each-query-in-neo4j? – jjaderberg

ответ

7

Попробуйте

MATCH (o:Order)-[r:ADDED]->(a:Article) 
WITH o, r, a 
ORDER BY o.oid, r.t 
WITH o, COLLECT(a)[..2] AS topArticlesByOrder UNWIND topArticlesByOrder AS a 
RETURN a.aid AS articleId, COUNT(*) AS count 

Результаты выглядят

articleId count 
    8   6 
    2   2 
    4   5 
    7   2 
    3   3 
    6   5 
    0   7 

на этом sample graph созданный с

FOREACH(opar IN RANGE(1,15) | 
    MERGE (o:Order {oid:opar}) 
    FOREACH(apar IN RANGE(1,5) | 
     MERGE (a:Article {aid:TOINT(RAND()*10)}) 
     CREATE o-[:ADDED {t:timestamp() - TOINT(RAND()*1000)}]->a 
    ) 
) 
+2

Хороший ответ. Однако я бы не собирал 'r'. Вы можете избежать необходимости иметь дело с 'endnode', просто собирая' a': 'MATCH (o: Order) - [r: ADDED] -> (a: Article) С o, r, a ORDER BY o .oid, rt WITH o, COLLECT (a) [.. 2] AS top_articles UNWIND top_articles AS статьи RETURN articles.aid, COUNT (*) AS count ORDER BY count DESC; ' –

+0

@NicoleWhite Вы правы, благодаря! Я обновил ответ. – jjaderberg

+0

Хорошо, Джонатан, я был немного смущен _very short_ идентификатором и именами свойств :) И в зависимости от количества статей лучше было бы сделать 'WITH a, count (*) как count RETURN a.id, count', чтобы уменьшить # доступа к свойствам. –

2

Использование LIMIT в сочетании с ORDER BY, чтобы получить верхнюю N чего-либо. Например, топ 5 баллов будет:

MATCH (node:MyScoreNode) 
RETURN node 
ORDER BY node.score DESC 
LIMIT 5; 

ORDER BY часть обеспечивает самые высокие баллы показывают, в первую очередь. LIMIT дает вам только первые 5, которые, поскольку они отсортированы, всегда самые высокие.

+0

Спасибо, что ответили, но это не совсем то, что я хочу. Наверное, мой вопрос был недостаточно ясен. Я отредактирую его. – tiberiu

0

Я пытался достичь желаемых результатов и не смог.

Итак, моя догадка - это невозможно с чистым cypher.

В чем проблема? Сайфер рассматривает все как путь. И на самом деле делает ход.
Попытка сгруппировать результаты, а затем выполнить фильтр в каждой группе означает, что cypher должен каким-то образом разветвить его в некоторых точках. Но Cypher выполнил фильтр по всем результатам, потому что они рассматриваются как набор различных путей.

Мое предложение - создайте несколько запросов, которые достигают желаемой функциональности и реализуют некоторую клиентскую логику.

Смежные вопросы