2017-11-21 1 views
3

Ich habe eine große Gruppe von Knoten, die die folgende Chiffre entsprechen:Wie kann ich mithilfe der Neo4j-Chiffrierabfrage ein Histogramm von Knoten erstellen, die nach der Anzahl der Beziehungen bucket sind?

(:Word)<-[:Searched]-(:Session) 

Ich mag bei jeder Frequenz von gesuchten Beziehungen ein Histogramm der Anzahl von Word Knoten machen.

Ich mag diese Art von Diagramm machen:

Searches Words 
0  100 
1-5  200 
6-10  150 
11-15 50 
16-20 25 

Ich fange gerade mit Neo4j, und ich bin nicht sicher, wie man diesen Ansatz oder, selbst wenn es eine Möglichkeit, dies zu präzisieren Chiffre. Das nächste, was ich habe, ist, die Beziehungen zu zählen und Durchschnittswerte zu erhalten.

MATCH (n:Word) 
RETURN 
DISTINCT labels(n), 
count(*) AS NumofNodes, 
avg(size((n)<-[:Searched]-())) AS AvgNumOfRelationships, 
min(size((n)<-[:Searched]-())) AS MinNumOfRelationships, 
max(size((n)<-[:Searched]-())) AS MaxNumOfRelationships 

, das hier ein Beispiel basiert: https://neo4j.com/developer/kb/how-do-i-produce-an-inventory-of-statistics-on-nodes-relationships-properties/

ich auch, erhalten für die Gruppierung der Eimer Verwendung des Modulo-Operator gesehen habe, obwohl ich nicht sicher bin, wie das zu der in Bezug auf die Verwendung Anzahl: Neo4j cypher time interval histogram query of time tree

Gibt es einen "besten" Weg, dies zu tun?

Antwort

1

konnte ich eine Abfrage, um herauszufinden, was ich denke, die Daten bekommt mir ich will:

MATCH (n:Word) 
WITH n, 5 AS bucketsize 
WITH (FLOOR(SIZE((n)<-[:Searched]-())/bucketsize) * bucketsize) AS numRels 
RETURN numRels, COUNT(*) 
ORDER BY numRels ASC 

Es erhält nicht die Null-Zeile, die ich haben möchte, aber es scheint, wie es funktioniert anders. Hoffentlich hat jemand anderes eine bessere Lösung.

1

ich ein einfaches Beispiel-Datensatz aus drei Wörtern erstellt: w1 ohne Durchsuchungen, w2 mit 3 sucht und w3 mit 6.

CREATE (w1:Word {w: '1'}) 
WITH count(*) AS dummy 

CREATE (w2:Word {w: '2'}) WITH w2 
UNWIND range(1, 3) AS i 
CREATE (w2)<-[:Searched]-(:Session) 
WITH count(*) AS dummy 

CREATE (w3:Word {w: '3'}) WITH w3 
UNWIND range(1, 6) AS i 
CREATE (w3)<-[:Searched]-(:Session) 

ich es so nähern würde: Erstens, lassen Sie uns eine Liste erstellen, mit der Obergrenzen für jede Schaufel:

RETURN [i IN range(0, 4) | i*5] AS upperLimits 

╒══════════════╕ 
│"upperLimits" │ 
╞══════════════╡ 
│[0,5,10,15,20]│ 
└──────────────┘ 

Zweitens verwenden, um dies mit einem list comprehension, die die Elemente aus der Liste auswählt, die eine hinreichend große obere Grenze hat. Die erste davon ist unser Bucket, also wählen wir das mit dem Listenindexer [0] aus. Der Rest ist die Berechnung nur die untere Grenze und Bestell Reihen:

WITH [i IN range(0, 4) | i*5] AS upperLimits 
MATCH (n:Word) 
WITH upperLimits, ID(n) AS n, size((n)<-[:Searched]-()) AS numOfRelationships 
WITH 
    [upperLimit IN upperLimits WHERE numOfRelationships <= upperLimit][0] AS upperLimit, 
    count(n) AS count 
RETURN 
    upperLimit - 4 AS lowerLimit, 
    upperLimit, 
    count 
ORDER BY lowerLimit 

