Results 1 to 6 of 6

Thread: Cypher params in index queries possible?

  1. #1
    Join Date
    May 2009
    Posts
    18

    Default Cypher params in index queries possible?

    Hi Cypher experts ;-)

    In neo4j 1.5 docs, chapter Cypher Parameters is completely gone, so I'm a bit lost on how to do this really simple query:

    Find all Nodes of type X (using the basic index over X, SDN creates) which have property Y set to the value of param A and property Z set to the value of param B

    I started with this the example (Node by index query):
    Code:
    start n=(nodes,"name:A") return n
    from here (13.2.4) ending up with this:

    Code:
    @Query(value = "start Orig = node:X(\"Y:{A} AND Z:{B}\") return Orig", type = QueryType.Cypher)
    which led to the following cryptic error:

    Cannot parse 'Y:{A} AND Z:{B}': Encountered " "}" "} "" at line 1, column 4.

    I also tried 13.2.3. Node by index lookup, same query just without the quotes. That led to

    org.neo4j.cypher.SyntaxException: `=' expected but `:' found

    Any suggestion appreciated.

    Björn
    Last edited by Xnyle; Nov 15th, 2011 at 09:57 AM. Reason: typos

  2. #2
    Join Date
    Jan 2011
    Location
    Dresden, Germany
    Posts
    525

    Default

    Björn,

    You can find the Neo4j 1.5 docs for cypher parameters here.

    the whole lucene query string is one parameter, so what you would use is:
    @Query(value = "start Orig = node:X({p}) return Orig")

    You didn't mention if that was a query on a field or on a repository method.

    For the field you have to supply the additional parameters in the annotation, for a repository method they would be the parameters of the method (either indexed then use {0} etc or annotated with @Param("p") then use {p}).

    You might also want to look into the new cypher-dsl which allows some nice conjunction with QueryDSL to formulate concise queries. See Rickard Öberg's blog post for an intro and please follow the links to the DSL-documentation.

  3. #3
    Join Date
    May 2009
    Posts
    18

    Default

    You didn't mention if that was a query on a field or on a repository method.
    Sorry, on a repository method. It's clear to me how that works.

    the whole lucene query string is one parameter
    Not the answer i was hoping for. What about "LQL"-injection.

    Did I miss something? Graph traversal and everything, very cool, but:

    Don't you have to find start nodes first in nearly every use case a human is involved having some properties in mind and not node ids? Most of the time it's not just one property but a combination of two or more.

    The where part seems to do the trick but in every example I found it is combined with start node ids which I don't understand as in nearly every use case I can imagine I would search for exactly these start nodes.

    Again, did I miss something?
    Last edited by Xnyle; Nov 16th, 2011 at 02:36 AM.

  4. #4
    Join Date
    Jan 2011
    Location
    Dresden, Germany
    Posts
    525

    Default

    Cypher's parameter support only covers the lucene query string as a single parameter.
    It would be sensible to have better support there, correct.

    For now you have some options:
    * construct your parameters using the properties and you knowledge of the LQL
    * use the cypher-dsl lucene query expression support
    * get the nodes you want to query on using a regular lucene lookup (e.g. template.lookup) and pass the Iterable<Node> as parameter to the query (it is not just node-id's but also collections of nodes that can be passed in)

    * there is preliminary support for this in derived queries findByTitleLike(String title) but that doesn't handle combinations so far
    * we could add a "string replacement" part for parameters inside the lucene query part but that would only be a bad hack

    Michael

  5. #5
    Join Date
    May 2009
    Posts
    18

    Default

    Hi Michael,

    I don't want to open Pandora's, excuse me, Cypher-DSL's box until I get my test case working.


    I've decided to use one property which hopefully filters the most as index lookup and the remaining as where parts like this:

    Code:
    @Query(value = "start Orig = node:World(name = {name}) WHERE Orig.someOtherProperty = {someOtherProperty} return Orig", type = QueryType.Cypher)
    	Iterable<World> getAllNamed(@Param("name") String name, @Param("someOtherProperty") String someOtherProperty);
    That is working for me and I'm good with the solution atm.

    What is not working is this:

    Code:
    @Query(value = "start Orig = node:World(longNumber = {num}) return Orig", type = QueryType.Cypher)
    	Iterable<World> getAllByLongNumber(@Param("num") Long number);
    
    	@Query(value = "start Orig = node:moonIndex(moons = {num}) return Orig", type = QueryType.Cypher)
    	Iterable<World> getAllByMoonNumber(@Param("num")int moons);
    both return null, the definition in World is

    Code:
    @Indexed
    	private Long longNumber;
    	
    	@Indexed
    	private String name;
    	
    	@Indexed
    	private String someOtherProperty;
    
    	@Indexed(indexName = "moonIndex")
    	private int moons;
    It seems, numbers do not work? Neither with the explicitly defined index "moonIndex" nor with the default index used on "someOtherProperty". Is this a bug or did I make a mistake?

    Test case is n4jpatest6.zip, not working calls are in App.java line 33 onwards.

    As always, any help appreciated

  6. #6
    Join Date
    Jan 2011
    Location
    Dresden, Germany
    Posts
    525

    Default

    Björn, I added some tests to SDN to check the behaviour and it seems some cypher issues with handing query-strings to lucene:

    For now, would it be ok for you to pass in lucene query objects? String queries should also work but they don't

    Something like this works in my case:

    Code:
            final String queryString = "start person=node:Person({age}) return person.name";
            final NumericRangeQuery<Integer> rangeQuery = NumericRangeQuery.newIntRange("age", michael.getAge(), michael.getAge(), true, true);
            final Map<String, Object> result = queryEngine.query(queryString, map("age", rangeQuery)).singleOrNull();
            assertNotNull("result is null",result);
            assertEquals("found correct person", michael.getName(), result.get("person.name"));
    Support for numeric parameter querying will be fixed in Cypher with one of the next Neo4j Milestones.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •