Coder Social home page Coder Social logo

redisgraph / redisgraph-go Goto Github PK

View Code? Open in Web Editor NEW
133.0 7.0 38.0 116 KB

A Golang client for redisgraph

Home Page: https://redisgraph.io

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

Go 98.88% Makefile 1.12%
redisgraph golang-client redis graphdatabase cypher

redisgraph-go's Introduction

license CircleCI GitHub issues Codecov Go Report Card GoDoc

redisgraph-go

Forum Discord

redisgraph-go is a Golang client for the RedisGraph module. It relies on redigo for Redis connection management and provides support for RedisGraph's QUERY, EXPLAIN, and DELETE commands.

Installation

Simply do:

$ go get github.com/redislabs/redisgraph-go

Usage

The complete redisgraph-go API is documented on GoDoc.

package main

import (
	"fmt"
	"os"

	"github.com/gomodule/redigo/redis"
	rg "github.com/redislabs/redisgraph-go"
)

func main() {
	conn, _ := redis.Dial("tcp", "127.0.0.1:6379")
	defer conn.Close()

	graph := rg.GraphNew("social", conn)

	graph.Delete()

	john := rg.Node{
		Label: "person",
		Properties: map[string]interface{}{
			"name":   "John Doe",
			"age":    33,
			"gender": "male",
			"status": "single",
		},
	}
	graph.AddNode(&john)

	japan := rg.Node{
		Label: "country",
		Properties: map[string]interface{}{
			"name": "Japan",
		},
	}
	graph.AddNode(&japan)

	edge := rg.Edge{
		Source:      &john,
		Relation:    "visited",
		Destination: &japan,
	}
	graph.AddEdge(&edge)

	graph.Commit()

	query := `MATCH (p:person)-[v:visited]->(c:country)
           RETURN p.name, p.age, c.name`

	// result is a QueryResult struct containing the query's generated records and statistics.
	result, _ := graph.Query(query)

	// Pretty-print the full result set as a table.
	result.PrettyPrint()

	// Iterate over each individual Record in the result.
	fmt.Println("Visited countries by person:")
	for result.Next() { // Next returns true until the iterator is depleted.
		// Get the current Record.
		r := result.Record()

		// Entries in the Record can be accessed by index or key.
		pName := r.GetByIndex(0)
		fmt.Printf("\nName: %s\n", pName)
		pAge, _ := r.Get("p.age")
		fmt.Printf("\nAge: %d\n", pAge)
	}

	// Path matching example.
	query = "MATCH p = (:person)-[:visited]->(:country) RETURN p"
	result, err := graph.Query(query)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("Pathes of persons visiting countries:")
	for result.Next() {
		r := result.Record()
		p, ok := r.GetByIndex(0).(rg.Path)
		fmt.Printf("%s %v\n", p, ok)
	}
}

Running the above produces the output:

+----------+-------+--------+
|  p.name  | p.age | c.name |
+----------+-------+--------+
| John Doe |    33 | Japan  |
+----------+-------+--------+

Query internal execution time 1.623063

Name: John Doe

Age: 33

Running queries with timeouts

Queries can be run with a millisecond-level timeout as described in the module documentation. To take advantage of this feature, the QueryOptions struct should be used:

options := NewQueryOptions().SetTimeout(10) // 10-millisecond timeout
res, err := graph.QueryWithOptions("MATCH (src {name: 'John Doe'})-[*]->(dest) RETURN dest", options)

ParameterizedQueryWithOptions and ROQueryWithOptions endpoints are also exposed by the client.

Running tests

A simple test suite is provided, and can be run with:

$ go test

The tests expect a Redis server with the RedisGraph module loaded to be available at localhost:6379

License

redisgraph-go is distributed under the BSD3 license - see LICENSE

redisgraph-go's People

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  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

redisgraph-go's Issues

Create new tag and update `go.mod`

Hello, FalkorDB/RedisGraph team!

Would it be possible to update this package s.t. the latest tag includes the multi-label PR and update the go.mod file accordingly to make the new version available as a simple import?
Currently, users must specify the latest commit hash to use the multi-label functionality in their Go projects.

Rely on Go Modules to ensure package dependencies and replicable builds

why we need it?

Go Modules is the official Go dependency management tool, and it’s directly implemented into the go toolchain.
We need this in order to:

  • Automatically detect import statements and then update dependencies graph, lock, download, and install appropriate versions of packages.

    Quoting golang official docs
    :

