2

Say I have a decision tree that looks like this:

enter image description here

I've written a cypher query to create that decision tree:

create (_0 {`name`:"Spins?", `type`:"split"})

create (_1a {`name`:"Weight", `type`:"split"})
create (_1b {`name`:"Weight", `type`:"split"})

create (_2a {`name`:"Spider", `type`:"terminal"})
create (_2b {`name`:"Spider Man", `type`:"terminal"})
create (_2c {`name`:"Ant", `type`:"terminal"})
create (_2d {`name`:"Ant Man", `type`:"terminal"})

create (_0)-[:`CON` {`lt`:.5}]->(_1a)
create (_0)-[:`CON` {`gte`:.5}]->(_1b)

create (_1a)-[:`CON` {`lt`:200}]->(_2a)
create (_1a)-[:`CON` {`gte`:200}]->(_2b)

create (_1b)-[:`CON` {`lt`:200}]->(_2c)
create (_1b)-[:`CON` {`gte`:200}]->(_2d)
;

A couple questions:

  1. Is this the best way to set up a decision tree in neo4j?
  2. How would I write a cypher query to join to the graph and get the result node with input data? e.g. say I had the data {'Spins?' : False, 'Weight' : 500}, how would I write a query to efficiently return the "Ant Man" node?

1 Answers1

2

Allow to make small changes to the model:

MERGE (_0:DT:Split  {name: 'Spins', l:0, i:0})
MERGE (_1a:DT:Split {name: 'Weight', l:1, i:0})
MERGE (_1b:DT:Split {name: 'Weight', l:1, i:1})

MERGE (_2a:DT:Terminal {name:'Spider', l:2, i:0})
MERGE (_2b:DT:Terminal {name:'Spider Man', l:2, i:0})
MERGE (_2c:DT:Terminal {name:'Ant', l:2, i:0})
MERGE (_2d:DT:Terminal {name:'Ant Man', l:2, i:0})

MERGE (_0)-[:DT {type:'Left', value: 0.5, propname:'Spins'}]->(_1a)
MERGE (_0)-[:DT {type:'Right', value: 0.5, propname:'Spins'}]->(_1b)
MERGE (_1a)-[:DT {type:'Left', value: 50, propname:'Weight'}]->(_2a)
MERGE (_1a)-[:DT {type:'Right', value: 50, propname:'Weight'}]->(_2b)
MERGE (_1b)-[:DT {type:'Left', value: 50, propname:'Weight'}]->(_2c)
MERGE (_1b)-[:DT {type:'Right', value: 50, propname:'Weight'}]->(_2d)

And query:

// Input parameters:
WITH {Spins: 0.6, Weight: 500} as Cor
// Get all decision paths:
MATCH p = (S:DT:Split {l:0,i:0})-[:DT*]->(T:DT:Terminal)
// Test single decision path:
WHERE ALL(r in relationships(p) WHERE 
        (r.type='Left' AND Cor[r.propname]<r.value) OR // Left variant
        (r.type='Right' AND Cor[r.propname]>=r.value) // Right variant
      )
RETURN T
stdob--
  • 28,222
  • 5
  • 58
  • 73
  • This is fantastic, because I have been thinking about decision trees and models within Neo for a while. The only thing that i can't wrap my head around is the use of the property `i`. What is that doing? – Btibert3 May 28 '16 at 13:12
  • @Btibert3 The property of `l` (level of the tree) and `i` (index of node at specific level of the tree) are needed to distinguish between the nodes with the same name from each other: `(:DT:Split {name: 'Weight', l:1, i:0})` !== `(:DT:Split {name: 'Weight', l:1, i:1})`. – stdob-- May 28 '16 at 13:50