Just about any graph database can model the information you are describing. How you go about constructing the queries to get what you want will be different in each product.
In InfiniteGraph we can model the information using the following schema:
UPDATE SCHEMA {
CREATE CLASS Company {
name : String,
industry : String,
owns : LIST {
element: Reference {
edgeClass : Owns,
edgeAttribute : owns
},
CollectionTypeName : SegmentedArray
},
ownedBy : LIST {
element: Reference {
edgeClass : Owns,
edgeAttribute : ownedBy
},
CollectionTypeName : SegmentedArray
}
}
CREATE CLASS Owns
{
percentage : Real { Storage: B32 },
owns : Reference {referenced: Company, inverse: ownedBy },
ownedBy : Reference {referenced: Company, inverse: owns }
}
};
Then we can load the data you referred to in your question:
LET coA = CREATE Company { name: "A", industry: "Manufacturing" };
LET coB = CREATE Company { name: "B", industry: "Manufacturing" };
LET coC = CREATE Company { name: "C", industry: "Retail" };
LET coD = CREATE Company { name: "D", industry: "Construction" };
CREATE Owns { owns: $coB, ownedBy: $coA, percentage: 50.00 };
CREATE Owns { owns: $coC, ownedBy: $coB, percentage: 50.00 };
CREATE Owns { owns: $coC, ownedBy: $coD, percentage: 50.00 };
Finally, we can define a weight calculator operator that effectively multiplies the edge weights along a path together. Here we represent the weight of each edge as 1/percentage and then at the end we flip the sum over again and this gives us the value you're looking for.
CREATE WEIGHT CALCULATOR wcOwnership {
minimum: 0,
default: 0,
edges: {
(:Company)-[ow:Owns]->(:Company): 1/ow.percentage
}
};
The "edges" section defines the edge patterns to match on and the computation to be performed to compute the edge weight for that edge. In InfiniteGraph, the edge weight does not have to be an attribute; it can be a simple attribute or the result of complex computation based on the contents of one or many objects.
On the given data, we can use the weight calculator to query from the target company (C) up the hierarchy and for each root discovered, we can display the target (C), the percentage of ownership, the length of the path, and the name of the root company. This particular query only goes 1 to 10 degrees ([*1..10]) but this number can be expanded as necessary.
DO> Match m = max weight 1000.0 wcOwnership
((cTarget:Company {name == 'C'})-[*1..10]->(cRoot:Company))
return cTarget.name,
1/Weight(m) as PercentageOwnership,
Length(m),
cRoot.name;
{
_Projection
{
cTarget.name:'C',
PercentageOwnership:50.0000,
Length(m):1,
cRoot.name:'B'
},
_Projection
{
cTarget.name:'C',
PercentageOwnership:50.0000,
Length(m):1,
cRoot.name:'D'
},
_Projection
{
cTarget.name:'C',
PercentageOwnership:25.0000,
Length(m):2,
cRoot.name:'A'
}
}
This model will capture all of the root nodes per company in question.
#InfiniteGraph