I am trying to persist just a relationship in Neo4j but doesn't work. See my query. My domain object has this relationship to itself.
#RelatedTo (type="PLUS_ME", direction = Direction.BOTH)
private Set<Errand> plusMe;
Then I run this query with a GraphRepository.
Errand e = new Errand ();
Errand e1 = new Errand ();
e = template.save(e);
e1 = template.save(e1);
p (e.getId() + " " + e1.getId ());
String query = "MATCH (one:Errand)" +
"WHERE one.id = " + e.getId() +
"MATCH (two:Errand)" +
"WHERE two.id = " + e1.getId() +
"CREATE (one)-[b:PLUS_ME]->(two)" +
"CREATE (two)-[a:PLUS_ME]->(one)";
eRepo.query(query, null);
But when I run this query with junit I get 0 as the size that is.
eRepo.findByPlusMe(e).size();
use parameters
you don't need the inverse relationship
are you sure your match statements returns the correct errands?
can you show the structure of your Errand class?
is your findByPlusMe repository query a annotated or derived query?
Related
String query = "START n1=node:TEST_INDEX(nodeName='" + elementID
+ "') match n1-[:hasSubClass]->n2-[:hasPropertyGroup]->n3-[:containsProperty]->n4 with n2 match n2-[:hasInstance]->n5 "
+ "where n2.elementType='class' and not(n4.status! = 'Deleted') and n4.nodeName! =~ '(?i)" + propertyName + "' and where count(n5)=0 return n4,count(n5)";
I am trying to convert this particular query to MATCH query facing issue in understanding these conditions
not(n4.status! = 'Deleted') and n4.nodeName! =~ '(?i)" + propertyName
+ "'
I tried to change the query :-
MATCH(n1:TESTDATA{nodeName:'ProductConcept'})
match (n1)-[:hasSubClass]->(n2)-[:hasPropertyGroup]->(n3)-[:containsProperty]->(n4) with n2,n4
match (n2)-[:hasInstance]->(n5)
where n2.elementType='class'
and NOT EXISTS(n4.status)
and n4.nodeName <>'(?i)view'
//and where count(n5)=0
return n4,count(n5)
Assuming you pass elementId and propertyName as parameters, this Cypher seems to be equivalent to the intent of your original query:
START n1=node:TEST_INDEX(nodeName=$elementId)
MATCH (n1)-[:hasSubClass]->(n2)-[:hasPropertyGroup]->()-[:containsProperty]->(n4)
WHERE
n2.elementType = 'class' AND
n4.status = 'Deleted' AND
(NOT n4.nodeName =~ ('(?i)' + $propertyName)) AND
SIZE((n2)-[:hasInstance]->()) = 0
RETURN n4
This query does not bother to return the equivalent of COUNT(n5), since the query requires that the value must always be 0.
I am creating nodes in Neo4j using neo4j-java driver with the help of following Cipher Query.
String cipherQuery = "CREATE (n:MLObsTemp { personId: " + personId + ",conceptId: " + conceptId
+ ",obsId: " + obsId + ",MLObsId: " + mlObsId + ",encounterId: " + encounterId + "}) RETURN n";
Function for creating query
createNeo4JObsNode(String cipherQuery);
Implementation of the Function
private void createNeo4JObsNode(String cipherQuery) throws Exception {
try (ConNeo4j greeter = new ConNeo4j("bolt://localhost:7687", "neo4j", "qwas")) {
System.out.println("Executing query : " + cipherQuery);
try (Session session = driver.session()) {
StatementResult result = session.run(cipherQuery);
} catch (Exception e) {
System.out.println("Error" + e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
Making relation for the above nodes using below code
String obsMatchQuery = "MATCH (m:MLObsTemp),(o:Obs) WHERE m.obsId=o.obsId CREATE (m)-[:OBS]->(o)";
createNeo4JObsNode(obsMatchQuery);
String personMatchQuery = "MATCH (m:MLObsTemp),(p:Person) WHERE m.personId=p.personId CREATE (m)-[:PERSON]->(p)";
createNeo4JObsNode(personMatchQuery);
String encounterMatchQuery = "MATCH (m:MLObsTemp),(e:Encounter) WHERE m.encounterId=e.encounterId CREATE (m)-[:ENCOUNTER]->(e)";
createNeo4JObsNode(encounterMatchQuery);
String conceptMatchQuery = "MATCH (m:MLObsTemp),(c:Concept) WHERE m.conceptId=c.conceptId CREATE (m)-[:CONCEPT]->(c)";
createNeo4JObsNode(conceptMatchQuery);
It is taking me 13 seconds on average for creating nodes and 12 seconds for making relations. I have 350k records in my database for which I have to create nodes and their respective relations.
How can I improve my code? Moreover, is this the best way for creating nodes in Neo4j using bolt server and neo4j-java driver?
EDIT
I am now using the query parameter in my code
HashMap<String, Object> parameters = new HashMap<String, Object>();
((HashMap<String, Object>) parameters).put("personId", 1390);
((HashMap<String, Object>) parameters).put("obsId", 14001);
((HashMap<String, Object>) parameters).put("conceptId", 5978);
((HashMap<String, Object>) parameters).put("encounterId", 10810);
((HashMap<String, Object>) parameters).put("mlobsId", 2);
String cypherQuery=
"CREATE (m:MLObsTemp { personId: $personId, ObsId: $obsId, conceptId: $conceptId, MLObsId: $mlobsId, encounterId: $encounterId}) "
+ "WITH m MATCH (p:Person { personId: $personId }) CREATE (m)-[:PERSON]->(p) "
+ "WITH m MATCH (e:Encounter {encounterId: $encounterId }) CREATE (m)-[:Encounter]->(e) "
+ "WITH m MATCH (o:Obs {obsId: $obsId }) CREATE (m)-[:OBS]->(o) "
+ "WITH m MATCH (c:Concept {conceptId: $conceptId }) CREATE (m)-[:CONCEPT]->(c) "
+ " RETURN m";
Creating Node function
try {
ConNeo4j greeter = new ConNeo4j("bolt://localhost:7687", "neo4j", "qwas");
try {
Session session = driver.session();
StatementResult result = session.run(cypherQuery, parameters);
System.out.println(result);
} catch (Exception e) {
System.out.println("[WARNING] Null Row");
}
} catch (Exception e) {
e.printStackTrace();
}
I am also performing the indexing in order to speed up the process
CREATE CONSTRAINT ON (P:Person) ASSERT P.personId IS UNIQUE
CREATE CONSTRAINT ON (E:Encounter) ASSERT E.encounterId IS UNIQUE
CREATE CONSTRAINT ON (O:Obs) ASSERT O.obsId IS UNIQUE
CREATE CONSTRAINT ON (C:Concept) ASSERT C.conceptId IS UNIQUE
Here is the plan for 1 cypher query-profile
Now the performance has improved but not significant. I am using neo4j-java-driver version 1.6.1. How can I batch my cipher queries to improve the performance further.
You should try to minimize redundant work in your cyphers.
MLObsTemp has a lot of redundant properties, and you are searching for it to create every link. Relationships defeat the need to create properties for foreign keys (node ids)
I would recommend a Cypher that does everything together, and uses parameters like this...
CREATE (m:MLObsTemp)
WITH m MATCH (p:Person {id:"$person_id"}) CREATE (m)-[:PERSON]->(p)
WITH m MATCH (e:Encounter {id:"$encounter_id"}) CREATE (m)-[:Encounter]->(e)
WITH m MATCH (c:Concept {id:"$concept_id"}) CREATE (m)-[:CONCEPT]->(c)
// SNIP more MATCH/CREATE
RETURN m
This way, Neo4j doesn't have to find m repeatedly for every relationship. You don't need the ID properties, because that is effectively what the relationship you just created is. Neo4j is very efficient at walking edges (relationships), so just follow the relationship if you need the id value.
TIPS: (mileage may very across Neo4j versions)
Inline is almost always more efficent than WHERE (MATCH (n{id:"rawr"}) vs MATCH (n) WHERE n.id="rawr")
Parameters make frequent, similar queries more efficient, as Neo4j will cache how to do it quickly (the $thing_id syntax used in the above query.) Also, It protects you from Cypher injection (See SQL injection)
From a Session, you can create a Transaction (Session.run() actually creates a transaction for each run call). You can batch multiple Cyphers using a single transaction (Even using the results of previous Cyphers from the same transaction), because transactions live in memory until you mark it a success and close it. Note that if you are not careful, your transaction can fail with "outofmemory". So remember to commit periodically/between batches. (commit batches of 10k records seems to be the norm when ingesting large data sets)
I have a graph that consists of DATASET and GRAPH nodes. With the following relationships:
DATASET->READS->GRAPH
GRAPH->WRITES->DATASET
When I run the following : MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN p
In Neo4J Desktop I get a result that is correct, where node names are present. But when I run it in py2neo:
graph.run("MATCH (p1:DATASET_NAME {
name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN p").dump()
I get a result in the following format:
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(f9ddd22)-[:READS]->(fcca016)-[:WRITES]->(e152f69)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
(f3ff862)-[:READS]->(c539bdc)-[:WRITES]->(b217f5a)-[:READS]->(ebf9c4f)-[:WRITES]->(cbc5d42)-[:READS]->(fcca016)-[:WRITES]->(a9c241a)
I am assuming that these are some sort of references. Is there a way where I can get the string value for name from these references?
You are returning the matched path so what you see in py2neo is the representation of the path object. In the neo4j console it does a little extra looking up for you and presents the path as a set of nodes and relationships and it labels them according to what you have configured in the console.
If you want to see the names in your py2neo output you could use the reduce function on the returned path p to produce a string with the node names and relationship types. Something like this should get you started.
MATCH (p1:DATASET_NAME { name:'test1.dat' }),(p3:DATASET_NAME { name:'test32.txt' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3))
RETURN head(nodes(p)).name + ' - ' + reduce(path_str = "", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)
In py2neo [Note the escape characters added in order to avoid cypher error. # ...reduce(path_str = \"\"... ]:
graph.run("MATCH (p1:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/data/serial/temp/yyyymmdd_yyyymmddhhmiss_bk_mrk_stat_init.dat' }),(p3:DATASET_NAME { name:'/projects/bkrpty_vfcn/bkrpty_vfcn_vendr/tables/onevgb1/ai_bkrpty_case' }), p = ((p1)-[:READS|:WRITES*1..8]->(p3)) RETURN head(nodes(p)).name + ' - ' + reduce(path_str = \"\", r in relationships(p) | path_str + type(r) + ' - ' + endnode(r).name)").dump()
I am looking for a query where i can return all work items and their relation from a area path.
for example : project 1
i need all Featured all Userstories mapped to it all workitem and Bug mapped to userstories,
in short if i took a bug from the object i need somthing like parent id where i can match with the userstory.
string query1 = " SELECT * FROM WorkItemLinks " +
" WHERE ( [System.IterationPath] Under 'iteration1' )" +
" AND ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward' )" +
" ORDER BY [Microsoft.VSTS.Scheduling.StartDate]";
which throwing an error like below
An exception of type 'Microsoft.TeamFoundation.WorkItemTracking.Client.ValidationException' occurred in Microsoft.TeamFoundation.WorkItemTracking.Client.dll but was not handled in user code
Additional information: TF51005: The query references a field that does not exist. The error is caused by «[System.IterationPath]».
when i checked the dll's are refereed correctly and when i re wrote the query like this the query is working fine
string query = " SELECT * FROM WorkItems"+
" WHERE ( [System.IterationPath] Under 'iteration1' )" +
//" AND ([System.State] = 'Active' OR [System.State] = 'Assessed' ) "+
//" AND ( [Microsoft.VSTS.Scheduling.StartDate] <= '09/13/2017' AND [Microsoft.VSTS.Scheduling.FinishDate] >= '09/13/2017' )"+
" ORDER BY [Microsoft.VSTS.Scheduling.StartDate]";
but this query result does not give the relation ship that if a work item mapped as a child to other i need parent id in the work item object. how to get that. Thanks in advance.
You can try below query:
Install Nuget Package Microsoft.TeamFoundationServer.ExtendedClient for the project.
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
namespace _0925_WIQL
{
class Program
{
static void Main(string[] args)
{
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(
new Uri("http://server:8080/tfs/CollectionLC"));
WorkItemStore workItemStore = (WorkItemStore)tpc.GetService(typeof(WorkItemStore));
string query1= " SELECT * FROM WorkItemLinks " +
" WHERE ( Source.[System.IterationPath] Under 'TeamProject\\Iteration 1' )" +
" AND ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward' )" +
" ORDER BY [Microsoft.VSTS.Scheduling.StartDate]";
Query query = new Query(workItemStore, query1);
WorkItemLinkInfo[] witLinkInfos = query.RunLinkQuery();
foreach (WorkItemLinkInfo witinfo in witLinkInfos)
{
.......
}
Besides, you can also use Wiql Editor. If you want to get all the parent workitems (IDs) from a specific child work item (ID), you can use below WIQL:
SELECT
[System.Id],
[System.WorkItemType],
[System.Title],
[System.AssignedTo],
[System.State]
FROM workitemLinks
WHERE ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward')
AND ([Target].[System.Id] = 25)
ORDER BY [System.Id]
MODE (Recursive, ReturnMatchingChildren)
I have the following java code snippet that demonstrates the problem. The error I receive is also included below.
It correctly pulls the correct set, but I am having trouble printing.
I'm using the org.neo4j.graphdb.Node node. Is this the wrong class?
If not, how do I obtain the results movieid, avgrating and movie_title from the ExecutionEngine?
Java Code
GraphDatabaseService db = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
ExecutionEngine engine = new ExecutionEngine(db);
String cypherQuery = "MATCH (n)-[r:RATES]->(m) \n"
+ "RETURN m.movieid as movieid, avg(toFloat(r.rating)) as avgrating, m.title as movie_title \n"
+ "ORDER BY avgrating DESC \n"
+ "LIMIT 20;";
ExecutionResult result = engine.execute(cypher);
for (Map<String, Object> row : result) {
Node x = (Node) row.get("movie_title");
for (String prop : x.getPropertyKeys()) {
System.out.println(prop + ": " + x.getProperty(prop));
}
}
Error
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.neo4j.graphdb.Node
at beans.RecommendationBean.queryMoviesWithCypher(RecommendationBean.java:194)
at beans.RecommendationBean.main(RecommendationBean.java:56)
Node x = (Node) row.get("movie_title");
...looks to be the culprit.
In your Cypher statement, you return m.title as movie_title, i.e. you're returning a node property (in this case, a string), and, in the offending line, you're trying to cast that string result as a Node.
If you want Cypher to return a series of nodes you can iterate through, try returning m (the whole node) instead of just individual properties and aggregates, e.g.
"...RETURN m AS movie;"
...
Node x = (Node) row.get("movie");
Etc.