Error while forcing index in cypher query - neo4j

I am using version 2.0.1 of Neo4j.
I have a label named as prod and a property as id.
My doubt is as follows:
The following query return results very fast:
profile match (p:PROD) where p.id="111" return p;
SchemaIndex(identifier="n", _db_hits=0, _rows=2, label="Prod", query="Literal(111)", property="id")
But when i use a list using IN and force index usage:
profile match (p:PROD) USING INDEX p:PROD(id) where p.id IN ["111","222"] return p;
It shows the following error:
IndexHintException: Cannot use index hint in this context. The label and property comparison must be specified on a non-optional node
Label: `prod`
Property name: `id`
Why can't i use the USE INDEX method to specify the index.? What am i doing wrong? How should i correct it?

WHERE conditions using the IN operator do not use indexes in Neo4j 2.0.x. Please upgrade to 2.1.3 which supports this operation.

Related

Neo4j cypher query fails with unknown syntax error

I have the following paramObj and dbQuery
paramObj = {
email: newUser.email,
mobilenumber: newUser.telephone,
password: newUser.password,
category: newUser.category,
name: newUser.name,
confirmuid: verificationHash,
confirmexpire: expiryDate.valueOf(),
rewardPoints: 0,
emailconfirmed: 'false',
paramVehicles: makeVehicleArray,
paramVehicleProps: vehiclePropsArray
}
dbQuery = `CREATE (user:Person:Owner {email:$email})
SET user += apoc.map.clean(paramObj,
['email','paramVehicles','paramVehiclesProps'],[])
WITH user, $paramVehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
CREATE UNIQUE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v`;
Then I tried to execute
commons.session
.run(dbQuery, paramObj)
.then(newUser => {
commons.session.close();
if (!newUser.records[0]) {........
I am getting
Error: {"code":"Neo.ClientError.Statement.SyntaxError","name":"Neo4jError"}
which doesn't direct me anywhere. Can anyone tell me what am I doing wrong here?
This is actually the first time I am using the query format .run(dbQuery, paramObj) but this format is critical to my use case. I am using Neo4j 3.4.5 community with apoc plugin installed.
Ok...so I followed #inversFalcon suggestion to test in browser and came up with following parameters and query that closely match the ones above:
:params paramObj:[{ email:"xyz123#abc.com", mobilenumber:"8711231234",password:"password1", category:"Owner",name:"Michaell",vehicles:["Toyota","BMW","Nissan"],vehicleProps: [] }]
and query
PROFILE
CREATE (user:Person:Owner {email:$email})
SET user += apoc.map.clean($paramObj, ["email","vehicles","vehicleProps"],[])
WITH user, $vehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
MERGE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v;
Now I get
Neo.ClientError.Statement.TypeError: Can't coerce `List{Map{name -> String("Michaell"), vehicles -> List{String("Toyota"), String("BMW"), String("Nissan")},.......
I also reverted to neo4j 3.2 (re: an earlier post by Mark Needham) and got the same error.
You should try doing an EXPLAIN of the query using the browser to troubleshoot it.
A few of the things I'm seeing here:
You're referring to paramObj, but it's not a parameter (rather, it's the map of parameters you're passing in, but it itself is not a parameter you can reference in the query). If you need to reference the entire set of parameters being passed in, then you need to use nested maps, and have paramObj be a key in the map that you pass as the parameter map (and when you do use it in the query, you'll need to use $paramObj)
CREATE UNIQUE is deprecated, you should use MERGE instead, though be aware that it does behave in a different manner (see the MERGE documentation as well as our knowledge base article explaining some of the easy-to-miss details of how MERGE works).
I am not sure what caused the coercion error to disappear but it did with the same query and I got a "expected parameter error" this was fixed by using $paramObj.email, etc. so the final query looks like this:
CREATE (user:Person:Owner {email: $paramObj.email})
SET user += apoc.map.clean($queryObj, ["email","vehicles","vehicleProps"],[])
WITH user, $paramObj.vehicles AS vehicles
UNWIND vehicles AS vehicle
MATCH(v:Vehicles {name:vehicle})
MERGE (user)-[r:OWNS {since: timestamp()}]->(v)
RETURN user,r,v;
which fixed my original problem of how to remove properties from a map when using SET += map.

Wrong result when query has more filters

MATCH (prs:Issue)-[:REPORTED_BY]-(custs)
MATCH (prs)-[:CLOSED_ON]-(cls:IssueClosedDate)
MATCH (prs)-[:REPORTED_BY]->(custNode:Customer)
MATCH (prs)-[:APP_FUN_CAT]-(afc:AppFunCat)
MATCH (prs)-[:REPORTED_IN]-(release:Release)
WHERE afc.func STARTS WITH 'WEB' AND NOT(cls.closedDate = '' ) AND afc.appName STARTS WITH 'SOCKET'
AND apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') >= apoc.date.parse('01/01/2014','s', 'MM/dd/yyyy')
AND apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') <= apoc.date.parse('06/13/2017','s', 'MM/dd/yyyy')
AND afc.cat IN ["ALL","NEW","SOFTWARE","UNDETERMINED"]
RETURN prs.prId AS prList, custs.customerName AS customer, afc.cat AS category, cls.closedDate AS prClosedDate, release.relName as releaseName `
The above query gives me result shown below:
 "prList"  "funName"  "year"  "afc.appName"  "afc.cat"  "cls.closedDate"  
7371322  "WEB"   "2015"  "SOCKET"   "SOFTWARE"  "4/27/2015"  
8277662  "WEB"   "2015"  "SOCKET"   "SOFTWARE"  "9/24/2015"  
7513015  "WEB"   "2015"  "SOCKET"   "SOFTWARE"  "9/24/2015"
This result is not correct if I check with data base. It should have given more number of list than this.
It is found that if I remove either of the filter
afc.appName STARTS WITH 'SOCKET' or
apoc.date.parse(cls.closedDate,'s', 'MM/dd/yyyy') <= apoc.date.parse('06/13/2017','s', 'MM/dd/yyyy') or
fc.cat IN ["ALL","NEW","SOFTWARE","UNDETERMINED"]
the result I get is correct. So I can say that the database is build properly. Though the above query is showing the three result there are more number of columns.
Is there any limitation from neo4j database that we cannot do this?
Can anybody suggest how can I resolve this problem?
As said by InverseFalcon in comment, version might be the issue. We updated the version as mention below:
Neo4j Browser version: 3.0.1 to 3.2.8
Neo4j Server version: 3.2.0 to 3.4.8 (community)
apoc-3.2.3.5-all.exe to apoc-3.4.0.3-all.exe
Now all the filters are working good. Problem is solved.

Numeric sort in Manual (Legacy) index in Neo4j 3 is not working correctly

I'm using Legacy indexing (now called Manual indexing). After migration from Neo4j 2 to version 3 I have some problems with numeric sorting.
Example of correct statement in Neo4j 2:
queryContext.sort(new Sort(new SortField(AGE, SortField.INT, false)));
This stament should be changed for Neo4j 3 (Lucene 5):
queryContext.sort(new Sort(new SortField(AGE, SortField.Type.INT, false)));
But if you use this sort statement you will get an exception:
java.lang.IllegalStateException: unexpected docvalues type SORTED_SET for field 'firstName' (expected=SORTED). Use UninvertingReader or index with docvalues.
at org.apache.lucene.index.DocValues.checkField(DocValues.java:208)
at org.apache.lucene.index.DocValues.getSorted(DocValues.java:264)
at org.apache.lucene.search.FieldComparator$TermOrdValComparator.getSortedDocValues(FieldComparator.java:762)
at org.apache.lucene.search.FieldComparator$TermOrdValComparator.getLeafComparator(FieldComparator.java:767)
at org.apache.lucene.search.FieldValueHitQueue.getComparators(FieldValueHitQueue.java:183)
at org.apache.lucene.search.TopFieldCollector$SimpleFieldCollector.getLeafCollector(TopFieldCollector.java:164)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.replayTo(DocValuesCollector.java:297)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.getTopDocs(DocValuesCollector.java:275)
at org.neo4j.kernel.api.impl.index.collector.DocValuesCollector.getIndexHits(DocValuesCollector.java:150)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.search(LuceneLegacyIndex.java:346)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:261)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:205)
at org.neo4j.index.impl.lucene.legacy.LuceneLegacyIndex.query(LuceneLegacyIndex.java:217)
at org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeLegacyIndexQuery(StateHandlingStatementOperations.java:1440)
at org.neo4j.kernel.impl.api.OperationsFacade.nodeLegacyIndexQuery(OperationsFacade.java:1162)
at org.neo4j.kernel.impl.coreapi.LegacyIndexProxy$Type$1.query(LegacyIndexProxy.java:83)
at org.neo4j.kernel.impl.coreapi.LegacyIndexProxy.query(LegacyIndexProxy.java:365)
I think this is caused by new added statement in Neo4j indexer class (Neo4j is indexing field for sorting automatically now?). See in:
org.neo4j.index.impl.lucene.legacy.IndexType CustomType addToDocument( Document document, String key, Object value )
new line:
document.add( instantiateSortField( key, value ) );
and method instantiateSortField is creating SortedSetDocValuesField
So I changed my code to:
queryContext.sort(new Sort(new SortedSetSortField(AGE, false)));
This runs OK but sorting is not working because numbers are sorted as string. I see that "value" parameter is String every time in method "addToDocument". I think the root cause is explained it this old comment:
see comment in class org.neo4j.index.impl.lucene.legacy.IndexType CustomType
// TODO We should honor ValueContext instead of doing value.toString() here.
// if changing it, also change #get to honor ValueContext.
Am I missing some new way how to index, search and sort data in Neo4j 3 or this is really problem that values are indexed as string in Neo4j?
Simple unit test for Neo4j 2 and Neo4j 3 can be downloaded
Solution added by MishaDemianenko at GH issue

allShortestPaths: Unknown Identifier

Im currently writing a query to return a VIRTUEALSUITE with its belonging PRODUCT_VERSIONS and their children (recursively).
Here is my current query:
MATCH (vs: VIRTUALSUITE {NAME: "Test VS Copy"})-[:INCLUDES_VERSION]->(productVersion: PRODUCT_VERSION)
MATCH allShortestPaths((productVersion)-[:IS_BOMPARENT_OF*..]->(child: PRODUCT_VERSION))
RETURN vs, productVersion, child
I need the "allShortestPaths" function. Otherwise queries like this take an infinite time.
But as a result of this query i just get the error message:
Unknown identifier `child`
Unknown identifier `vs`.
Unknown identifier `productVersion`.
Unknown identifier `child`.
As u will probably notice, I'm quite new to this. Would be very nice, if you could help me out! :)
Thanks a lot and Greetings
Schakron
It appears you are using version 2.0 of neo4j. Your Cypher query should work in versions 2.1 and above.
See this console. You can change the version used by the console by clicking the Options button at the top.
Also, I believe you would want to return the shortest paths:
MATCH (vs: VIRTUALSUITE {NAME: "Test VS Copy"})-[:INCLUDES_VERSION]->(productVersion: PRODUCT_VERSION)
MATCH p = allShortestPaths((productVersion)-[:IS_BOMPARENT_OF*..]->(child: PRODUCT_VERSION))
RETURN vs, productVersion, child, p

Cypher query for externalized property values

in our data model we have externalized some of our domain entities values into external nodes. The model for a service object looks like:
ref=node(0),
ref<-[:SERVICE]-subRefNode<-[:SERVICE]-aService-[:HAS_PROPERTY_VALUE]->propValueNode-[:IS_OF_TYPE]->propDefType,
ref<-[:SERVICE]-subRefNode-[:HAS_PROPERTY]->propDefType
The node subRefNode holds a relationship to all services. All possible properties for a service are defined through ref<-[:SERVICE]-subRefNode-[:HAS_PROPERTY]->propDefType. So it could be that a certain node doesn't have a propValueNode yet for a certain property (e.g. a comment) and others might have one but its empty (the user might have entered a comment and then cleared it).
So my question is how do I get the nodes with an empty propValueNode.value and also the ones that do not have a propertyValueNode yet? I thought about something like...
START ref=node(0) MATCH ref<-[:SERVICE]-subRef, aService-[pvRel?:HAS_PROPERTY_VALUE]->propValueNode-[pdRel:IS_OF_TYPE]->propDef<-[:HAS_PROPERTY]-subRef<-[:SERVICE]-aService WHERE (pvRel IS NOT NULL AND propDef.name = 'comment' AND propValueNode.value=~"^$") OR (pvRel IS NULL AND pdRel IS NULL AND propDef.name="comment") RETURN DISTINCT aService.debug
http://console.neo4j.org/r/7zeoay
...but this misses the ones without a propValueNode. Any hints are appreciated!
Regards,
Andi
If http://console.neo4j.org/r/7zeoay is not valid anymore, here's the initial graph setup:
start _0 = node(0) with _0
create
(_1 {type:"SubReferenceNode", name:"SubRef"}),
(_2 {type:"Service", debug:"S0 empty value"}),
(_3 {type:"Service", debug:"S1 missing value node"}),
(_4 {type:"Service", debug:"S2 with value"}),
(_5 {type:"PropertyDefintion", name:"comment"}),
(_6 {type:"PropertyDefintion", name:"name"}),
(_7 {type:"PropertyValue", value:"S0 empty value"}),
(_8 {type:"PropertyValue", value:"S1 missing value node"}),
(_9 {type:"PropertyValue", value:"S2 with value"}),
(_10 {type:"PropertyValue", value:""}),
(_11 {type:"PropertyValue", value:"This is a comment"}),
_0<-[:SERVICE]-_1,
_1<-[:SERVICE]-_2,
_1<-[:SERVICE]-_3,
_1<-[:SERVICE]-_4,
_1-[:HAS_PROPERTY]->_5,
_1-[:HAS_PROPERTY]->_6,
_2-[:HAS_PROPERTY_VALUE]->_7,
_7-[:IS_OF_TYPE]->_6,
_3-[:HAS_PROPERTY_VALUE]->_8,
_8-[:IS_OF_TYPE]->_6,
_4-[:HAS_PROPERTY_VALUE]->_9,
_9-[:IS_OF_TYPE]->_6,
_2-[:HAS_PROPERTY_VALUE]->_10,
_10-[:IS_OF_TYPE]->_5,
_4-[:HAS_PROPERTY_VALUE]->_11,
_11-[:IS_OF_TYPE]->_5
You can combine two queries, one is to return the service which has an empty value for the property "comment", and another returns the service which does not have a propery value that is of the type "comment", in other word, none of the service property values is of the the type "comment".
START ref=node(0)
MATCH ref<-[:SERVICE]-subRef, aService-[pvRel?:HAS_PROPERTY_VALUE]->propValueNode-[pdRel:IS_OF_TYPE]->propDef<-[:HAS_PROPERTY]-subRef<-[:SERVICE]-aService
WHERE (pvRel IS NOT NULL AND propDef.name = 'comment' AND propValueNode.value=~"^$")
RETURN DISTINCT aService.debug
UNION
START ref=node(0)
MATCH ref<-[:SERVICE]-subRef, aService-[pvRel:HAS_PROPERTY_VALUE]->propValueNode-[pdRel:IS_OF_TYPE]->propDef<-[:HAS_PROPERTY]-subRef<-[:SERVICE]-aService
with aService, collect(propDef.name) as propNames
WHERE NONE( propName in propNames where propName = 'comment')
RETURN DISTINCT aService.debug
The alternative solution without using the "UNION" clause is to get all value nodes for each service and returns only those service that either none of its values is of type "comment" or there is one value of the type "comment" and the value is empty, as shown in the "Where" clause below,
START ref=node(0)
MATCH ref<-[:SERVICE]-subRef, aService-[pvRel:HAS_PROPERTY_VALUE]->propValueNode-[pdRel?:IS_OF_TYPE]->propDef<-[:HAS_PROPERTY]-subRef<-[:SERVICE]-aService
WHERE propDef.name = 'comment'
WITH aService, collect(propValueNode) AS valueNodes, propDef
WHERE NONE (v IN valueNodes
WHERE v-[:IS_OF_TYPE]->propDef) OR SINGLE (v IN valueNodes
WHERE v.value=~"^$" AND v-[:IS_OF_TYPE]->propDef)
RETURN aService.debug

Resources