I'm trying to create an outline for a syntax definition I create in rascal. I've managed to make the various object appear in the outline by simply adding label annotations like recommended in the documentation. However, I would also like to "categorise" these objects so that all the objects of the same type end up under a common collapsible category. Like the way that Rascal's outline is with all the annotations, functions, variables, tests and so on sorted into their own categories. I haven't found anything really in the documentation about it. I've tried applying #Category to the syntax and to the AST, neither really worked
public node ps_outline(Tree x){
PSGAME g = ps_implode(x);
return g;
}
This is currently the function that I register as my outliner, all that ps_implode does is add a #label and #location annotation to the imploded syntax definition.
new_l # location = l#location;
new_l # label = "Level";
Current outline vs Desired outline
You can nest nodes like so:
"Sounds"(["soundData"(...)])
The nesting of the value will be reflected in the outline.
Lists will be treated as elements on the same nesting level.
The intermediate nodes use the same labels and location information. If a node label appears twice I'm not sure what happens.. it could be that the trees under the same nodes are merged 😎
Cheers!
Related
We are using neo4j version 4.1.1,
and we have a graph that represents a structure of objects.
we support translation using nodes for translation and the connection between an object and a translation node is the object name and description.
for example:
(n:object)-[r:Translation]-(:ru)
means that on relationship r is the name and description of object n in russian.
In order to search by name and description we implemented a fullText index like that:
CALL db.index.fulltext.createRelationshipIndex("TranslationRelationshipIndex",["Translation"],["Name","Description"], { eventually_consistent: "true" })
We also support search for items in order to do it we are using the index to query and we have names like "UFO41.SI01V03":
CALL db.index.fulltext.queryRelationships('TranslationRelationshipIndex', '*FO41.SI0*') YIELD relationship, scoreÂ
but for names as shown above([0-9.*]) no results are returned
while results are returned for name like "ab.or"
Is there any one who knows how to make it work? I've tried all 46 analyzers available.
I know we can solve it just using match()-[r]-() where r.Name contains "<string>"
but we prefer a more efficient index-using solution to this problem.
stay safe!
and thanks in advance.
p.s if needed I can supply a few lines to recreate it locally just ask.
The analyzer will probably recognise words like ab.or differently than ab.or123 and consider them a single token in the first case and two tokens in the second case.
There is no analyzer that will really fit your needs except than creating your own.
You can however replace the . in your query with a simple AND, for eg :
CALL db.index.fulltext.queryNodes('Test', replace("*FO41.SI0*", ".", " AND "))
Will return you the results you're looking at.
Resources for creating your own analyser :
https://graphaware.com/neo4j/2019/09/06/custom-fulltext-analyzer.html
https://neo4j.com/docs/java-reference/current/extending-neo4j/full-text-analyzer-provider/
I am going over this YouTube tutorial, "Using LOAD CSV in the Real World".
The tutorial shows how to take a CSV, where each row is a complaint made against some bank, and model it as a Neo4j dictionary.
When doing so, the narrator sets Properties on the Complaint node:
CREATE (complaint:Complaint {id: line.`Complaint ID`})
SET complaint.year= TOINT(date[2]),
complaint.month= TOINT(date[0]),
complaint.day = TOINT(date[1])
I'm confused about a small point -- what makes this date information more of a 'Property' than a Label?
Could this be modeled instead where the node has this information encapsulated as Labels instead of Properties? At what point do you need one of these and not the other?
Labels and properties are very different things.
A property belongs to a node or a relationship, and has a name and a value.
A node label is similar in concept to a "class name", and has no value.
So, it does not make any sense to talk about putting a date value in a "label". You can only put a value in a property.
Note, however, that people often use a label name (e.g., "Foo") as a shorthand for "node that has the Foo label". For example, they may say "store the date in Foo" when they actually mean "store the date in the appropriate property of a node with the label Foo". Perhaps this is what is causing the confusion.
As cybersam pointed out in his answer, labels cannot contain values. They are just... labels. Like a tag. Taking this in a slightly different direction:
A long, long time ago, in a version far, far away, Neo4j didn't have labels. So, if you wanted to identify a particular type of node (say... a Person)... you'd likely include a property+value such as nodeType = 'Person'. And then you'd include a filter in your queries, such as:
WHERE node.nodeType = 'Person'
Labels make such a property type obsolete, and are also indexable. Further, you may have multiple labels on a node (which would require your legacy nodeType property to be an array, and not as efficient to search).
So: Labels for tagging/indexing. Properties for holding values.
" Node labels serve as an anchor point for a query. By specifying a label, we are specifying a subset of one or more nodes with which to start a query. Using a label helps to reduce the amount of data that is retrieved." https://graphacademy.neo4j.com/
Relationship/Arrows in Neo4j can not get more than one type/label (see here, and here). I have a data model that edges need to get labels and (probably) properties. If I decide to use Neo4j (instead of OriendDB which supports labeled arrow), I think I would have then two options to model an arrow, say f, between two nodes A and B:
1) encode an arrow f as a span, say A<--f-->B, such that f is also a node and --> and <-- are arrows.
or
2) encode an arrow f as A --> f -->B, such that f is a node again and two --> are arrows.
Though this seems to be adding unnecessary complexity on my data model, it does not seem to be any other option at the moment if I want to use Neo4j. Then, I am trying to see which of the above encoding might fit better in my queries (queries are the core of my system). For doing so, I need to resort to examples. So I have two question:
First Question:
part1) I have nodes labeled as Person and father, and there are arrows between them like Person<-[:sr]-father-[:tr]->Person in order to model who is father of who (tr is father of sr). For a given person p1 how can I get all of his ancestors.
part2) If I had Person-[:sr]->father-[:tr]->Person structure instead, for modeling father relationship, how the above same query would look like.
This is answered here when father is considered as a simple relationship (instead of being encoded as a node)
Second Question:
part1) I have nodes labeled as A nodes with the property p1 for each. I want to query A nodes, get those elements that p1<5, then create the following structure: for each a1 in the query result I create qa1<-[:sr]-isA-[:tr]->a1 such that isA and qa1 are nodes.
part2) What if I wanted to create qa1-[:sr]->isA-[:tr]->qa1 instead?
This question is answered here when isA is considered as a simple arrow (instead of being modeled as a node).
First, some terminology; relationships don't have labels, they only have types. And yes, one type per relationship.
Second, relative to modeling, I think the direction of the relationship isn't always super important, since with neo4j you can traverse it both ways easily. So the difference between A-->f-->B and A<--f-->B I think should be entirely driven what what makes sense semantically for your domain, nothing else. So your options (1) and (2) at the top seem the same to me in terms of overall complexity, which brings me to point #3:
Your main choice is between making a complex relationship into a node (which I think we're calling f here) or keeping it as a relationship. Making "a relationship into a node" is called reification and I think it's considered a fairly standard practice to accommodate a number of modeling issues. It does add complexity (over a simple relationship) but adds flexibility. That's a pretty standard engineering tradeoff everywhere.
So with all of that said, for your first question I wouldn't recommend an intermediate node at all. :father is a very simple relationship, and I don't see why you'd ever need more than one label on it. So for question one, I would pick "neither of the options you list" and would instead model it as (personA)-[:father]->(personB). More simple. You'd query that by saying
MATCH (personA { name: "Bob"})-[:father]->(bobsDad) RETURN bobsDad
Yes, you could model this as (personA)-[:sr]->(fatherhood)-[:tr]->(personB) but I don't see how this gains you much. As for the relationship direction, again it doesn't matter for performance or query, only for semantics of whatever :tr and :sr are supposed to mean.
I have nodes labeled as A nodes with the property p1 for each. I want
to query A nodes, get those elements that p1<5, then create the
following structure: for each a1 in the query result I create
qa1<-[:sr]-isA-[:tr]->a1 such that isA and qa1 are nodes.
That's this:
MATCH (aNode:A)
WHERE aNode.p1 < 5
WITH aNode
MATCH (qa1 { label: "some qa1 node" })
CREATE (qa1)<-[:sr]-(isA)-[:tr]->aNode;
Note that you'll need to adjust the criteria for qa1 and also specify something meaningful for isA.
What if I wanted to create qa1-[:sr]->isA-[:tr]->qa1 instead?
It should be trivial to modify that query above, just change the direction of the arrows, same query.
I have a situation where I'm trying to filter out nodes that are not related to nodes with a particular property. For example, say I have a query that gets me all people, but I want to filter down to just the ones that have dogs with brown fur. What I would like to do is something like this:
//For simplicity's sake, assume nodes 1,2,3 are the potentials I care about
START person=node(1,2,3)
WHERE person-[:has]->(dog{furColor:"Brown"}) // <-- would be nice to use
RETURN person
However, this doesn't work. The parser explicitly tells me:
Properties on pattern elements are not allowed in MATCH.
(Amusing that it references "MATCH" when I'm using "WHERE", but whatever). So you can't reference properties of nodes in this fashion. What other options do I have? I was able to emulate what I want by adding in a MATCH clause...
START person=node(1,2,3)
MATCH person-[:has]->dog
WHERE dog.furColor! = "Brown"
RETURN person
...but it seems strange and inefficient to me that I have to MATCH additional paths and then filter them back out again. Is there another way?
i'm afraid there is no other way then to use the WHERE clause in your graph design.
but considering you can change and you really want to, you can make the property furColor a relationship type to the Brown node. so instead of keeping the info in the property, you can create additional nodes for all colors, and than just relate the dog nodes with the relationship of type furColor to those color nodes. than, querying would be faster for a MATCH clause like MATCH person-[:has]->dog-[:furColor]->brown (when you also specify the brown node in the START phase)
You can try, this, but measure it against the match performance wise.
path expressions in where return a collection of paths, with the collection functions extract and the collection predicate all you can operate on that collection of paths.
START person=node(1,2,3)
WHERE ALL(dog in extract( path in person-[:has]->() : last(path) // last node of path
WHERE dog.furColor! = "Brown"
)
RETURN person
I am trying to change the index of a node, because there are some specific nodes that at all times needs to be at the bottom of my tree. I tried to change the Node.Index, but that did not change anything. So my question is: How do I change the Index of a PVirtualNode?
Thanks! - Jeff
To change the index of node A, find the node B that has the index you want A to have, and then call Tree.MoveTo(A, B, amInsertBefore, False). B and everything after it will shift down by one to make room for A, and their Index fields will be recalculated. This works even if A doesn't yet exist in the tree (such as just after calling MakeNewNode).
If you're using Index to associate each node with its corresponding data value in a list or array, then you'll find this largely ineffective for re-ordering the displayed values.
You canot change the index of a node. Normally when using VirtualStringTree you hold your data in your own data structure separate from the tree and access the data from the events.
You can also store data directly in the nodes (using a record), but I prefer the other approach because it keeps the logic out of the tree view.
For example, you could store the data in a list and access this list in the GetText handler (you can use Node.Index). Then, if you want to reorder the items, just reorder your list and everything else will happen automatically (you might have to call Invalidate on the tree).
Pseudocode:
Initializing:
Tree.RootNodeCount := MyList.Count;
In the GetTextevent:
NodeText := MyList [Node.Index];
Reordering:
Reorder (MyList);
Tree.Invalidate;
Given that you are still using the tree view control as a container, the ideal solution offered by Smasher is not available to you.
One rather obvious solution, given that your tree view has no hierarchy (i.e. it's a list) would be to use the Sort method with your own compare function (OnCompareNodes).
The other blindingly obvious strategy would be to add the node that you want at the bottom last. If you need to add other nodes later, then insert them above the special last node with InsertNode. This simple approach will probably suffice for the problem as you have described it.
TVirtualNode is a doubly-linked list, it's not a index-based structure: you change the index of a node by removing it and adding it where you want it.
Look into DeleteNode and AddChild.