I'm learning Jetpack Compose by this article http://intelligiblebabble.com/compose-from-first-principles/ , which explain the principle of Compose in a very comprehensible way. However i'm stuck in the conception of "Groups" which handle the cache misalignment when the structure of ui tree changes. It's really hard for me to understand what actually the Groups did. Begging for any comprehensible explanation, thanks!!!
First, a group is an internal runtime concept that you really don't need to understand to use compose. That said, a group, from the runtime's perspective is a group of nodes (or other state information) that are composed together. They enter, leave, and move around together.
This can most easily be seen with a function; a function implies a group. Consider the following function:
#Composable
fun MyText() {
Text("one")
Text("two")
Text("three")
}
This function generates three layout nodes, one for each block of text, but the layout nodes enter, leave, and move together as a group. Either they all are are emitted or none of them are.
Now consider the following,
#Composable
fun MyTexts(a: Boolean, b: Boolean, c: Boolean) {
Column {
if (a) {
MyText()
}
if (b) {
MyText()
}
if (c) {
MyText()
}
}
}
You can see here that the text nodes are emitted conditionally on a, b and c. As the values change all three of the implied nodes are added or removed together. The Column node, however, doesn't know anything about the group, it just get told that the nodes are added and removed, there isn't a node that represents the three nodes together in the tree. What tracks that the three nodes from MyText are insert and deleted together is the group maintained internally by the runtime.
Now consider the case where the parameter are initially true and then later b becomes false the group makes it easy for the runtime to determine that nodes 3, 4 and 5 need to be removed from the Column node without having to know what MyText did to produce them. Later, if b becomes true again, it is easy to determine that three nodes need to be inserted at index 3 (after the three nodes inserted because a is true).
Related
Given a neo4j database containing vertices which are either of type folder or leaf. A general tree is modelled using :childof relations, and there is a single 'root' node which is the common ancestor for all vertices.
When presenting the tree, I want to filter out either full branches based on the id of any vertex of type folder. Additionally there is a filter for any properties on vertices of type leaf. The tricky part is that I do not want to see any folders where all descendant leaf nodes are filtered out. Each query only returns immediate descendants, but the filter is applied to the whole subtree. The query must return the immediate children, and a collection of the id of each folder containing leafs which are not filtered out.
The use case is an API for showing a hierarchy based on some filter constraints. I have programmed this in the API application code, but transferring all data from the db to the API application is too slow, so I need to improve the query to condense the data transfer. A third approach is using a purpose built process that does this filtering, keeping the tree in memory. This has been done with some success, but I prefer to use shelf-ware if I can.
The following code is used to get the top level nodes, without filtering. I struggle with expressing MATCH only if at least one descendant also matches
MATCH (p)-[:childof]->(s:Folder) WHERE s.name = 'root'
WITH p OPTIONAL MATCH (v)-[:childof*1..]->(p)
WHERE NOT((v)<-[:childof]-(:Folder))
RETURN p, collect(v.id) as folder_ids
My personal inclination to the problem is that it is too specific for a general purpose graph engine, but I am hoping to be proved wrong.
It sounds like you're close.
We can use pattern comprehensions at the folder level to check for children that meet the filter, and make sure we only keep folders that have at least one child that meets the filter criteria.
And at the immediate descendent level, if we use a MATCH instead of an OPTIONAL MATCH, since folders will get filtered for you, the only immediate descendants that are left are ones with at least one of these folders.
Let's say for example that our filter is that leaf nodes must have active = true, so we want to make sure that our folders for consideration must have at least one child node meeting the filter, and when we get back to the immediate descendants, we only want to keep that descendent if the collection of eligible folders isn't empty.
Something like this:
MATCH (p)-[:childof]->(s:Folder) WHERE s.name = 'root'
WITH p
MATCH (folder)-[:childof*1..]->(p)
WHERE NOT((folder)<-[:childof]-(:Folder)) AND
size([(folder)<-[:childof]-(child) WHERE child.active = true | child]) <> 0
RETURN p, collect(folder.id) as folder_ids
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.
Totally new to graph databases -- corrections welcome.
If I want to obtain a list of nodes labeled with the "User" label, does neo4j (or possibly other graph databases) need to search all nodes for that label or does it somehow auto-index nodes by label?
Without indexing, (horrible performance) every node is queried to see if any one of its labels matches "User," like so:
List<Node> userNodes = new List<Node>();
for (Node node : all_nodes)
{
for (Label label : node.labels())
{
if (label.name() == "User")
{
userNodes.Add(node);
// no need to look at other labels for this node
break;
}
}
}
return userNodes;
With indexing, the system grabs some system-managed "node" that has all of the label names under it (search space of dozens instead of millions) and grabs its children:
List<Node> userNodes = new List<Node>();
for (Node labelNode : labels_node) // where labels_node is system-managed
{
if (labelNode.name() == "User")
{
// All children of the "User" node have the label "User"
userNodes = labelNode.children();
// No need to look at other labels
break;
}
}
return userNodes;
Ultimately, I think this question gets to this: if I am building a list of "things" for which I need to retrieve all of them by type of thing, should I use labels to accomplish this? Or should I instead create my own "Users" node, which points to all nodes that are users, and only use labels once I have found the subset of nodes I want?
It seems this question is similar though more vague but did not receive a satisfactory answer.
Terminology wise, the docs talk about "labels and schema indexes". An "index" is a thing that you attach on a label property, such as indexing all first_name attributes of :Person nodes.
But for your question, labels behave like indexes because yes, the execution engine takes advantage of them and use them like you'd expect an index, even though the documentation doesn't talk about labels as indexes.
So, for a concrete example, suppose we had a graph of 1 million nodes, of which 5 of them had the label :Person. And suppose we had the following query:
MATCH (p:Person) RETURN p;
The question boils down to, how many nodes does cypher have to consider? The answer is 5, not 1 million.
Your second code snippet is more of a neo4j version 1.9 kind of approach; nowadays I wouldn't create these artificial "index nodes", and I wouldn't loop through all possible labels, I'd just match by label and be done with it.
Yes labels are indexed automatically, meaning that if you have 1000 user nodes where 700 are active users, querying for the Active label will only return you the 700 active users without looking up for the others.
Having super nodes and connecting to them the related ones is a (almost always) bad idea.
Also, you should model your database for querying purposes, look this amazing answer :
Neo4J - Storing into relationship vs nodes
There is a topic too for the difference between using labels or indexed properties on nodes, this blog post is explaining it very well :
http://graphaware.com/neo4j/2015/01/16/neo4j-graph-model-design-labels-versus-indexed-properties.html
You should also profile your queries, meaning also it is non sense to start importing 1million nodes at the beginning, try with 100 and do some queries.
I heard an amazing sentence from someone at the neo4j hq :
Be faithful to your graph and the graph will be faithful to you
Find your way to do it at a manner that it solves your problem !
There is a dedicated method in
ops = GlobalGraphOperations.at(gdb);
for (Node node : ops.getAllNodesWithLabel(DynamicLabel.label("User")) {
// do sth with node
}
which uses the optimized label-scan-store behind the scenes.
My graph is composed of multiple "sub-graphes" that are disconnected from one another. These sub-graphes are composed of nodes that are connected with a given relation type.
I would like to get (for example) the list of sub-graphes that contain at least one node that has the property "name" equals "John".
It's equivalent to finding one node per subgraph having this property.
One solution would be to find all the nodes having this property and loop through this list to only pick the ones that are not connected to the previously picked ones. But that would be ugly and quite heavy. Is there an elegant way to do that with Cypher?
I'm trying with something along this direction but have no success so far:
START source=node:user('name:"John"')
MATCH source-[r?:KNOWS*]-target
WHERE r is null
RETURN source
Try this one it may help
START source=node:user('name:"John"')
MATCH source-[r:KNOWS]-()-[r2:KNOWS]-target
WHERE NOT(source-[r:KNOWS]-target)
RETURN target
I'm playing around with neo4j, and I was wondering, is it common to have a type property on nodes that specify what type of Node it is? I've tried searching for this practice, and I've seen some people use name for a purpose like this, but I was wondering if it was considered a good practice or if indexes would be the more practical method?
An example would be a "User" node, which would have type: user, this way if the index was bad, I would be able to do an all-node scan and look for types of user.
Labels have been added to neo4j 2.0. They fix this problem.
You can create nodes with labels:
CREATE (me:American {name: "Emil"}) RETURN me;
You can match on labels:
MATCH (n:American)
WHERE n.name = 'Emil'
RETURN n
You can set any number of labels on a node:
MATCH (n)
WHERE n.name='Emil'
SET n :Swedish:Bossman
RETURN n
You can delete any number of labels on a node:
MATCH (n { name: 'Emil' })
REMOVE n:Swedish
Etc...
True, it does depend on your use case.
If you add a type property and then wish to find all users, then you're in potential trouble as you've got to examine that property on every node to get to the users. In that case, the index would probably do better- but not in cases where you need to query for all users with conditions and relations not available in the index (unless of course, your index is the source of the "start").
If you have graphs like mine, where a relation type implies two different node types like A-(knows)-(B) and A or B can be a User or a Customer, then it doesn't work.
So your use case is really important- it's easy to model graphs generically, but important to "tune" it as per your usage pattern.
IMHO you shouldn't have to put a type property on the node. Instead, a common way to reference all nodes of a specific "type" is to connect all user nodes to a node called "Users" maybe. That way starting at the Users node, you can very easily find all user nodes. The "Users" node itself can be indexed so you can find it easily, or it can be connected to the reference node.
I think it's really up to you. Some people like indexed type attributes, but I find that they're mostly useful when you have other indexed attributes to narrow down the number of index hits (search for all users over age 21, for example).
That said, as #Luanne points out, most of us try to solve the problem in-graph first. Another way to do that (and the more natural way, in my opinion) is to use the relationship type to infer a practical node type, i.e. "A - (knows) -> B", so A must be a user or some other thing that can "know", and B must be another user, a topic, or some other object that can "be known".
For client APIs, modeling the element type as a property makes it easy to instantiate the right domain object in your client-side code so I always include a type property on each node/vertex.
The "type" var name is commonly used for this, but in some languages like Python, "type" is a reserved word so I use "element_type" in Bulbs ( http://bulbflow.com/quickstart/#models ).
This is not needed for edges/relationships because they already contain a type (the label) -- note that Neo4j also uses the keyword "type" instead of label for relationships.
I'd say it's common practice. As an example, this is exactly how Spring Data Neo4j knows of which entity type a certain node is. Each node has "type" property that contains the qualified class name of the entity. These properties are automatically indexed in the "types" index, thus nodes can be looked up really fast. You could implement your use case exactly like this.
Labels have recently been added to Neo4j 2.0 ( http://docs.neo4j.org/chunked/milestone/graphdb-neo4j-labels.html ). They are still under development at the moment, but they address this exact problem.