2015-10-05 23 views
7

Ho bisogno di raggruppare i dati da un database neo4j e quindi di filtrare tutto tranne i primi record n di ogni gruppo.Ottenere i primi n record per ciascun gruppo in neo4j

Esempio:

Ho due tipi di nodi: Ordine e art. Tra loro c'è una relazione "AGGIUNTA". La relazione "AGGIUNTA" ha una proprietà data/ora. Quello che voglio sapere (per ogni articolo) è quante volte è stato tra i primi due articoli aggiunti ad un ordine. Quello che ho provato è il seguente approccio:

  1. ottenere tutte le degli ordini [AGGIUNTO] -Articolo

  2. sorta il risultato della fase 1 per ordine id come prima chiave e poi da timestamp rapporto AGGIUNTI smistamento come seconda chiave di smistamento;

  3. per ogni sottogruppo della fase 2 che rappresenta un ordine, mantenere solo le prime 2 righe;

  4. Contare gli ID articolo distinti nell'output del passaggio 3;

mio problema è che mi sono bloccato al punto 3. E 'possibile ottenere top 2 file per ogni sottogruppo che rappresenta un ordine?

Grazie,

Tiberiu

+0

La prego di mostrarci il vostro modello? – MicTech

+0

Stai cercando qualcosa di simile a questo http://stackoverflow.com/questions/32907134/return-top-n-results-for-each-query-in-neo4j? – jjaderberg

risposta

7

Prova

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 

risultati sembrano

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

su questo sample graph creata con

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

Buona risposta. Non vorrei raccogliere 'r', però. Puoi evitare di dover gestire 'endnode' semplicemente raccogliendo' a': 'MATCH (o: Order) - [r: ADDED] -> (a: Articolo) WITH o, r, a ORDER BY o .oid, rt CON O, raccogliere (a) [.. 2] AS top_articles rilassarsi top_articles AS articoli RITORNO articles.aid, cOUNT (*) AS conteggio ORDER BY count DESC; ' –

+0

@NicoleWhite Hai ragione, Grazie! Ho aggiornato la risposta. – jjaderberg

+0

Buon Jonatan, ero solo un po 'confuso dal _ molto short_ identificatore e nome-proprietà :) E a seconda del numero di articoli potrebbe essere meglio fare 'WITH a, count (*) come count RETURN a.id, conta' per ridurre il numero di accessi di proprietà. –

2

Usa LIMIT combinato con ORDER BY per ottenere la parte superiore N di nulla. Ad esempio, i primi 5 segni sarebbero:

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

La parte ORDER BY assicura i punteggi più alti appaiono prima. Il LIMIT ti dà solo i primi 5, che dal momento che sono ordinati, sono sempre i più alti.

+0

Grazie per la risposta, ma non è esattamente quello che voglio. Probabilmente la mia domanda non era abbastanza chiara. Lo modifico – tiberiu

0

Ho cercato di ottenere i risultati desiderati e ho fallito.

Quindi, la mia ipotesi - questo è impossibile con puro cypher.

Qual è il problema? Cypher considera tutto come un percorso. E in realtà sta attraversando.
Provare a raggruppare i risultati e quindi eseguire il filtro su ciascun gruppo significa che in alcuni punti la cifratura dovrebbe in qualche modo dirottarla. Ma Cypher ha eseguito il filtro su tutti i risultati, perché sono considerati come raccolta di percorsi diversi.

Il mio suggerimento: crea diverse query, che raggiungono la funzionalità desiderata e implementano una logica lato client.

Problemi correlati