GithubHelp home page GithubHelp logo

redisgraph / jredisgraph Goto Github PK

View Code? Open in Web Editor NEW
58.0 7.0 19.0 949 KB

Java API for RedisGraph

Home Page: https://redisgraph.io

License: BSD 3-Clause "New" or "Revised" License

Java 100.00%
java-client redisgraph redis cypher

jredisgraph's Introduction

Release CircleCI Dockerhub Codecov Bounty

RedisGraph

A graph database module for Redis

Forum Discord


RedisGraph is now in maintenance mode.

As of July 5th, 2023 RedisGraph is no longer under active development. We do not plan to release new features (2.12 is the last feature-bearing release), but we will continue to release patches until January 31, 2025.

We are grateful to the RedisGraph community for their interest and support.

You can read more about the end of life of RedisGraph here.

There is an actively maintained fork of RedisGraph, in the form of FalkorDB.


RedisGraph is the first queryable Property Graph database to use sparse matrices to represent the adjacency matrix in graphs and linear algebra to query the graph.

Primary features:

  • Adopting the Property Graph Model
    • Nodes (vertices) and Relationships (edges) that may have attributes
    • Nodes can have multiple labels
    • Relationships have a relationship type
  • Graphs represented as sparse adjacency matrices
  • OpenCypher with proprietary extensions as a query language
    • Queries are translated into linear algebra expressions

To see RedisGraph in action, visit Demos. To read the docs, visit redis.io.

Quickstart

  1. Trying RedisGraph
  2. Docker
  3. Build
  4. Start
  5. Use from any client

Give it a try

Once loaded you can interact with RedisGraph using redis-cli.

Here we'll quickly create a small graph representing a subset of motorcycle riders and teams taking part in the MotoGP league, once created we'll start querying our data.

With redis-cli

The format of results through redis-cli is described in the RedisGraph documentation.

$ redis-cli
127.0.0.1:6379> GRAPH.QUERY MotoGP "CREATE (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}), (:Rider {name:'Dani Pedrosa'})-[:rides]->(:Team {name:'Honda'}), (:Rider {name:'Andrea Dovizioso'})-[:rides]->(:Team {name:'Ducati'})"
1) 1) Labels added: 2
   2) Nodes created: 6
   3) Properties set: 6
   4) Relationships created: 3
   5) "Query internal execution time: 0.399000 milliseconds"

Now that our MotoGP graph is created, we can start asking questions, for example: Who's riding for team Yamaha?

127.0.0.1:6379> GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, t.name"
1) 1) "r.name"
   2) "t.name"
2) 1) 1) "Valentino Rossi"
      2) "Yamaha"
3) 1) "Query internal execution time: 0.625399 milliseconds"

How many riders represent team Ducati?

127.0.0.1:6379> GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team {name:'Ducati'}) RETURN count(r)"
1) 1) "count(r)"
2) 1) 1) (integer) 1
3) 1) "Query internal execution time: 0.624435 milliseconds"

Building

Compiling

Requirements:

  • The RedisGraph repository: git clone --recurse-submodules -j8 https://github.com/RedisGraph/RedisGraph.git

  • On Ubuntu Linux, run: apt-get install build-essential cmake m4 automake peg libtool autoconf python3

  • On OS X, verify that homebrew is installed and run: brew install cmake m4 automake peg libtool autoconf.

    • The version of Clang that ships with the OS X toolchain does not support OpenMP, which is a requirement for RedisGraph. One way to resolve this is to run brew install gcc g++ and follow the on-screen instructions to update the symbolic links. Note that this is a system-wide change - setting the environment variables for CC and CXX will work if that is not an option.

To build, run make in the project's directory.

Congratulations! You can find the compiled binary at src/redisgraph.so.

Running tests

First, install required Python packages by running pip install -r requirements.txt from the tests directory.

If you've got redis-server in PATH, just invoke make test.

Otherwise, invoke REDIS_SERVER=<redis-server-location> make test.

For more verbose output, run make test V=1.

Building in a docker

The RedisGraph build system runs within docker. For detailed instructions on building, please see here.