Die Abfrage gibt die folgenden Ergebnisse:

╒════════════╤════════════╤═══════╕ 
│"lowerLimit"│"upperLimit"│"count"│ 
╞════════════╪════════════╪═══════╡ 
│-4   │0   │1  │ 
├────────────┼────────────┼───────┤ 
│1   │5   │1  │ 
├────────────┼────────────┼───────┤ 
│6   │10   │1  │ 
└────────────┴────────────┴───────┘ 

Mögliche Verbesserungen:

(1) Wenn der Wert von numOfRelationships größer als die größte obere Grenze, die obige Abfrage wird das erste Element einer leeren Liste zurückgeben, die null ist. Um dies zu vermeiden, wird entweder 1) eine ausreichend große obere Grenze, z.

MATCH (n:Word) 
WITH max(size((n)<-[:Searched]-())) AS maxNumberOfRelationShips 
WITH [i IN range(-1, maxNumberOfRelationShips/5+1) | {lower: i*5-4, upper: i*5}] AS limits 
RETURN * 

Sie können den Top-Eimer mit "16 oder mehr" Semantik mit coalesce verwenden.

(2) -4 als Untergrenze ist nicht sehr schön, wir können CASE verwenden, um es loszuwerden.

Putting all dies zusammen, erhalten wir diese:

MATCH (n:Word) 
WITH max(size((n)<-[:Searched]-())) AS maxNumberOfRelationShips 
WITH [i IN range(0, maxNumberOfRelationShips/5+1) | i*5] AS upperLimits 
MATCH (n:Word) 
WITH upperLimits, ID(n) AS n, size((n)<-[:Searched]-()) AS numOfRelationships 
WITH 
    [upperLimit IN upperLimits WHERE numOfRelationships <= upperLimit][0] AS upperLimit, 
    count(n) AS count 
RETURN 
    CASE WHEN upperLimit - 4 < 0 THEN 0 ELSE upperLimit - 4 END AS lowerLimit, 
    upperLimit, 
    count 
ORDER BY lowerLimit 

was zur Folge hat:

╒════════════╤════════════╤═══════╕ 
│"lowerLimit"│"upperLimit"│"count"│ 
╞════════════╪════════════╪═══════╡ 
│0   │0   │1  │ 
├────────────┼────────────┼───────┤ 
│1   │5   │1  │ 
├────────────┼────────────┼───────┤ 
│6   │10   │1  │ 
└────────────┴────────────┴───────┘ 
+0

Okay, das habe viel zu lange. Ich werde es ein bisschen komprimieren. –

1

Was ich in der Regel in diesem Szenario zu tun, ist, dass ich die Einstellung in Neo4j verwenden, wenn Sie teilen eine ganze Zahl durch eine ganze Zahl erhalten Sie eine ganze Zahl zurück. Dies vereinfacht die Abfrage sehr. Wir fügen einen Sonderfall für 0 hinzu und alles passt in eine Zeile.

WITH [0,1,5,7,9,11] as list 
UNWIND list as x 
WITH CASE WHEN x = 0 THEN -1 ELSE (x/5) * 5 END as results 
return results 

Das gibt

-1, 0, 5, 5, 5, 10

was nicht ideal gegeben ist, dass Sie 1-5 zusammen gruppieren möchten, aber gut genug, denke ich.

+0

Ouh, du hast etwas sehr ähnliches gemacht ... :) –

2

Folgendes sollte funktionieren:

WITH 5 AS gSize 
MATCH (w:Word) 
OPTIONAL MATCH (w)<-[s:Searched]-() 
WITH gSize, w, TOINT((COUNT(s) + (gSize-1))/gSize * gSize) AS m 
RETURN 
    CASE m WHEN 0 THEN '0' ELSE (m-gSize+1)+'-'+m END AS range, 
    COUNT(*) AS ct 
ORDER BY range; 

mit der Probe durch @GaborSzarnyas zur Verfügung gestellten Daten, die Ausgabe ist:

+-------------+ 
| range | ct | 
+-------------+ 
| "0" | 1 | 
| "1-5" | 1 | 
| "6-10" | 1 | 
+-------------+ 
Verwandte Themen