How to implement this tree view in C# - c#

I need to implement a binary tree view attached in the diagram. The process is going like this. First, start in position#1. Then need to print P#2.After p#3.As binary tree method need print left first then right. This is for pyramid system. Please check the example below how this should be. Each node represents the customer(By ID) and his position.
Ex: Let's assume out customerID is number 01 and he might have 5 positions in the tree representing his ID #1, Like in the diagram. And customer number2 have 3 positions in a tree. So we have a lot of customers and some have more than 20 positions in each node.
I need a solution to implement this view. Please note this is not relevant for binary search tree. Thank you!
Please check the image in here

It looks like you are trying to implement a breadth first search but with an unusual order for returning the results whereby you take one item from each child in a row and interleave them.
So you will need to proceed row-by-row: build a list of nodes at that level, and then to get the next level take all of the left children of each and then all of the right children of each of each to form the next level. This will disentangle your curious tree and you will visit the nodes in this order:
Position #1
LEFTS = { P#1 }, RIGHTS = { P#2 }
LEFTS = { P#3 P#4}, RIGHTS = { P#5 P#6 }
LEFTS = { P#7 P#8 P#9 P#10 }, RIGHTS = { P#11 P#12 P#13 P#14 }

Related

How can I get an exclusive subgraph from a vertex?

I've recently had to change from using Cypher to Gremlin and I'm trying to convert a query that allowed a user to 'delete' a node and all of the subgraph nodes that would be affected by this. It wasn't actually removing nodes but just adding a 'DELETED' label to the affected nodes.
I can get a subgraph in Gremlin using:
g.V(nodeId).repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph')
but this doesn't take into account any nodes in the subgraph that might have a route back past the originally 'deleted' node and therefore shouldn't be orphaned.
If you take the graph above; B is the node being deleted. It's subgraph would include D, E, G and H. However, since E still has a route back to A through C, we don't want to 'delete' it. D, G and H will be left without a route back to A and should therefore also be deleted.
My Cypher query worked like this (using Neo4jClient.Cypher in C#):
// Find the node to be deleted i.e. B
.Match("(b {Id: 'B'})")
// Set a DELETED label to B
.Set("b:DELETED")
.With("b")
// Find the central node i.e A
.Match("(a {Id: 'A'})")
// Find the subgraph of B ignoring previously deleted nodes
.Call("apoc.path.subgraphAll(b, { relationshipFilter: '<memberOf', labelFilter: '-DELETED'})")
.Yield("nodes AS subgraph1")
// Get each node in subgraph1 as sg1n
.Unwind("subgraph1", "sg1n")
// Check if each sg1n node has a route back to A ignoring DELETED routes
.Call("apoc.path.expandConfig(sg1n, { optional: true, relationshipFilter: 'memberOf>', labelFilter: '-DELETED', blacklistNodes:[b],terminatorNodes:[a]})")
.Yield("path")
// If there is a path then store the nodes as n
.Unwind("CASE WHEN path IS NULL THEN [null] ELSE nodes(path) END", "n")
// Remove the nodes in n from the original subgraph (This should leave the nodes without a route back)
.With("apoc.coll.subtract(subgraph1, collect(n)) AS subgraph2")
// Set the DELETED label on the remaining nodes
.ForEach("(n IN(subgraph2) | SET n:DELETED)")
Is there any way I can get similar functionality in Gremlin?
UPDATE
Thanks to sel-fish's help in this question and in this one, I now have this working using:
g.V(itemId) // Find the item to delete.
.union( // Start a union to return
g.V(itemId), // both the item
g.V(itemId) // and its descendants.
.repeat(__.inE('memberOf').outV().store('x')) // Find all of its descendants.
.cap('x').unfold() // Unfold them.
.where(repeat(out('memberOf') // Check each descendant
.where(hasId(neq(itemId))).simplePath()) // to see if it has a path back that doesn't go through the original vertex
.until(hasId(centralId))) // that ends at the central vertex .
.aggregate('exception') // Aggregate these together.
.cap('x').unfold() // Get all the descendants again.
.where(without('exception'))) // Remove the exceptions.
.property('deleted', true) // Set the deleted property.
.valueMap(true) // Return the results.
First, save the vertices in subgraph as candidates:
candidates = g.V().has('Id', 'B').repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph').next().traversal().V().toList()
Then, filter the candidates, remains those which doesn't get a path towards Vertex('A') which not including Vertex('B'):
g.V(candidates).where(repeat(out('memberOf').where(has('Id', neq('B'))).simplePath()).until(has('Id','A'))).has('Id', neq('B')).aggregate('expection').V(candidates).where(without('expection'))

Trying to do Unwind and Create New Relationship Between Nodes Neo4J C# Client

I have a list of nodes - In the code as targetNodeList and I have a node called sourceNode(Different Types Of Nodes).
The List and the single node are already existing in the neo4j Db
and I would like to make a relationship between them with additional data that is inside the targetNodeList.
TargetNodeList is a wrapper which contains the node data and the relationship data that I would like to put inside the Relationship
I havn't manage to finish the code because I don't know how to continue it but thats the sample that I tried to do :
public void CreateRelationshipBetweenNodes(NodeType sourceNode,List<TargetNodes> targetNodeList,int solutionId)
{
graphClient.Cypher
.Unwind(targetNodeList, "singleNode")
.Match("(firstNode:FirstType)", "(secondNode:SecondType)")
.Where(" firstNode.Id = otherNode:FirstType{Id:innerNode.Id}")
.AndWhere(" secondNode.Id = node:SecondType {Id:singleNode.Id}")
.WithParams(new { innerNode = sourceNode})
.Create("(firstNode)-[msg:SENT {solution}]->(secondNode)")
.WithParam("solution", solutionId).ExecuteWithoutResults();
}
its not working and there is still more data that I want to add to the relationship from the singleNode for example: singleNode.Score
Would appriciate any help.
Thanks a lot from advanced.
So I'm a little confused with the nodes you're taking in and how they relate, but hopefully the below query will get you on the right route.
First off, match on the sourceNode then UNWIND your other nodes, ready to do the create. Once you have the two nodes MATCHed you then CREATE the relationship (PS. you may want MERGE if you don't want duplicates) - and I set an Id property on the relationship - you need to provide a property name, else it won't work!
graphClient.Cypher
.Match("(sourceNode:SourceNodeType {Id:sourceNode.Id})")
.Unwind(targetNodeList, "singleNode")
.Match("(targetNodeInDb:TargetNode {Id:targetNode.Id})")
.Create("(sourceNode)-[:SENT {Id:{solutionIdParam}}]->(targetNode)")
.WithParam("solutionIdParam", solutionId)
.ExecuteWithoutResults();

Working with index in Neo4j

I've been going through the Neo4J and Neo4J C# client..
The neo4jclient wiki helped me to with node crud operations.. however the wiki ends there abruptly..
I poked around the test methods in source code and managed to understand about relationships and searched online to understand how indexing works.
So far, here's what I have, roughly:
//create indexing on user and car
client.CreateIndex("User", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node);
client.CreateIndex("Car", new IndexConfiguration() { Provider = IndexProvider.lucene, Type = IndexType.fulltext }, IndexFor.Node);
//create user
client.Create(new User() { Name = "Dovakiin", Job = "Dragon Slayer" });
client.Create(new User() { Name = "Ulfric stormcloak", Job = "Imperial Slayer" });
//create Car
client.Create(new Car() { Name = "Paarthurnax", Modal = 212 });
//User owns car relationship
client.CreateRelationship(userRef, new Owns_CarRelationship(CarRef));
This is where I am stuck now.. When I try to look for the user by name, my cipher query is returning zero results:
start u=node:User(Name="Dovakiin") return u;
and I don't quite understand why it returns zero nodes when clearly
start n=node(*) return n;
shows all nodes.
Am I missing something else while indexing? Or is this not index related at all? Do I not need to add each node to the index?
All I am trying to do, is select the node with a given property: Name = "Dovakiin" in this case.. How do I select this please?
Just to expand on ulkas' answer, if you want to enable auto indexing and found the documentation a little confusing (like I did the first time I read it), this is how you set it up.
Let's say you want to automatically index some node properties; say, "name" and "job". Open up the /conf/neo4j.properties file and you should see something like this:
# Autoindexing
# Enable auto-indexing for nodes, default is false
#node_auto_indexing=true
# The node property keys to be auto-indexed, if enabled
#node_keys_indexable=name,age
You then have to edit the file to the following:
# Autoindexing
# Enable auto-indexing for nodes, default is false
node_auto_indexing=true
# The node property keys to be auto-indexed, if enabled
node_keys_indexable=name,job
Once this is done, in order for auto indexing to take effect, you'll have to restart neo4j. Also, as a side note, any currently existing nodes won't be auto indexed, which means you'll have to recreate them. If you don't want to start from scratch, here's some documentation on how to update them: http://docs.neo4j.org/chunked/milestone/auto-indexing.html#auto-indexing-update-removal (I've never tried it).
Then you can start finding nodes like this:
start n=node:node_auto_index(name="Dovakiin"), or
start n=node:node_auto_index(job="Dragon Slayer")
Or, like this with the C# client:
Node<User> myNode = client.QueryIndex<User>("node_auto_index", IndexFor.Node, "name:Dovakiin").First();, or
Node<User> myNode = client.QueryIndex<User>("node_auto_index", IndexFor.Node, "job:Dragon Slayer").First();
You can do the same thing with with relationships as well, as soon as you set it up in the /conf/neo4j.properties file. You do it exactly the same way as with nodes.
you must manually add the nodes to the index, something like
client.indexRef1.addToIndex(nodeRef, 'name', 'Dovakiin')
client.indexRef2.addToIndex(nodeRef, 'job', 'Dragon Slayer')
there is also an automatic indexing feature in neo4j in case you want the nodes to be automatically added to the index.

Linq to SQL Nested Objects

I have a object called Category which has an Id, Name, and OwnerId. I then nest these to create Subcategories. If a category has an Owner Id it is a sub category. The number of subcategories is unlimited but each item can only have 1 parent. Simple enough.
My Issue is, I need to access a subcategory after loaded. How do I get the Owning category using Linq. I know the Owner Id but I dont know how many lvls deep the owner could be.
Basically I am looking for a way to get the Category or subcategory where the Id == X but this can live in a subcategory 6 levels or more deep.
I am trying to avoid a loop for each sub category in each sub category....
There is another way to store/retrieve a tree hierarchy as explained in this fogbugz blog post:
Turns out there's a pretty cool
solution for this problem explained by
Joe Celko. Instead of attempting to
maintain a bunch of parent/child
relationships all over your database
-- which would necessitate recursive SQL queries to find all the
descendents of a node -- we mark each
case with a "left" and "right" value
calculated by traversing the tree
depth-first and counting as we go. A
node's "left" value is set whenever it
is first seen during traversal, and
the "right" value is set when walking
back up the tree away from the node.
A picture probably makes more sense:
The Nested Set SQL model lets us add
case hierarchies without sacrificing
performance.
How does this help? Now we just ask
for all the cases with a "left" value
between 2 and 9 to find all of the
descendents of B in one fast, indexed
query. Ancestors of G are found by
asking for nodes with "left" less than
6 (G's own "left") and "right" greater
than 6. Works in all databases.
Greatly increases performance --
particularly when querying large
hierarchies
Here's another post going into more detail. It's written using Sql and php but I think you can get the gist of it and easily translate in Linq to Sql.
In MS SQL 2005 and up you can create recursive queries. In LINQ to SQL however, you are out of luck. Without restructoring the data in the database, there is no way you can traverse the tree in a single database call.
However... there is 1 workaround I can think of. When you are able to group all Category elements of a single tree (or a part of the tree) together, you can pre-load that part of the complete tree in a single statement. After that, you will be able to traverse that part of the tree, without triggering new calls to the database. It would look something like this:
// Load the category that will be used as starting point.
var subCategory = db.Categories.Single(c => c.Id == 56);
// Performance: Load the complete group in one go.
var categories = (
from category in db.Categories
where category.GroupId == subCategory.GroupId
select category)
.ToArray();
// Traverse the tree and get the top-most parent (if any).
var parent = subCategory.GetParents().LastOrDefault();
// Extension method to get the parents.
public static IEnumerable<Category> GetParents(
this Category category)
{
while (category.Parent != null)
{
// NOTE: cat.Parent will not cause a database call
// when the Parent is already loaded by L2S.
yield return cat.Parent;
category = category.Parent;
}
}
This of course will only work if you will be able to determine elements as a group. Whether this solution will be faster also depends on the size of the group. When the group of objects that you load (and don't use) is very big, it will actually slow the application down.

Querying by near, sorting, then paging

I'm using the geospatial "near" search in MongoDB (using the C# driver) to return homes within 25 miles of a given lat/long. This returns the homes sorted by proximity to the lat/long and works great.
However, I want to add in sorting (on other fields such as home price) and paging and here is where I'm getting stuck. To work correctly, it would need to figure out which homes were within 25 miles of the lat/long, then sort those results (let's say based on price), and then take a "page" of 10 results.
Below is what I have so far, the issue with it is it takes a page of results (based on the proximity sort) and then sorts that page of 10 results by what I set in "SetSortOrder" rather than sorting the entire result near the lat/long, so each page of 10 results is sorted in itself.
var coordinates = find.GetCoordinates();
var near = Query.Near("Coordinates", coordinates.Latitude,
coordinates.Longitude,
find.GetRadiansAway(), false);
var query = Collection().Find(near);
query.Skip = find.GetSkip();
query.Limit = find.GetLimit();
query.SetSortOrder(new string[] { "Price" });
var results = query.ToArray();
It is right behavior, because $near by default return result sorted by distance. And sorting done internally in $near operator, so you can't change it.
db.places.find( { loc : { $near :
[50,50] } } )
The above query finds the closest
points to (50,50) and returns them
sorted by distance (there is no need
for an additional sort parameter)
So in you example Price it's second sort field that sort data within result sorted by distance.
Workgraund is load entire result of Query.Near and than sort it by whatever you want field on the client.

Categories