In Go 1.14, module support is considered ready for production use, and all users are encouraged to migrate to modules from other dependency management systems.

Also quoting the golang official blog, the reason why this does not break compatibility with previous go versions:

(Inside $GOPATH/src, for compatibility, the go command still runs in the old GOPATH mode, even if a go.mod is found. See the go command documentation for details.) Starting in Go 1.13, module mode will be the default for all development.

minimum specified version

we will need to ensure we have a go.mod on all go clients ( and test at least with the minimum 1.12 go version to say we support >=1.12 ). Ideally it should be 1.11 but redigo outputs an error:

$ gvm use go1.11
Now using version go1.11
filipe@filipe-ThinkPad-T490:~/go/src/github.com/RedisBloom/redisbloom-go$ GOCMD="GO111MODULE=on go" make
GO111MODULE=on go get -t -v ./...
go get: -t flag is a no-op when using modules
github.com/gomodule/redigo/redis
go build github.com/gomodule/redigo/redis: module requires Go 1.14
make: *** [Makefile:24: get] Error 1

Can't use redis-graph example

I am trying to use redis-graph with the README's example but all I get is the next error:

$ go run main.go 
# command-line-arguments
./main.go:5:2: imported and not used: "github.com/redislabs/redisgraph-go" as redisgraph
./main.go:12:11: undefined: Graph
./main.go:14:13: undefined: Node
./main.go:25:30: undefined: Node
./main.go:33:39: undefined: Edge

Graph Commital not Visualizing within RedisInsight

Hi,

I might not have properly understood the paradigm of the library, but I was looking to generalize the creation of nodes and edges through the use of builder/factory methods. So far as I can tell, there are no errors in my Go implementation, and the data does RETURN properly when I examine it through RedisInsight. However, the visualizer is broken. I can only view my data as raw text; which really defeats the purpose of loading everything into a graph in the first place.

My implementation isn't too long, but pulling off the various hat-tricks with generics and getting the types to play together did take the majority of the day.

Relevant types:

type Option[T comparable] struct {
	value T
	label string
	edges []string
}

type OptionsList[T comparable] struct {
	TypeLabel string
	Options   []Option[T]
}

type NodeList[T comparable] map[string]OptionNodeList[T]

type OptionNodeList[T comparable] map[T]*rg.Node

Node factories:

func BuildNodes[T comparable](optionList OptionsList[T], graph rg.Graph) NodeList[T] {
	nodesList := make(NodeList[T])
	emptyOptionList := make(OptionNodeList[T])

	for _, option := range optionList.Options {
		node := BuildNode[T](optionList.TypeLabel, option, graph)

		if nodesList[optionList.TypeLabel] == nil {
			nodesList[optionList.TypeLabel] = emptyOptionList
		}

		nodesList[optionList.TypeLabel][option.value] = node //STORE LIST OF NODES BY TYPE & VALUE
	}

	return nodesList
}

func BuildNode[T comparable](label string, option Option[T], graph rg.Graph) *rg.Node {
	//buildPropertyMap Here
	properties := map[string]interface{}{
		option.label: option.value,
	}
	//create node
	node := rg.Node{
		Label:      label,
		Properties: properties,
	}

	graph.AddNode(&node)

	return &node
}

Edge factories:

func MapEdges[T comparable](relationLabel string, optionList OptionsList[T], sourceList NodeList[T], destinationLabel string, destinationList NodeList[string], graph *rg.Graph) {
	for _, option := range optionList.Options {
		sourceNode := sourceList[optionList.TypeLabel][option.value]
		for _, edgeValue := range option.edges {
			destinationNode := destinationList[destinationLabel][edgeValue]
			CreateRelationship(sourceNode, relationLabel, destinationNode, graph)
		}
	}
}

func CreateRelationship(source *rg.Node, relationLabel string, destination *rg.Node, graph *rg.Graph) {
	// fmt.Println(source, relationLabel, destination)
	edge := rg.Edge{
		Source:      source,
		Relation:    relationLabel,
		Destination: destination,
	}
	graph.AddEdge(&edge)
}

The caller function:

func CreateGraph() {
	conn, _ := redis.Dial("tcp", REDIS_HOST)
	defer conn.Close()
	graph := rg.GraphNew("Configurations", conn)
	graph.Delete() //CLEAR OLD DATA FOR CLEAN SET UP

	variantOptions := OptionsList[string]{
		TypeLabel: "Variants",
		Options: []Option[string]{
			{label: "name", value: "A", edges: []string{}},
			{label: "name", value: "B", edges: []string{}},
			{label: "name", value: "C", edges: []string{}},
			{label: "name", value: "D", edges: []string{}},
		},
	}
	navOptions := OptionsList[int]{
		TypeLabel: "NavButtons",
		Options: []Option[int]{
			{label: "name", value: 5, edges: []string{"A", "C"}},
			{label: "name", value: 4, edges: []string{"B", "D"}},
		},
	}

	variantOptionNodes := BuildNodes[string](variantOptions, &graph)
	navOptionNodes := BuildNodes[int](navOptions, &graph)

	MapEdges[int]("COMPOSEDOF", navOptions, navOptionNodes, variantOptions.TypeLabel, variantOptionNodes, &graph)

	graph.Commit()
	query := `MATCH (n) RETURN n`
	queryRel := `MATCH (a)-[r]-(b) RETURN r`
	resultOne, _ := graph.Query(query)
	resultTwo, _ := graph.Query(queryRel)

	resultOne.PrettyPrint()
	resultTwo.PrettyPrint()

}

Result One:

+---------------+
|       n       |
+---------------+
| {name:"A"}    |
| {name:"B"}    |
| {name:"C"}    |
| {name:"D"}    |
| {name:5}      |
| {name:4}      |
+---------------+

Cached execution 0.000000
Query internal execution time 0.225416

Result Two:

+----+
| r  |
+----+
| {} |
| {} |
| {} |
| {} |
| {} |
| {} |
| {} |
| {} |
+----+

Cached execution 0.000000
Query internal execution time 0.409459

Result Two is curious, as RedisInsight returns this data for the same query:

1) 1) "r"
2) 1) 1) 1) 1) "id"
            2) "0"
         2) 1) "type"
            2) "COMPOSEDOF"
         3) 1) "src_node"
            2) "5"
         4) 1) "dest_node"
            2) "1"
         5) 1) "properties"
            2) (empty list or set)
   2) 1) 1) 1) "id"
            2) "2"
         2) 1) "type"
            2) "COMPOSEDOF"
         3) 1) "src_node"
            2) "6"
         4) 1) "dest_node"
            2) "2"
         5) 1) "properties"
            2) (empty list or set)
   3) 1) 1) 1) "id"
            2) "1"
         2) 1) "type"
            2) "COMPOSEDOF"
         3) 1) "src_node"
            2) "5"
         4) 1) "dest_node"
            2) "3"
         5) 1) "properties"
            2) (empty list or set)
   4) 1) 1) 1) "id"
            2) "3"
         2) 1) "type"
            2) "COMPOSEDOF"
         3) 1) "src_node"
            2) "6"
         4) 1) "dest_node"
            2) "4"
         5) 1) "properties"
            2) (empty list or set)
... Etc 

I can shelf this for now and I suppose attempt the same intent of what I'd like to do here by creating factories that parse/output Cypher statements, but that doesn't really seem to be in the spirit of the library.

Load an existing graph

Hello,

I am using GraphNew() to play with Redis Graph, my problem is that the existing nodes&edges are not loaded in the graph structure.
The workaround I have is to read the graph (nodes + edges), delete the graph and add these back inside, then do my work.

As mentioned in the doc, Commit() rebuilds an entire Graph so I can use it only once.
Is there any better solution?

Integer overflow on ARMv6 (32-bit)

I noticed redisgraph-go deserializes integers into int instead of int64. Depending on the system, int may be either 64 or 32 bits long. This can cause overflows for larger values, e.g. Unix timestamps beyond Y2038.

Tested on Raspberry Pi Zero W (ARMv6):

package main

import (
	"fmt"
	"log"

	"github.com/gomodule/redigo/redis"
	rg "github.com/redislabs/redisgraph-go"
)

func main() {
	conn, _ := redis.Dial("tcp", "192.168.1.100:6379")
	defer conn.Close()

	graph := rg.GraphNew("test", conn)
	graph.Delete()

	var t int64 = 2147483648
	q1 := fmt.Sprintf(`CREATE (:Person{name: 'John', time_created: %d})`, t)

	if _, err := graph.Query(q1); err != nil {
		log.Fatal(err)
	}

	q2 := `MATCH (p:Person) RETURN p.time_created`

	result, err := graph.Query(q2)
	if err != nil {
		log.Fatal(err)
	}

	result.PrettyPrint()
}

Expected output:

+----------------+
| p.time_created |
+----------------+
|     2147483648 |
+----------------+

Actual output:

+----------------+
| p.time_created |
+----------------+
|              0 |
+----------------+

Calling reflect.TypeOf on the record value returns int.

Note that the node had to be added using a string query, since the other method doesn't accept int64 properties, e.g.:

john := rg.Node{
	Label: "Person",
	Properties: map[string]interface{}{
		"name":         "John",
		"time_created": time.Now().Unix(),
	},
}

graph.AddNode(&john)
graph.Commit()

causes a panic:

panic: Unrecognized type to convert to string

goroutine 1 [running]:
github.com/redislabs/redisgraph-go.ToString(0x60b4a0, 0xc0000b24a0, 0xc000107b40, 0x2)
	/home/tomek/.local/go/pkg/mod/github.com/redislabs/[email protected]+incompatible/utils.go:40 +0x317
github.com/redislabs/redisgraph-go.Node.Encode(0x0, 0x64bfa4, 0x6, 0xc0000b24d0, 0xa, 0xc00009aae0, 0xc0000fe000, 0x10, 0x203000)
	/home/tomek/.local/go/pkg/mod/github.com/redislabs/[email protected]+incompatible/node.go:70 +0x23d
github.com/redislabs/redisgraph-go.(*Graph).Commit(0xc0000fe000, 0xc00009aab0, 0xc0000b24d0, 0xa)
	/home/tomek/.local/go/pkg/mod/github.com/redislabs/[email protected]+incompatible/graph.go:91 +0x19e
main.main()
	/tmp/rgtest/main.go:30 +0x5a5
exit status 2

[Bug] QueryResult parsing fails on node labels retrieval on read only replicas

I noticed an issue with the QueryResult -> parseRecords logic when running a query against a redis read-only replica. Specific issue around Labels retrieval that it called internally when parsing a node:

values[idx] = qr.parseNode(c)
labels[i] = qr.graph.getLabel(labelIds[i])

Turned out the Labels() calls procedure internally

redisgraph-go/graph.go

Lines 283 to 284 in 3b0ad09

func (g *Graph) Labels() []string {
qr, _ := g.CallProcedure("db.labels", nil)
which disregards the mode for that procedure and always attempts to run RW g.Query(q) which will obviously fail on read-only replicas.

return g.Query(q)

I'm happy to submit a PR for this issue as I've already solved it in my current project.

redisgraph.Graph literal.New undefined (type redisgraph.Graph has no field or method New)

In Ubuntu 18.04.01 Server Edition I installed redis-server:

marco@pc01:~$ redis-server --version
Redis server v=5.0.5 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=fc2f09ebe3c4d851

and the latest version of RedisGraph:

marco@pc01:~$ 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: 1.547186 milliseconds"
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.970905 milliseconds"
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.518645 milliseconds"
127.0.0.1:6379> 

Running the following redisgraph-go example:

package main
import (
        "github.com/gomodule/redigo/redis"
        rg "github.com/redislabs/redisgraph-go"
)
func main() {
        conn, _ := redis.Dial("tcp", "0.0.0.0:6379")
        defer conn.Close()ì
        graph := rg.Graph{}.New("social", conn)
        john := rg.Node{
                Label: "person",
                Properties: map[string]interface{}{
                        "name":   "John Doe",
                        "age":    33,
                        "gender": "male",
                        "status": "single",
                },
        }
        graph.AddNode(&john)
        japan := rg.Node{
                Label: "country",
                Properties: map[string]interface{}{
                        "name": "Japan",
                },
         }
        graph.AddNode(&japan)
        edge := rg.Edge{
                Source:      &john,
                Relation:    "visited",
                Destination: &japan,
        }
        graph.AddEdge(&edge)
        graph.Commit()
        query := `MATCH (p:person)-[v:visited]->(c:country)
                   RETURN p.name, p.age, v.purpose, c.name`
        rs, _ := graph.Query(query)
        rs.PrettyPrint()
}

I got this error :

marco@pc01:~/RedisGraph/redisgraph-goExample$ go run main.go 
# command-line-arguments
./main.go:12:21: redisgraph.Graph literal.New undefined (type redisgraph.Graph has no field or 
 method New)

Any hints to solve it?
Marco

Bulk Support

I have a few million records in my program that I want to bulk insert using my Go program. It takes me about 2 minutes for 500 records and that would take me 4000 hours for just a million records. I have a couple of MERGE statements in each iteration.

I read about how to improve this and stumbled on to the GRAPH.BULK which may seem useful in this case. But the go library does not seem to support this as the documentation is not covering it. Are there plans to support the BULK API for usecases similar to mine ? Inserting a million records (a few hundred nodes and edges) may not be such a rare scenario. Thanks.

Leak if not reading the output of `Query` function

A sample program:

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"time"

	"github.com/gomodule/redigo/redis"
	rg "github.com/redislabs/redisgraph-go"
	"github.com/sirupsen/logrus"
)

func process() {
	for {
		queryStr := fmt.Sprintf("MATCH (X) RETURN X")

		_ = query("mesh7Graph", queryStr)
		logrus.Println("blah")
	}
}

func query(graphName, query string) error {
	conn := pool.Get()
	defer conn.Close()

	g := rg.GraphNew(graphName, conn)
	if false {
		_, err := g.Query(query)
		if err != nil {
			logrus.Errorf("GraphDB query error: %v", err)
			return err
		}
	} else {
		res, err := g.Query(query)
		if err != nil {
			logrus.Errorf("GraphDB query error: %v", err)
			return err
		}

		for res.Next() {
			_ = res.Record()
		}
	}

	return nil
}

var pool *redis.Pool

const (
	address  = "<REDIS_SERVER_URL>:6379"
	password = "<REDIS_PASSWORD>"
)

func main() {
	pool = &redis.Pool{
		MaxIdle:     100,
		MaxActive:   100,
		IdleTimeout: 240 * time.Second,
		// Dial or DialContext must be set.
		// When both are set, DialContext takes precedence over Dial.
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", address)
			logrus.Tracef("Dialing redis @ %v", address)
			if err != nil {
				logrus.Errorf("Dial failed. Error: %v", err)
				return nil, err
			}
			if _, err := c.Do("AUTH", password); err != nil {
				logrus.Errorf("Authorization failed. Error: %v", err)
				c.Close()
				return nil, err
			}
			return c, nil
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
	}

	go process()

	logrus.Fatal(http.ListenAndServe("localhost:8080", nil))
}

Now run the above program toggling the if block with false and true. The program will just continuously do some redisgraph calls and not parse the response in one case, will parse the response in another case.

When the above program is running, do:

curl -sK -v http://localhost:8080/debug/pprof/heap > heap.out
go tool pprof heap.out
(pprof) lines
(pprof) web

In the case when we ignore the output of Query function, we get a memory leak in the pprof output. When the response is parsed and the record are read, there is no leak reported in the pprof output.

The docs do not mention anything about reading the Query function output. There is no close function on the QueryResult struct either, if I have to call it via defer. There is no other function except Query (like an Exec in the SQL) which I can do to not read results.

I will be happy to provide any other debugging information if you want.

Query failing with error: "redigo: unexpected type for Values, got type []uint8"

This error seems to originate here

records[i], err = redis.Values(result, nil)

We're currently running a version from this commit 0d6a465.

This is pretty far from a reproducible example, but I'd appreciate any suggestions/advice here.


In terms of a more usable example, I've managed to see a similar error while running the sample code from the readme (below). Also running on the same version (0d6a465).

The error here is

redigo: unexpected type for Strings, got type []uint8

The code is essentially verbatim from the README, just added a print for the error:

func main() {
    conn, _ := redis.Dial("tcp", "0.0.0.0:6379")
    defer conn.Close()

    graph := rg.Graph{}.New("social", conn)

    john := rg.Node{
        Label: "person",
        Properties: map[string]interface{}{
            "name":   "John Doe",
            "age":    33,
            "gender": "male",
            "status": "single",
        },
    }
    graph.AddNode(&john)

    japan := rg.Node{
        Label: "country",
        Properties: map[string]interface{}{
            "name": "Japan",
        },
    }
    graph.AddNode(&japan)

    edge := rg.Edge{
        Source:      &john,
        Relation:    "visited",
        Destination: &japan,
    }
    graph.AddEdge(&edge)

    graph.Commit()

    query := `MATCH (p:person)-[v:visited]->(c:country)
		   RETURN p.name, p.age, v.purpose, c.name`
    rs, err := graph.Query(query)
    fmt.Println(err) // ERROR is here

    rs.PrettyPrint()
}

How do you iterate over query results in view

Hi, I'm using the Go Buffalo framework. I'm setting a query result for the view, however the result format does not fit how the view consumes it. Here's my code:

query := MATCH (p:person)-[v:visited]->(c:country) RETURN p.name, p.age, v.purpose, c.name
rs, _ := graph.Query(query)
rs.PrettyPrint()
c.Set("rs", rs)

