Announcement Announcement Module
Collapse
No announcement yet.
Cypher params in index queries possible? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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, 10:57 AM. Reason: typos

  • #2
    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.

    Comment


    • #3
      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, 03:36 AM.

      Comment


      • #4
        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

        Comment


        • #5
          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 Attachment , not working calls are in App.java line 33 onwards.

          As always, any help appreciated
          Attached Files

          Comment


          • #6
            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.

            Comment

            Working...
            X