Loading RedisGraph into Redis

RedisGraph is hosted by Redis, so you'll first have to load it as a Module to a Redis server. Redis 6.2 is required for RedisGraph 2.12.

We recommend having Redis load RedisGraph during startup by adding the following to your redis.conf file:

loadmodule /path/to/module/src/redisgraph.so

In the line above, replace /path/to/module/src/redisgraph.so with the actual path to RedisGraph's library. If Redis is running as a service, you must ensure that the redis user (default) has the necessary file/folder permissions to access redisgraph.so.

Alternatively, you can have Redis load RedisGraph using the following command line argument syntax:

~/$ redis-server --loadmodule /path/to/module/src/redisgraph.so

Lastly, you can also use the MODULE LOAD command. Note, however, that MODULE LOAD is a dangerous command and may be blocked/deprecated in the future due to security considerations.

Once you've successfully loaded RedisGraph your Redis log should have lines similar to:

...
30707:M 20 Jun 02:08:12.314 * Module 'graph' loaded from <redacted>/src/redisgraph.so
...

If the server fails to launch with output similar to:

# Module /usr/lib/redis/modules/redisgraph.so failed to load: libgomp.so.1: cannot open shared object file: No such file or directory
# Can't load module from /usr/lib/redis/modules/redisgraph.so: server aborting

The system is missing the run-time dependency OpenMP. This can be installed on Ubuntu with apt-get install libgomp1, on RHEL/CentOS with yum install libgomp, and on OSX with brew install libomp.

Using RedisGraph

You can call RedisGraph's commands from any Redis client.

With redis-cli

$ redis-cli
127.0.0.1:6379> GRAPH.QUERY social "CREATE (:person {name: 'roi', age: 33, gender: 'male', status: 'married'})"

With any other client

You can interact with RedisGraph using your client's ability to send raw Redis commands.

Depending on your client of choice, the exact method for doing that may vary.

Python example

This code snippet shows how to use RedisGraph with raw Redis commands from Python via redis-py:

import redis

r = redis.StrictRedis()
reply = r.execute_command('GRAPH.QUERY', 'social', "CREATE (:person {name:'roi', age:33, gender:'male', status:'married'})")

Client libraries

Some languages have client libraries that provide support for RedisGraph's commands:

Project Language License Author Stars Package Comment
jedis Java MIT Redis Stars Maven
redis-py Python MIT Redis Stars pypi
node-redis Node.JS MIT Redis Stars npm
nredisstack .NET MIT Redis Stars nuget
redisgraph-rb Ruby BSD Redis redisgraph-rb-stars GitHub
redisgraph-go Go BSD Redis redisgraph-go-stars GitHub
rueidis Go Apache 2.0 Rueian rueidis-stars GitHub
ioredisgraph JavaScript ISC Jonah ioredisgraph-stars GitHub
@hydre/rgraph JavaScript MIT Sceat rgraph-stars GitHub
php-redis-graph PHP MIT KJDev php-redis-graph-stars GitHub
redisgraph_php PHP MIT jpbourbon redisgraph_php-stars GitHub
redisgraph-ex Elixir MIT crflynn redisgraph-ex-stars GitHub
redisgraph-rs Rust MIT malte-v redisgraph-rs-stars GitHub
redis_graph Rust BSD tompro redis_graph-stars GitHub
rustis Rust MIT Dahomey Technologies rustis-stars Crate Documentation
NRedisGraph C# BSD tombatron NRedisGraph-stars GitHub
RedisGraph.jl Julia MIT xyxel RedisGraph.jl-stars GitHub

Documentation

Read the docs at redisgraph.io.

Mailing List / Forum

Got questions? Feel free to ask at the RedisGraph forum.

License

Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1). See LICENSE.

jredisgraph's People

Contributors

aviavni avatar bsbodden avatar chayim avatar dependabot[bot] avatar dvirdukhan avatar filipecosta90 avatar gkorland avatar jeffreylovitz avatar lgtm-com[bot] avatar sazzad16 avatar snyk-bot avatar swilly22 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jredisgraph's Issues

Maven Build Warning

➜ mvn clean test
[INFO] Scanning for projects...
[WARNING]
[WARNING] Some problems were encountered while building the effective model for com.redislabs:jredisgraph:jar:2.3.0-SNAPSHOT
[WARNING] 'dependencies.dependency.version' for org.junit.jupiter:junit-jupiter:jar is either LATEST or RELEASE (both of them are being deprecated) @ line 76, column 22
[WARNING] 'dependencies.dependency.version' for org.junit.jupiter:junit-jupiter:jar is either LATEST or RELEASE (both of them are being deprecated) @ line 82, column 22
[WARNING] 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique: org.junit.jupiter:junit-jupiter:jar -> duplicate declaration of version RELEASE @ line 79, column 21
[WARNING]
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING]
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING]

Exactly one relationship type must be specified for CREATE - Example

Hi, I am running your example with 1.0.3 version, I am getting the following error while running the query:

api.query("MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[knows]->(a)")

Error:
Exactly one relationship type must be specified for CREATE

How to use MULTI/EXEC?

Thanks for this project.

Seeing that RedisGraph is a Redis module, I understand that we can use the MULTI/EXEC commands to query the graph as well.
How can this be done using JRedisGraph?

Property data corruption after graph rebuild

RedisGraph version: 2.2.6
JRedisGraph version: 2.1.0

For simplicity, let's say we have two Java services talking to a RedisGraph server: one called GraphBuilder, the other called GraphQuerier. They both use JRedisGraph client. Our GraphBuilder has a timer task that builds a graph once every minute. We are using MERGE command, so it's essentially a timer task that keeps "upserting" the graph.

Everything is on K8s. When the Redis server crashes, its pod will be restarted, and the graph will be gone, but the GraphBuilder will rebuild the graph in no time. When this happens, queries ran on the GraphQuerier can produce corrupted data. Particularly the property names are messed up.

For instance, if the GraphQuerier has not been restarted after Redis crash, it will print a list of properties with property names all messed up:

properties={name=Service, component=String, instance=String, memory_limits=String, pod=workload | deployment | statefulset | daemonset | replicaset, cpu_limits=String, access_mode=String, _created=1602617008984, _updated=1602617495780}

But if we restart the GraphQuerier, or deploy a new GraphQuerier pod, and query the same node on the same graph, we will get the correct result:

properties={name=Service, app=String, kube_service=String, namespace=String, lookup_workload=workload | deployment | statefulset | daemonset | replicaset, workload=String, workload_type=String, _created=1602617008984, _updated=1602617495780}

Note for some properties, we are storing Java data types like String as the values, so don't be confused there.

The query we run to fetch the data is very simple, like

MATCH (n:EntityType {name:$param0}) WHERE (n._updated >= $param1 AND n._created <= $param2) RETURN n

Is it that JRedisGraph client has some form of cached mapping from property ids to property names? If the graph is rebuilt, the mapping will be out-of-date.

We don't have a way to always restart all our services whenever the Redis restarts. So this kind of data corruption cracks the foundation our software is built on.

Question: How to add indexes?

I have tried to add an index programmatically using jredisgraph (version 1.0.3), but it crashes with an IndexOutOfBoundsException (see below). Is this the right/only way to add indexes from code?

The exception occurs when executing following code. It appears to occur because the return value from the server has only one entry, but 2 are expected.

Code:

    RedisGraphAPI graphApi = new RedisGraphAPI("graphKey");
    graphApi.query("CREATE INDEX on :SELECTION(id)");

Stack trace:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
	at java.util.ArrayList.get(ArrayList.java:429)
	at com.redislabs.redisgraph.impl.ResultSetImpl.<init>(ResultSetImpl.java:23)
	at com.redislabs.redisgraph.RedisGraphAPI.query(RedisGraphAPI.java:58)
        ....

ResultSet parse to Tree Struct

I have some entities in my graph, such as Device which is own of an Organization, Software which is installed on a Device, etc

Screen Shot 2021-01-13 at 3 14 17 PM
Screen Shot 2021-01-13 at 2 56 35 PM

when I query by "MATCH p = (o:Organization) - [*] - (s) return o as primary, s as target, nodes(p) as nodes, relationships(p) as edges' cypher sql,

finally, I want to get a tree struct like this, maybe like graphQL result.

GraphNode: {
	id: "org1",
	label: "Organization",
	property: {
		name: 'apple',
                 ...
	},
	children: [
	        GraphNode2,
		{
                    id: "dev01",
                    label: "Device",
                    property: {
                       name: 'dev01',
                       .....
                   }
                   children: [
                        GraphNode4
                   ]
                }
              ....
	]
}

does anyone have same work? or some suggestions? thx

Enable TCK integration with Scala hook

As described in the openCypher documentation, by exposing a conformant API we can integrate with and run the TCK more directly than the Cucumber->Behave approach used currently.

This would have a few advantages, including accessing the TCK as a Maven dependency, simpler reporting, and fewer custom steps.

This is in the nice-to-have category - not pressing, but worth keeping in mind!

Query does not support backtics

I have some special character (colon) in my query and to escape that cypher language suggests to use backtics as mentioned here to use this character. Howerver, using redisgraph I get following error:

127.0.0.1:6379>  GRAPH.QUERY provenance "MATCH (n:`C:\USERS\TARGET0\JAVA.EXE`)-[:write]->(d) RETURN n,d"
(error) Syntax error at offset 13 near ':'

How to close the redisgraph connections

Hi Team,

I'm looking for a template how to close the redisgraph connection obtained from the JedisPool to handle the resource leakage. How can we achieve this on JRedisGraph dependency?

Below is an excerpt of the code that gets the RedisGraph API which is used by other classes to execute queries against the database.

@Configuration
public class Config {
   @Bean
   public RedisGraph redisGraph() {
      JedisPool pool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
      return new RedisGraph(pool);
   }
}

We are then calling the created bean directly to send query to database, this is resulting on resource leakage

@Service
public class Util {
   @Autowired
   private RedisGraph redisGraph; 
 public ResultSet redisGraphApi(String query) {
      ResultSet resultSet = redisGraph.query(graphId, query);
      return resultSet;
   }
}

Create a new vertex and return its id

When creating a new vertex is it possible to get the id of the newly created vertex. I've tried the following but it throws a JedisDataException.

ResultSet rs = api.query( "CREATE (p:person{name:'rois', age:32}) RETURN ID(p))");

Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: Syntax error at offset 46 near 'RETURN'
at redis.clients.jedis.Protocol.processError(Protocol.java:131)
at redis.clients.jedis.Protocol.process(Protocol.java:165)
at redis.clients.jedis.Protocol.read(Protocol.java:219)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:309)
at redis.clients.jedis.Connection.getRawObjectMultiBulkReply(Connection.java:276)
at redis.clients.jedis.Connection.getObjectMultiBulkReply(Connection.java:280)
at com.redislabs.redisgraph.RedisGraphAPI.query(RedisGraphAPI.java:58)

What's the correct way to do this?

Get GraphEntity properties map

Hi,

Thanks for this project!

When running a query and getting a node/edge in the response, there is no way of iterating over all the properties. This might be useful when I'm not interested in a set of particular properties but rather in all properties.
I think that exposing the properties map (or at least the keys) should solve this.

Add multi label support

Latest version of RedisGraph support node with multiple labels this needs to be reflected in the client
when creating a node and when parsing a result that contains node

Redis Graph 1.0.6 not working

Hey chaps

I'm trying to run the example before version 2.0.0, and it just doesn't work.

Steps to reproduce:

  1. Spin up redis graph container

docker run -d --name redis-p 6379:6379 redislabs/redisgraph

  1. Import JRedis 1.0.6

<dependencies> <dependency> <groupId>com.redislabs</groupId> <artifactId>jredisgraph</artifactId> <version>1.0.6</version> </dependency> </dependencies>

  1. Copy example in repository readme
public class RedisGraphExample {
	public static void main(String[] args) {

		RedisGraphAPI api = new RedisGraphAPI("social");

		api.query("CREATE (:person{name:'roi',age:32})");
		api.query("CREATE (:person{name:%s,age:%d})", "amit", 30);

		api.query("MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)");

		ResultSet resultSet = api.query("MATCH (a:person)-[:knows]->(b:person) RETURN a, b");

		while(resultSet.hasNext()){
			Record record = resultSet.next();
			System.out.println(record.getString("a.name"));
		}
	}
}

Issues:

  1. This line does not work as t here is no query method with more than one argument api.query("CREATE (:person{name:%s,age:%d})", "amit", 30);

  2. By commenting out the above line, we can now attempt to run the code which returns the following error:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.get(ArrayList.java:433) at com.redislabs.redisgraph.impl.ResultSetImpl.<init>(ResultSetImpl.java:24) at com.redislabs.redisgraph.RedisGraphAPI.query(RedisGraphAPI.java:58) at Main.main(Main.java:11)

Support for point() type and function

It appears that the java graph library ( com.redislabs.redisgraph.impl.api.RedisGraph ) cannot handle point() types.

Query: match (s:Shopper {id: 3}) return s graph: recommendations
Records returned from query: match (s:Shopper {id: 3}) return s
[Record] Key: s Value: Node{labels=[Shopper], id=4002, propertyMap={country=Property{name='country', value=Canada}, name=Property{name='name', value=David Rugrat}, id=Property{name='id', value=3}}}
Query: match (s:Shopper {id: 1}) return s graph: recommendations

Exception in thread "main" com.redislabs.redisgraph.exceptions.JRedisGraphCompileTimeException: redis.clients.jedis.exceptions.JedisDataException: Unrecognized response type
	at com.redislabs.redisgraph.impl.api.ContextedRedisGraph.sendQuery(ContextedRedisGraph.java:59)
	at com.redislabs.redisgraph.impl.api.RedisGraph.sendQuery(RedisGraph.java:68)
	at com.redislabs.redisgraph.impl.api.AbstractRedisGraph.query(AbstractRedisGraph.java:37)

redis-cli handles the point type:

127.0.0.1:10005> GRAPH.QUERY "recommendations" "match (s:Shopper {id: 3}) return s"
1) 1) "s"
2) 1) 1) 1) 1) "id"
            2) (integer) 4002
         2) 1) "labels"
            2) 1) "Shopper"
         3) 1) "properties"
            2) 1) 1) "id"
                  2) (integer) 3
               2) 1) "name"
                  2) "David Rugrat"
               3) 1) "country"
                  2) "Canada"
3) 1) "Cached execution: 1"
   2) "Query internal execution time: 0.202800 milliseconds"
127.0.0.1:10005> GRAPH.QUERY "recommendations" "match (s:Shopper {id: 1}) return s"
1) 1) "s"
2) 1) 1) 1) 1) "id"
            2) (integer) 4000
         2) 1) "labels"
            2) 1) "Shopper"
         3) 1) "properties"
            2) 1) 1) "id"
                  2) (integer) 1
               2) 1) "name"
                  2) "David Hoppytail"
               3) 1) "country"
                  2) "Canada"
               4) 1) "geo_point"
                  2) "point({latitude:51.964802, longitude:-88.150902})"
3) 1) "Cached execution: 1"
   2) "Query internal execution time: 0.185100 milliseconds"

Does MULTI/EXEC support CREATE queries

It seems like MULTI/EXEC doesn't support CREATE queries, is this normal, or am I doing something wrong?

Code sample (Kotlin):

redisGraph.context.use { context ->
  context.multi().use { tx ->
    tx
    .query(
       "testGraph",
       """
           CREATE (:VARIABLE {id:${"$"}id})
       """.trimIndent(),
       mapOf("id" to "test")
    )
    tx.exec()
  }
}

Rename packages with `_` in their names

Remove underscores in the packages/folders below (suggestions added)
src/main/java/com/redislabs/redisgraph/graph_entities ==> src/main/java/com/redislabs/redisgraph/entities
src/main/java/com/redislabs/redisgraph/impl/graph_cache ==> src/main/java/com/redislabs/redisgraph/impl/cache

