Skip to content
Snippets Groups Projects
Commit c9fd7838 authored by Manish R Jain's avatar Manish R Jain
Browse files

Removed old code from query. Explained how SubGraph approach would work

parent b4127a6a
No related branches found
No related tags found
No related merge requests found
...@@ -18,143 +18,110 @@ package query ...@@ -18,143 +18,110 @@ package query
import ( import (
"fmt" "fmt"
"math"
"github.com/google/flatbuffers/go" "github.com/google/flatbuffers/go"
"github.com/manishrjain/dgraph/posting" "github.com/manishrjain/dgraph/task"
"github.com/manishrjain/dgraph/posting/types"
"github.com/manishrjain/dgraph/query/result"
"github.com/manishrjain/dgraph/uid" "github.com/manishrjain/dgraph/uid"
"github.com/manishrjain/dgraph/x" "github.com/manishrjain/dgraph/x"
) )
// Aim to get this query working: /*
// { * QUERY:
// me { * Let's take this query from GraphQL as example:
// id * {
// firstName * me {
// lastName * id
// birthday { * firstName
// month * lastName
// day * birthday {
// } * month
// friends { * day
// name * }
// } * friends {
// } * name
// } * }
* }
* }
*
* REPRESENTATION:
* This would be represented in SubGraph format internally, as such:
* SubGraph [result uid = me]
* |
* Children
* |
* --> SubGraph [Attr = "xid"]
* --> SubGraph [Attr = "firstName"]
* --> SubGraph [Attr = "lastName"]
* --> SubGraph [Attr = "birthday"]
* |
* Children
* |
* --> SubGraph [Attr = "month"]
* --> SubGraph [Attr = "day"]
* --> SubGraph [Attr = "friends"]
* |
* Children
* |
* --> SubGraph [Attr = "name"]
*
* ALGORITHM:
* This is a rough and simple algorithm of how to process this SubGraph query
* and populate the results:
*
* For a given entity, a new SubGraph can be started off with NewGraph(id).
* Given a SubGraph, is the Query field empty? [Step a]
* - If no, run (or send it to server serving the attribute) query
* and populate result.
* Iterate over children and copy Result Uids to child Query Uids.
* Set Attr. Then for each child, use goroutine to run Step:a.
* Wait for goroutines to finish.
* Return errors, if any.
*/
var log = x.Log("query") var log = x.Log("query")
// SubGraph is the way to represent data internally. It contains both the
// query and the response. Once generated, this can then be encoded to other
// client convenient formats, like GraphQL / JSON.
type SubGraph struct { type SubGraph struct {
Attr string Attr string
Children []*SubGraph Children []*SubGraph
Query []byte query []byte
Result []byte result []byte
} }
func NewGraph(id uint64, xid string) *SubGraph { func NewGraph(euid uint64, exid string) (*SubGraph, error) {
// This would set the Result field in SubGraph, // This would set the Result field in SubGraph,
// and populate the children for attributes. // and populate the children for attributes.
return nil if len(exid) > 0 {
} u, err := uid.GetOrAssign(exid)
type Mattr struct {
Attr string
Msg *Mattr
Query []byte // flatbuffer
Result []byte // flatbuffer
/*
ResultUids []byte // Flatbuffer result.Uids
ResultValue []byte // gob.Encode
*/
}
type Message struct {
Id uint64 // Dgraph Id
Xid string // External Id
Attrs []Mattr
}
type Node struct {
Id uint64
Xid string
}
func extract(l *posting.List, uids *[]byte, value *[]byte) error {
b := flatbuffers.NewBuilder(0)
var p types.Posting
llen := l.Length()
if ok := l.Get(&p, l.Length()-1); ok {
if p.Uid() == math.MaxUint64 {
// Contains a value posting, not useful for Uids vector.
llen -= 1
}
}
result.UidsStartUidVector(b, llen)
for i := l.Length() - 1; i >= 0; i-- {
if ok := l.Get(&p, i); !ok {
return fmt.Errorf("While retrieving posting")
}
if p.Uid() == math.MaxUint64 {
*value = make([]byte, p.ValueLength())
copy(*value, p.ValueBytes())
} else {
b.PrependUint64(p.Uid())
}
}
vend := b.EndVector(llen)
result.UidsStart(b)
result.UidsAddUid(b, vend)
end := result.UidsEnd(b)
b.Finish(end)
buf := b.Bytes[b.Head():]
*uids = make([]byte, len(buf))
copy(*uids, buf)
return nil
}
func Run(m *Message) error {
if len(m.Xid) > 0 {
u, err := uid.GetOrAssign(m.Xid)
if err != nil { if err != nil {
x.Err(log, err).WithField("xid", m.Xid).Error( x.Err(log, err).WithField("xid", exid).Error(
"While GetOrAssign uid from external id") "While GetOrAssign uid from external id")
return err return nil, err
} }
log.WithField("xid", m.Xid).WithField("uid", u).Debug("GetOrAssign") log.WithField("xid", exid).WithField("uid", u).Debug("GetOrAssign")
m.Id = u euid = u
} }
if m.Id == 0 { if euid == 0 {
err := fmt.Errorf("Query internal id is zero") err := fmt.Errorf("Query internal id is zero")
x.Err(log, err).Error("Invalid query") x.Err(log, err).Error("Invalid query")
return err return nil, err
} }
for idx := range m.Attrs { // Encode uid into result flatbuffer.
mattr := &m.Attrs[idx] b := flatbuffers.NewBuilder(0)
key := posting.Key(m.Id, mattr.Attr) task.ResultStartUidsVector(b, 1)
pl := posting.Get(key) b.PrependUint64(euid)
vend := b.EndVector(1)
if err := extract(pl, &mattr.ResultUids, &mattr.ResultValue); err != nil { task.ResultStart(b)
x.Err(log, err).WithField("uid", m.Id).WithField("attr", mattr.Attr). task.ResultAddUids(b, vend)
Error("While extracting data from posting list") rend := task.ResultEnd(b)
} b.Finish(rend)
if mattr.Msg != nil { sg := new(SubGraph)
// Now this would most likely be sent over wire to other servers. sg.result = b.Bytes[b.Head():]
if err := Run(mattr.Msg); err != nil { return sg, nil
return err
}
}
}
return nil
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment