cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Neo4j Multi tenancy Count Optimisation

michael3
Node Link

I'm using Neo4j Aura (Ent 3.5). Its for a multi tenancy SaaS application so I am using specific labels to identify the nodes that belong to different tenants. This means that every node generally has at least 2 labels. The first to identify the tenant and the second to identify the node type. However, this also means that the Neo4j fast counts is generally unavailable to me as it doesn't work with multiple labels.

I'm trying to return the total count of all nodes that by label for a tenant. The query I am using works fine (below) but as I scale up beyond 10k nodes the query takes a while to run. At the moment its around 4-5 seconds.

Note that for each entity node in the database thee is also a connected state node. I use these to maintain history. In the below query I am matching to all state nodes for a tenant first.

I'm open to any and all suggestions or alternate approaches to doing this.

MATCH (s:state:n4nite_com_au)
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(idi:entity:Idiom:n4nite_com_au)  
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(de:entity:Data_Element:n4nite_com_au)  
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(sys:entity:System:n4nite_com_au)  
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(dat:entity:Dataset:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(attr:entity:Attribute:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(ctrl:entity:Control:n4nite_com_au)  
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(org:entity:Organization:n4nite_com_au)  
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(prd:entity:Product:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(prj:entity:Project:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(lst:entity:List:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(col:entity:Collection:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(reg:entity:Regulation:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(art:entity:Artefact:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(cou:entity:Course:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(pge:entity:Page:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(per:entity:Person:n4nite_com_au) 
  OPTIONAL MATCH (s)-[:HAS_STATE {current:true}]-(dom:entity:Domain:n4nite_com_au) 
RETURN { 
  Idiom:  COUNT(DISTINCT idi), 
  Data_Element:  COUNT(DISTINCT de), 
  System:  COUNT(DISTINCT sys), 
  Dataset: COUNT(DISTINCT dat), 
  Attribute: COUNT(DISTINCT attr), 
  Control:  COUNT(DISTINCT ctrl), 
  Organization:  COUNT(DISTINCT org), 
  Product: COUNT(DISTINCT prd), 
  Project: COUNT(DISTINCT prj), 
  List: COUNT(DISTINCT lst), 
  Collection: COUNT(DISTINCT col), 
  Regulation: COUNT(DISTINCT reg), 
  Artefact: COUNT(DISTINCT art), 
  Course: COUNT(DISTINCT cou), 
  Page: COUNT(DISTINCT pge), 
  Person: COUNT(DISTINCT per), 
  Domain: COUNT(DISTINCT dom) 
} as result

1 ACCEPTED SOLUTION

michael3
Node Link

In case it helps someone else...here is what I came up with ... its a mish mash of answers from Stack Overflow and gets the job done significantly faster than the old query.

MATCH (s:state:rest_com_au)-[:HAS_STATE {current:true}]-(e:entity:n4nite_com_au)
WITH DISTINCT LABELS(e) AS temp, COUNT(e) AS tempCnt
UNWIND temp AS label
WITH  collect([label,tempCnt]) as labelCounts
RETURN apoc.map.removeKeys(apoc.map.fromPairs(labelCounts), ['entity','n4nite_com_au']) as result

View solution in original post

1 REPLY 1

michael3
Node Link

In case it helps someone else...here is what I came up with ... its a mish mash of answers from Stack Overflow and gets the job done significantly faster than the old query.

MATCH (s:state:rest_com_au)-[:HAS_STATE {current:true}]-(e:entity:n4nite_com_au)
WITH DISTINCT LABELS(e) AS temp, COUNT(e) AS tempCnt
UNWIND temp AS label
WITH  collect([label,tempCnt]) as labelCounts
RETURN apoc.map.removeKeys(apoc.map.fromPairs(labelCounts), ['entity','n4nite_com_au']) as result
Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

All the sessions of the conference are now available online