And the view:

<%= for (r) in rs { %>


<%= r.p.name %>


<%= r.p.age %>


<%= r.p.status %>


<%= r.v.purpose %>


<%= r.c.name %>


<% } %>

What is the correct way to output the result in an html view with the Go lang driver?

What is the purpose of alias on a node?

Glimpsing on the code, I would assume it serves the purpose of a kind of primary/unique key or ID on a node -- which is what I am looking for desperately! But this does not seem to be the case and according to my research, it's also not something that RG natively would support.

Server's run time should return as float64 rather than int

In the object that represents the query result, there is a statistics section (a map), and one of its field is the execution run time. This should be a float rather than int (currently it returns zero for short run time of less than 0.5 ms.)

Adding edges to existing nodes

My development team noticed that there is no way in redisgraph-go to add edges to existing nodes without duplicating the nodes in the process. Please see RedisGraph/redisgraph-py#16 as a reference to this issue within Redis graph in general. The solution described here points to using MATCH (f:%s{%s:'%s'}), (t:%s{%s:'%s'}) CREATE (f)-[:in]->(t) as the way to avoid duplication of nodes. However, we do not find a way within redisgraph-go to make such a transaction? There is basically no 'update' possible to nodes, only create and delete. We can delete old nodes and create new ones with edges, but this is costly and inefficient. Is there any plan to add an UpdateEdge or something similar as AddEdge duplicates nodes?

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

Adding Edges to previously created Nodes

I am updating the graph from a stream of input data. I am updating the Nodes separately from the Edges.

From what I can see, the supported pattern is that I add the nodes and the edges that connect the nodes in the same commit. I did not see a way to create a node then at a later time add an edge to a node that had already been committed without adding the node to the Node map first. If I do that, it appears as though the node would be pushed to redis again.

Am I correct?

No results returned from count query

Example:

 query := fmt.Sprintf(
    "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'})",
  )

  // A service with an open, connected redisgraph
  results, _ := redisgraphsvc.Graph.Query(query)
  fmt.Println(results.Results) // Prints []

  query = fmt.Sprintf("MATCH (r:Rider) RETURN COUNT(r) AS riderCount")
  results, _ = suite.graphdriver.Graph.Query(query)
  fmt.Println(results.Results) // Prints [[riderCount] []]

query CREATE INDEX panics go

Hi,

The query gets executed but the go program panics

graph.Query("CREATE INDEX ON :user(name)")

goroutine 1 [running]: github.com/redislabs/redisgraph-go.QueryResultNew(0xc0000f6000, 0x61cc40, 0xc00000e4e0, 0xc0000aea80, 0x3, 0x3) /home/jinx/go/src/github.com/redislabs/redisgraph-go/query_result.go:85 +0x2f0 github.com/redislabs/redisgraph-go.(*Graph).Query(0xc0000f6000, 0x6788ed, 0x1b, 0x6747d9, 0xa, 0xbf731e6f36bbc14c) /home/jinx/go/src/github.com/redislabs/redisgraph-go/graph.go:108 +0x162

I think the issue is in query_result.go
qr.parseStatistics(r[2])
the Create index only return two values so r[2] is out of bounds.

Thanks

List/Map types not supported in properties

version : v2.0.2

issue: I'm not able to add list/map types as the property value.

example:

       japan := rg.Node{
		Label: "country",
		Properties: map[string]interface{}{
			"name":   "Japan",
			"states": []string{"Kanto", "Chugoku"},
		},
	}

error:

Unrecognized type to convert to string

the following block in utils.go throws the error during the properties encoding.

	switch i.(type) {
	case string:
		s := i.(string)
		return strconv.Quote(s)
	case int:
		return strconv.Itoa(i.(int))
	case float64:
		return strconv.FormatFloat(i.(float64), 'f', -1, 64)
	case bool:
		return strconv.FormatBool(i.(bool))
	case []interface {}:
		arr := i.([]interface{})
		return arrayToString(arr)
	default:
		panic("Unrecognized type to convert to string")
	}

Since the list/map is working via the Redis-CLI. I suspect this as a client library bug.

No way to access query results

There's no way to query a stored graph anymore. Constructing a new graph and committing it works but if I'm accessing a stored graph I can't get at the results of my queries.

From looking at it, they are private in query_results.go and not accessible outside of the package.

I'm happy to jump on this as a contributor and make a PR

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.