Extend API to have query builders

Have a builder pattern API which allows executing query without writing directly writing Cypher.
Support CRUD API to nodes and relationships via those builder objects.

MERGE Relationship

MATCH(a:person{name:'roi'}), (b:person{name:'amit'}) MERGE (a)-[:knows]->(b) throws
(error) Syntax error at offset 59 near 'MERGE

Q. Does CREATE, in this instance using JRedisGraph, behavior as specified in Cypher, it will re-create the relationship each time?

Client not working with latest RedisGraph!!!!!!

JRedisGraph client does not work since RedisGraph results sets were reworked (as per RedisGraph/RedisGraph@777da81).

The problem is that the return values now contain (nil) for null values and a similar format e.g. (integer) 1500 for primitive types.

Example stack trace, coming from a result set with integers in:

	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at com.redislabs.redisgraph.impl.ResultSetImpl.<init>(ResultSetImpl.java:43)
	at com.redislabs.redisgraph.RedisGraphAPI.query(RedisGraphAPI.java:58)
	at williamhill.retail.dds.graphviewer.redis.RedisGraphManualTest.testPrematchEventsRequestAndResponse(RedisGraphManualTest.java:111)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

Unreliable Statistics#propertiesSet

We are running a bunch of updating statements like this:

Statistics statistics = driver.query(graphId, query, params).getStatistics();
return statistics.propertiesSet();

The query variable is

MATCH (n:Service {site:$match_site, name:$match_name, namespace:$match_namespace, env:$match_env}) SET n.service_type=$service_type

and an example of the params variable is

{service_type=aurora-mysql, match_namespace=monitoring, match_site=dev, match_env=dev, match_name=aurora-mysql}

I assume if there is a match, the above code should return 1, and if there is no match, it should return 0.

Upon testing, I realize the return value is not reliable at all. Most of the time it returns 0 even though there is a match, so I wonder whether it only returns 1 if the update to service_type property actually changes the value. But then I noticed that in the cases it returns 1, there is a match but there is no change to the service_type property. In summary, neither 1 nor 0 means what I thought it is.

Can someone help explain?

Path Query gives ArrayOutOfBoundsException with redisgraph:edge docker version

When running a query like:

"MATCH p=(n:Container)<-[*0..10]-(m) WHERE n.name='c0' AND (n._updated >= 100000 AND n._created <= 100000) RETURN p"

It looks like we are intermittently getting this exception only with the newest redisgraph edge version:

Index -2 out of bounds for length 1
java.lang.ArrayIndexOutOfBoundsException: Index -2 out of bounds for length 1
	at java.base/java.util.concurrent.CopyOnWriteArrayList.elementAt(CopyOnWriteArrayList.java:385)
	at java.base/java.util.concurrent.CopyOnWriteArrayList.get(CopyOnWriteArrayList.java:398)
	at com.redislabs.redisgraph.impl.graph_cache.GraphCacheList.getCachedData(GraphCacheList.java:45)
	at com.redislabs.redisgraph.impl.graph_cache.GraphCache.getLabel(GraphCache.java:30)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializeNode(ResultSetImpl.java:148)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializeScalar(ResultSetImpl.java:240)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializeArray(ResultSetImpl.java:262)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializeScalar(ResultSetImpl.java:238)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializePath(ResultSetImpl.java:253)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.deserializeScalar(ResultSetImpl.java:244)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.parseResult(ResultSetImpl.java:90)
	at com.redislabs.redisgraph.impl.resultset.ResultSetImpl.<init>(ResultSetImpl.java:55)
	at com.redislabs.redisgraph.impl.api.ContextedRedisGraph.sendQuery(ContextedRedisGraph.java:53)
	at com.redislabs.redisgraph.impl.api.RedisGraph.sendQuery(RedisGraph.java:68)
	at com.redislabs.redisgraph.impl.api.AbstractRedisGraph.query(AbstractRedisGraph.java:39)
	at ai.asserts.model.redis.RedisKGraph.getEntityWithUplinks(RedisKGraph.java:178)
	at ai.asserts.model.graph.KGraphTest$UplinkMatchTest.redis_test(KGraphTest.java:93)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:413)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:834)

