Struggling to perform an Index Cypher Query in Neo4jClient.NET - neo4j

I am try to perform a query on my NameIndex in Neo4j using the Neo4jClient for .NET but i get this error:
{"Received an unexpected HTTP status when executing the request.\r\n\r\nThe response status was: 500 Internal Server Error\r\n\r\nThe raw response body was: {\"exception\":\"NullPointerException\",\"stacktrace\":[\"org.apache.lucene.util.SimpleStringInterner.intern(SimpleStringInterner.java:54)\",\"org.apache.lucene.util.StringHelper.intern(StringHelper.java:39)\",\"org.apache.lucene.index.Term.<init>(Term.java:38)\",\"org.apache.lucene.queryParser.QueryParser.getFieldQuery(QueryParser.java:643)\",\"org.apache.lucene.queryParser.QueryParser.Term(QueryParser.java:1421)\",\"org.apache.lucene.queryParser.QueryParser.Clause(QueryParser.java:1309)\",\"org.apache.lucene.queryParser.QueryParser.Query(QueryParser.java:1237)\",\"org.apache.lucene.queryParser.QueryParser.TopLevelQuery(QueryParser.java:1226)\",\"org.apache.lucene.queryParser.QueryParser.parse(QueryParser.java:206)\",\"org.neo4j.index.impl.lucene.IndexType.query(IndexType.java:300)\",\"org.neo4j.index.impl.lucene.LuceneIndex.query(LuceneIndex.java:227)\",\"org.neo4j.server.rest.web.DatabaseActions.getIndexedNodesByQuery(DatabaseActions.java:977)\",\"org.neo4j.server.rest.web.DatabaseActions.getIndexedNodesByQuery(DatabaseActions.java:960)\",\"org.neo4j.server.rest.web.RestfulGraphDatabase.getIndexedNodesByQuery(RestfulGraphDatabase.java:692)\",\"java.lang.reflect.Method.invoke(Unknown Source)\"]}"}
My method looks as follows:
public IEnumerable GraphGetNodeByName(string NodeName)
{
GraphOperationsLogger.Trace("Now entering GraphGetNodeByName() method");
IEnumerable QueryResult = null;
GraphOperationsLogger.Trace("Now performing the query");
var query = client_connection.QueryIndex<GraphNode>("NameIndex", IndexFor.Node,
//Here I want to pass in the NodeName into the query
//#"Start n = node:NameIndex(Name = '"+ NodeName +"') return n;");
//Here I am hard-coding the NodeName
#"Start n = node:NameIndex(Name = ""Mike"") return n;");
QueryResult = query.ToList();
return QueryResult;
}
I ideally would like to pass in the NodeName into the query but that is not working therefore I have tried hard-coding it in and that also doesn't work. Both scenarios produce the same error message?

The method you are calling, IGraphClient.QueryIndex is not a Cypher method. It's a wrapper on http://docs.neo4j.org/chunked/milestone/rest-api-indexes.html#rest-api-find-node-by-query. It's an older API, from before Cypher existed.
You're already half way there though, because your code comments include the Cypher query:
Start n = node:NameIndex(Name = "Mike")
return n;
So, let's just translate that into C#:
client
.Cypher
.Start(new CypherStartBitWithNodeIndexLookup("n", "NameIndex", "Name", "Mike"))
.Return<Node<Person>>("n");
Always start your Cypher queries from IGraphClient.Cypher or NodeReference.StartCypher (which is just a shortcut to the former).
There are some other issues with your method:
You're returning a raw IEnumerable. What is in it? You should return IEnumerable<T>.
You're calling query.ToList(). I'd be surprised if that even compiles. You want to call ToList on the results so that the enumerable is hit.
In C#, your local variables should be in camelCase not PascalCase. That is, queryResult instead of QueryResults.
Combining all of those points, your method should be:
public IEnumerable<Person> GetPeopleByName(string name)
{
return graphClient
.Cypher
.Start(new CypherStartBitWithNodeIndexLookup("n", "NameIndex", "Name", "Mike"))
.Return<Node<Person>>("n")
.Results
.ToList();
}

Related

this method cannot be translated into a store expression [duplicate]

I saw this code work with LINQ to SQL but when I use Entity Framework, it throws this error:
LINQ to Entities does not recognize the method 'System.Linq.IQueryable'1[MyProject.Models.CommunityFeatures] GetCommunityFeatures()' method, and this method cannot be translated into a store expression.`
The repository code is this:
public IQueryable<Models.Estate> GetEstates()
{
return from e in entity.Estates
let AllCommFeat = GetCommunityFeatures()
let AllHomeFeat = GetHomeFeatures()
select new Models.Estate
{
EstateId = e.EstateId,
AllHomeFeatures = new LazyList<HomeFeatures>(AllHomeFeat),
AllCommunityFeatures = new LazyList<CommunityFeatures>(AllCommFeat)
};
}
public IQueryable<Models.CommunityFeatures> GetCommunityFeatures()
{
return from f in entity.CommunityFeatures
select new CommunityFeatures
{
Name = f.CommunityFeature1,
CommunityFeatureId = f.CommunityFeatureId
};
}
public IQueryable<Models.HomeFeatures> GetHomeFeatures()
{
return from f in entity.HomeFeatures
select new HomeFeatures()
{
Name = f.HomeFeature1,
HomeFeatureId = f.HomeFeatureId
};
}
LazyList is a List that extends the power of IQueryable.
Could someone explain why this error occurs?
Reason:
By design, LINQ to Entities requires the whole LINQ query expression to be translated to a server query. Only a few uncorrelated subexpressions (expressions in the query that do not depend on the results from the server) are evaluated on the client before the query is translated. Arbitrary method invocations that do not have a known translation, like GetHomeFeatures() in this case, are not supported.
To be more specific, LINQ to Entities only support Parameterless constructors and Initializers.
Solution:
Therefore, to get over this exception you need to merge your sub query into the main one for GetCommunityFeatures() and GetHomeFeatures() instead of directly invoking methods from within the LINQ query. Also, there is an issue on the lines that you were trying to instantiate a new instance of LazyList using its parameterized constructors, just as you might have been doing in LINQ to SQL. For that the solution would be to switch to client evaluation of LINQ queries (LINQ to Objects). This will require you to invoke the AsEnumerable method for your LINQ to Entities queries prior to calling the LazyList constructor.
Something like this should work:
public IQueryable<Models.Estate> GetEstates()
{
return from e in entity.Estates.AsEnumerable()
let AllCommFeat = from f in entity.CommunityFeatures
select new CommunityFeatures {
Name = f.CommunityFeature1,
CommunityFeatureId = f.CommunityFeatureId
},
let AllHomeFeat = from f in entity.HomeFeatures
select new HomeFeatures() {
Name = f.HomeFeature1,
HomeFeatureId = f.HomeFeatureId
},
select new Models.Estate {
EstateId = e.EstateId,
AllHomeFeatures = new LazyList<HomeFeatures>(AllHomeFeat),
AllCommunityFeatures = new LazyList<CommunityFeatures>(AllCommFeat)
};
}
More Info: Please take a look at LINQ to Entities, what is not supported? for more info.
Also check out LINQ to Entities, Workarounds on what is not supported for a detailed discussion on the possible solutions.
(Both links are the cached versions because the original website is down)

Neo4j-JDBC Driver only returns one row

I'm using the Neo4j JDBC driver 2.0.1.
When I run the following query on by browser, I get the right data back.
MATCH (u:Person) RETURN u.name, u.lastname
I am executing this statement with the NeoJDBC driver (I am connected to the db, otherwise I would not have been able to create nodes before):
public static ResultSet executeCypher(String query)
{
try (Statement stmt = TestUtils.connection.createStatement())
{
return stmt.executeQuery(query);
}
catch (SQLException e)
{
System.out.println(e.getMessage() + "\n\n" + e.getCause().toString() + "\n\n" + e.getErrorCode());
}
}
When I'm iterating over the result set, there are 2 colums as expected. But only one row in the result set. I wrote this according to the minimum viable snippet:
//create some users here
//...
//check the database content
ResultSet rs = TestUtils.executeCypher("MATCH (u:Person) RETURN u.name, u.lastname");
while(rs.next())
{
System.out.println(rs.getString("u.name"));
System.out.println("print anything for test purposes");
}
Output:
Executing query: MATCH (u:Person) RETURN u.name as name, u.lastname
as lastname with params {} Starting the Apache HTTP client
John
print anything for test purposes
Why do I only get one row back although it should return multiple rows? I found some data in the "data" field of the ResultSet while debugging (see also Michael Hunger's answer here) where the "last" property is false. So I guess there is more data. But I don't know how to extract it.
How can I get all the data that is in the ResultSet (using an iterator)?

Filtering list using linq and mvc

Below is the code in question. I receive Object reference not set to an instance of an object. on the where clause inside the Linq query. However, this only happens after it goes through and builds my viewpage.
Meaning: If I step through using debugger, I can watch it pull the correct order I am filtering for, go to the correct ViewPage, fill in the model/table with the correct filtered item, and THEN it comes back to my Controller and shows me the error.
public ActionResult OrderIndex(string searchBy, string search)
{
var orders = repositoryOrder.GetOpenOrderList();
if (Request.QueryString["FilterOrderNumber"] != null)
{
var ordersFiltered = from n in orders
where n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n;
return View(ordersFiltered);
}
return View(orders);
}
its always better to manipulate your strings and other things outside the linq query ,
please refer : http://msdn.microsoft.com/en-us/library/bb738550.aspx
from the readability point of view also its not good ,
public ActionResult OrderIndex(string searchBy, string search)
{
var orders = repositoryOrder.GetOpenOrderList();
var orderNumber = Request.QueryString["FilterOrderNumber"];
if (!string.IsNullOrEmpty(orderNumber))
{
orderNumber = orderNumber.ToUpper();
var ordersFiltered = from n in orders
where n.OrderNumber.ToUpper().Contains(orderNumber)
select n;
return View(ordersFiltered);
}
return View(orders);
}
Your query is not being executed in your Action method because you don't have a ToList (or equivalent) added to your query. When your code returns, your query will be enumerated somewhere in your view and that's the point where the error occurs.
Try adding ToList to your query like this to force query execution in your action method:
var ordersFiltered = (from n in orders
where n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n).ToList();
What's going wrong is that a part of your where clause is null. This could be your query string parameter. Try moving the Request.QueryString part out of your query and into a temporary variable. If that's not the case make sure that your orders have an OrderNumber.
You both were right. Just separately.
This fixed my problem
var ordersFiltered = (from n in orders
where !string.IsNullOrEmpty(n.OrderNumber) && n.OrderNumber.ToUpper().Contains(Request.QueryString["FilterOrderNumber"].ToUpper().ToString())
select n);

Search a collection of objects

I'm trying to search for a collection of potential nodes but unable to do it...
I have a product that has a relationship with many instances. I would like to query the DB and get all the instances that are in a list that i get from the user.
Cypher:
var query = _context
.Cypher
.Start(new
{
instance = startBitsList,
product = productNode.Reference,
})
.Match("(product)-[:HasInstanceRel]->(instance)")
.Return(instance => instance.Node<ProductInstance>());
The problem is startBitsList... I use StringBuilder to generate a query that contains all the instances I'm looking for:
private static string CreateStartBits(IEnumerable<string> instanceNames)
{
var sb = new StringBuilder();
sb.AppendFormat("node:'entity_Name_Index'(");
foreach (var id in productIds)
{
sb.AppendFormat("Name={0} OR ", id);
}
sb.Remove(sb.Length - 4, 4);
sb.Append(")");
var startBitsList = sb.ToString();
return startBitsList;
}
I get exceptions when trying to run this cypher...
Is there a better way to search for multiple items that are stored in the collection I get from the user?
OK, I think there are a couple of issues at play here, first I'm presuming you are using Neo4j 1.9 and not 2.0 - hence using the .Start.
Have you tried taking your query and running it in Neo4j? This should be your first port of call, typically it's easy to add a breakpoint on the .Results call and add a 'watch' for query.Query.DebugText.
However, I don't think you need to use the StartBits the way you are, I think you'd be better off filtering with a .Where as you already have the start point:
private static ICypherFluentQuery CreateWhereClause(ICypherFluentQuery query, ICollection<string> instanceNames)
{
query = query.Where((Instance instance) => instance.Name == instanceNames.First());
query = instanceNames.Skip(1).Aggregate(query, (current, localInstanceName) => current.OrWhere((Instance instance) => instance.Name == localInstanceName));
return query;
}
and your query becomes something like:
var prodReference = new NodeReference<Product>(2);
var query =
Client.Cypher
.ParserVersion(1, 9)
.Start(new {product = prodReference})
.Match("(product)-[:HasInstanceRel]->(instance)");
query = CreateWhereClause(query, new[] {"Inst2", "Inst1"});
var resultsQuery = query.Return(instance => instance.As<Node<Instance>>());
2 things of note
We're not using the indexes - there is no benefit to using them as you have the start point and traversing to the 'instances' is a simple process for Neo4j.
The 'CreateWhereClause' method will probably go wrong if you pass in an empty list :)
The nice thing about not using the indexes is that - because they are legacy - you are set up better for Neo4j 2.0

neo4jclient ill formed cypher request sent to server

Trying to execute the following cypher query (which executes ok from neoclipse)
START a=node(*) MATCH a-[:Knows]->p WHERE (p.Firstname! = "Steve" ) RETURN p
from neo4jclient with the following statement
protected void Populate()
{
var client = new GraphClient(new Uri("http://altdev:7474/db/data"));
client.Connect();
var query = client.Cypher
.Start(new RawCypherStartBit("all", "node(*)"))
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Node<Person>>("Person");
var people = query.Results;
}
the client throws an exception, as follows
The query was: START all=node(*)
MATCH all-[:Knows]->p
WHERE (p.Firstname! = {p0})
RETURN Person
The response status was: 400 Bad Request
The response from Neo4j (which might include useful detail!) was: {
"message" : "Unknown identifier `Person`.",
"exception" : "SyntaxException",
"fullname" : "org.neo4j.cypher.SyntaxException",
"stacktrace" : [ "org.neo4j.cypher.internal.symbols.SymbolTable.evaluateType(SymbolTable.scala:59)", "org.neo4j.cypher.internal.commands.expressions.Identifier.evaluateType(Identifier.scala:47)", "org.neo4j.cypher.internal.commands.expressions.Expression.throwIfSymbolsMissing(Expression.scala:52)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe$$anonfun$throwIfSymbolsMissing$1.apply(ColumnFilterPipe.scala:61)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe$$anonfun$throwIfSymbolsMissing$1.apply(ColumnFilterPipe.scala:61)", "scala.collection.immutable.List.foreach(List.scala:309)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe.throwIfSymbolsMissing(ColumnFilterPipe.scala:61)", "org.neo4j.cypher.internal.pipes.PipeWithSource.<init>(Pipe.scala:63)", "org.neo4j.cypher.internal.pipes.ColumnFilterPipe.<init>(ColumnFilterPipe.scala:30)", "org.neo4j.cypher.internal.executionplan.builders.ColumnFilterBuilder.handleReturnClause(ColumnFilterBuilder.scala:60)", "org.neo4j.cypher.internal.executionplan.builders.ColumnFilterBuilder.apply(ColumnFilterBuilder.scala:38)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.prepareExecutionPlan(ExecutionPlanImpl.scala:54)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.<init>(ExecutionPlanImpl.scala:36)", "org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:80)", "org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:80)", "org.neo4j.cypher.internal.LRUCache.getOrElseUpdate(LRUCache.scala:37)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:80)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:72)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:76)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:79)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:94)", "java.lang.reflect.Method.invoke(Method.java:616)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
}
As you can see, essentially the queries are the same. And the nodes I'm trying to get are of _type "Person"
TIA
Marcelo
In your MATCH clause you use the identity p:
.Match("all-[:Knows]->p") // becomes MATCH all-[:Knows]->p
In your RETURN clause you change to using the identity Person:
.Return<Node<Person>>("Person"); // becomes RETURN person
You need to pick one and be consistent.
Integrating some other clean up too, your full query should be:
var query = client.Cypher
.Start(new { all = All.Nodes })
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Person>("p");
It's down to the way you are creating the Cypher code, specifically what you are returning:
var query = client.Cypher
.Start(new RawCypherStartBit("all", "node(*)"))
.Match("all-[:Knows]->p")
.Where((Person p) => p.Firstname == "Steve")
.Return<Node<Person>>("p"); // <-- THIS LINE SHOULD SAY 'P' NOT 'Person'
The return statement requires the name to be the same as the node you have defined. So you use: all-[:knows]->p where you define p. Now you need to return it.
(Which is what Peter is saying in his answer :))
You are trying to return a Person node that is not assigned to anything in the query.

Resources