We suspect the newer version triggered the issue in the client, but can't be 100%. Currently trying to deconstruct the series of queries that surfaced this as it seems to only occur with a specific ordering of queries. Hoping that maybe there is something known on your end.

All other previous versions didn't show this issue. Thanks for any help.

@DvirDukhan

two suggestion to RedisGraphAPITest

  1. writing error

81 line:

ResultSet resultSet = api.query("social", "MATCH (a:Person), (b:Person) WHERE (a.name = 'roi' AND b.name='amit')  CREATE (a)-[:Knows]->(a)"); // guess you want to say a-knows-b
  1. log4j missing
    run test will complain no slf4 default implementation.
    I add a dependency to fix it:
    <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.6.6</version> </dependency>

Exception in quoteString for empty string

This is the culprit:

If an empty string is passed as a parameter, the code tries to access the 0th character, which fails.

Workaround: use "\"\"" as parameter (i.e. a string that contains only two quotes).

(NB: I didn't send a PR because I'm not completely sure about the semantics of the the quoteString method. Should it escape characters or not?)

Timestamp values are deserialized into Integer

Steps to reproduce:

  • run a Cypher query to create a node, with a timestamp property created like
    MERGE (n:Foo) ON CREATE SET n.created=timestamp()
  • If you check out the graph in RedisInsight, you can see the created being a Unix timestamp
  • If you use JRedisGraph client to retrieve the node, you will notice that the created property is deserialized into an integer. Because a 64-bit Unix timestamp cannot fit into a 32-bit Java integer, it overflows and yields some strange integer values.

RedisGraph says the numeric types could be either 64-bit doubles and 64-bit signed integer. In Java, 64-bit signed Integer should be Long, instead of Integer. The ResultSetScalarTypes should really contain VALUE_LONG instead of VALUE_INTEGER. Likewise, In ResultSetImpl#deserializeScalar, we shouldn't cast the Long to an Integer.

How do i connect to a secure redis instance?

No option provided in the RedisGraphAPI constructor to pass auth.

Executing a query fails with following error on an redis instance with auth enabled:
Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required.
at redis.clients.jedis.Protocol.processError(Protocol.java:131)
at redis.clients.jedis.Protocol.process(Protocol.java:165)
at redis.clients.jedis.Protocol.read(Protocol.java:219)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:309)
at redis.clients.jedis.Connection.getRawObjectMultiBulkReply(Connection.java:276)
at redis.clients.jedis.Connection.getObjectMultiBulkReply(Connection.java:280)
at com.redislabs.redisgraph.RedisGraphAPI.query(RedisGraphAPI.java:47)

redis.clients.jedis.exceptions.JedisConnectionException is reported when executing the Cypher queries.

Hello, I discovered that when I executed the queries in the attached java file, an exception occurred:
redisgraph.zip

Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.
at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
at redis.clients.jedis.util.RedisInputStream.readByte(RedisInputStream.java:43)
at redis.clients.jedis.Protocol.process(Protocol.java:158)
at redis.clients.jedis.Protocol.read(Protocol.java:223)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:352)
at redis.clients.jedis.Connection.getOne(Connection.java:330)
at redis.clients.jedis.Jedis.sendCommand(Jedis.java:4559)
at com.redislabs.redisgraph.impl.api.ContextedRedisGraph.sendQuery(ContextedRedisGraph.java:52)
at com.redislabs.redisgraph.impl.api.RedisGraph.sendQuery(RedisGraph.java:68)
at com.redislabs.redisgraph.impl.api.AbstractRedisGraph.query(AbstractRedisGraph.java:63)
at RedisGraphExample.main(RedisGraphExample.java:32)

But if I comment out some of the queries, no error will be reported. And if these queries do not contain WHERE clauses, no error will be reported. I wonder if it is a bug. Thanks a lot!

RedisGraph Version: 2.4.11 Docker
Operating System: Windows 11
API: Cypher/Java API
JRedisGraph Version: 2.5.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.