Skip to content
Snippets Groups Projects
Commit 5ccc1526 authored by Pawan Rawal's avatar Pawan Rawal
Browse files

Modifying server side code to build protocol buffer response.

1. Protocol buffer now stores a entity based subgraph instead of a predicate
based subgraph.
parent b72aefdc
No related branches found
No related tags found
No related merge requests found
...@@ -9,8 +9,6 @@ It is generated from these files: ...@@ -9,8 +9,6 @@ It is generated from these files:
graphresponse.proto graphresponse.proto
It has these top-level messages: It has these top-level messages:
UidList
Result
GraphRequest GraphRequest
GraphResponse GraphResponse
*/ */
...@@ -34,32 +32,6 @@ var _ = math.Inf ...@@ -34,32 +32,6 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against. // is compatible with the proto package it is being compiled against.
const _ = proto.ProtoPackageIsVersion1 const _ = proto.ProtoPackageIsVersion1
type UidList struct {
Uids []uint64 `protobuf:"varint,1,rep,name=uids" json:"uids,omitempty"`
}
func (m *UidList) Reset() { *m = UidList{} }
func (m *UidList) String() string { return proto.CompactTextString(m) }
func (*UidList) ProtoMessage() {}
func (*UidList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type Result struct {
Values [][]byte `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
Uidmatrix []*UidList `protobuf:"bytes,2,rep,name=uidmatrix" json:"uidmatrix,omitempty"`
}
func (m *Result) Reset() { *m = Result{} }
func (m *Result) String() string { return proto.CompactTextString(m) }
func (*Result) ProtoMessage() {}
func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Result) GetUidmatrix() []*UidList {
if m != nil {
return m.Uidmatrix
}
return nil
}
type GraphRequest struct { type GraphRequest struct {
Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"`
} }
...@@ -67,30 +39,22 @@ type GraphRequest struct { ...@@ -67,30 +39,22 @@ type GraphRequest struct {
func (m *GraphRequest) Reset() { *m = GraphRequest{} } func (m *GraphRequest) Reset() { *m = GraphRequest{} }
func (m *GraphRequest) String() string { return proto.CompactTextString(m) } func (m *GraphRequest) String() string { return proto.CompactTextString(m) }
func (*GraphRequest) ProtoMessage() {} func (*GraphRequest) ProtoMessage() {}
func (*GraphRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } func (*GraphRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type GraphResponse struct { type GraphResponse struct {
Attribute string `protobuf:"bytes,1,opt,name=attribute" json:"attribute,omitempty"` Attribute string `protobuf:"bytes,1,opt,name=attribute" json:"attribute,omitempty"`
Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` Values map[string][]byte `protobuf:"bytes,2,rep,name=values" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"`
Query *UidList `protobuf:"bytes,3,opt,name=query" json:"query,omitempty"` Children []*GraphResponse `protobuf:"bytes,3,rep,name=children" json:"children,omitempty"`
Children []*GraphResponse `protobuf:"bytes,4,rep,name=children" json:"children,omitempty"`
} }
func (m *GraphResponse) Reset() { *m = GraphResponse{} } func (m *GraphResponse) Reset() { *m = GraphResponse{} }
func (m *GraphResponse) String() string { return proto.CompactTextString(m) } func (m *GraphResponse) String() string { return proto.CompactTextString(m) }
func (*GraphResponse) ProtoMessage() {} func (*GraphResponse) ProtoMessage() {}
func (*GraphResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func (*GraphResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *GraphResponse) GetResult() *Result {
if m != nil {
return m.Result
}
return nil
}
func (m *GraphResponse) GetQuery() *UidList { func (m *GraphResponse) GetValues() map[string][]byte {
if m != nil { if m != nil {
return m.Query return m.Values
} }
return nil return nil
} }
...@@ -103,8 +67,6 @@ func (m *GraphResponse) GetChildren() []*GraphResponse { ...@@ -103,8 +67,6 @@ func (m *GraphResponse) GetChildren() []*GraphResponse {
} }
func init() { func init() {
proto.RegisterType((*UidList)(nil), "pb.UidList")
proto.RegisterType((*Result)(nil), "pb.Result")
proto.RegisterType((*GraphRequest)(nil), "pb.GraphRequest") proto.RegisterType((*GraphRequest)(nil), "pb.GraphRequest")
proto.RegisterType((*GraphResponse)(nil), "pb.GraphResponse") proto.RegisterType((*GraphResponse)(nil), "pb.GraphResponse")
} }
...@@ -181,22 +143,20 @@ var _DGraph_serviceDesc = grpc.ServiceDesc{ ...@@ -181,22 +143,20 @@ var _DGraph_serviceDesc = grpc.ServiceDesc{
} }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 265 bytes of a gzipped FileDescriptorProto // 227 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x90, 0x4d, 0x4e, 0xc3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x2f, 0x4a, 0x2c,
0x10, 0x85, 0x49, 0x9b, 0x1a, 0x32, 0x2d, 0x12, 0x0c, 0x08, 0x45, 0x08, 0x24, 0xb0, 0x58, 0x94, 0xc8, 0x28, 0x4a, 0x2d, 0x2e, 0xc8, 0xcf, 0x2b, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
0x05, 0x59, 0x94, 0x0d, 0x07, 0x40, 0x62, 0x01, 0x1b, 0x2c, 0x71, 0x80, 0x84, 0x58, 0xd4, 0x52, 0x62, 0x2a, 0x48, 0x52, 0x52, 0xe1, 0xe2, 0x71, 0x07, 0x49, 0x05, 0xa5, 0x16, 0x96, 0xa6, 0x16,
0x68, 0x8c, 0x7f, 0x10, 0x9c, 0x87, 0x8b, 0xe2, 0x8c, 0x0d, 0xa5, 0x62, 0x37, 0x93, 0xf7, 0xe5, 0x97, 0x08, 0x89, 0x70, 0xb1, 0x02, 0x19, 0x45, 0x95, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41,
0xbd, 0x37, 0x86, 0x83, 0x17, 0x53, 0xeb, 0xa5, 0x91, 0x56, 0xf7, 0x2b, 0x2b, 0x2b, 0x6d, 0x7a, 0x10, 0x8e, 0xd2, 0x39, 0x46, 0x2e, 0x5e, 0xa8, 0x32, 0x88, 0x09, 0x42, 0x32, 0x5c, 0x9c, 0x89,
0xd7, 0xe3, 0x48, 0x37, 0xfc, 0x14, 0xb6, 0x9f, 0x54, 0xfb, 0xa0, 0xac, 0x43, 0x84, 0xdc, 0xab, 0x25, 0x25, 0x45, 0x99, 0x49, 0xa5, 0x25, 0xa9, 0x50, 0xb5, 0x08, 0x01, 0x21, 0x53, 0x2e, 0xb6,
0xd6, 0x96, 0xd9, 0xd9, 0x78, 0x9e, 0x0b, 0x9a, 0xf9, 0x3d, 0x30, 0x21, 0xad, 0xef, 0x1c, 0x1e, 0xb2, 0xc4, 0x1c, 0xa0, 0x81, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0xb2, 0x7a, 0x05, 0x49,
0x01, 0x7b, 0xaf, 0x3b, 0x2f, 0xa3, 0x3e, 0x13, 0x69, 0xc3, 0x4b, 0x28, 0x02, 0xf9, 0x5a, 0x3b, 0x7a, 0x28, 0x06, 0xe8, 0x85, 0x81, 0xe5, 0x5d, 0xf3, 0x4a, 0x8a, 0x2a, 0x83, 0xa0, 0x8a, 0x85,
0xa3, 0x3e, 0xca, 0x51, 0x90, 0xa6, 0x8b, 0x69, 0xa5, 0x9b, 0x2a, 0xb9, 0x8a, 0xb5, 0xca, 0x2f, 0x74, 0xb9, 0x38, 0x92, 0x33, 0x32, 0x73, 0x52, 0x8a, 0x52, 0xf3, 0x24, 0x98, 0xc1, 0x1a, 0x05,
0x60, 0x76, 0x37, 0xd4, 0x10, 0xf2, 0x2d, 0xfc, 0xe9, 0xf0, 0x10, 0x26, 0x61, 0x30, 0x9f, 0xc1, 0x31, 0x34, 0x06, 0xc1, 0x95, 0x48, 0x59, 0x72, 0x71, 0x23, 0x99, 0x22, 0x24, 0xc0, 0xc5, 0x9c,
0x31, 0x9b, 0x17, 0x22, 0x2e, 0xfc, 0x2b, 0x83, 0xdd, 0x84, 0xc5, 0xb6, 0x78, 0x02, 0x45, 0xed, 0x9d, 0x0a, 0x73, 0x38, 0x88, 0x09, 0xf2, 0x0c, 0xd8, 0x64, 0xa0, 0x2b, 0x18, 0x35, 0x78, 0x82,
0x82, 0x43, 0xe3, 0x9d, 0x4c, 0xec, 0xfa, 0x03, 0x72, 0x60, 0x86, 0x2a, 0x86, 0xf4, 0x2c, 0xa4, 0x20, 0x1c, 0x2b, 0x26, 0x0b, 0x46, 0x23, 0x0b, 0x2e, 0x36, 0x17, 0xb0, 0xb1, 0x42, 0x7a, 0x5c,
0xc3, 0x90, 0x1e, 0x4b, 0x8b, 0xa4, 0xe0, 0xf9, 0x4f, 0xd2, 0x98, 0x90, 0x8d, 0x82, 0x51, 0xc1, 0xac, 0x81, 0x20, 0x3f, 0x0a, 0x09, 0x20, 0x59, 0x05, 0x0e, 0x0b, 0x29, 0x4c, 0xcb, 0x95, 0x18,
0x2b, 0xd8, 0x79, 0x5e, 0xaa, 0xae, 0x35, 0x72, 0x55, 0xe6, 0x74, 0xc6, 0xfe, 0x40, 0x6d, 0x34, 0x92, 0xd8, 0xc0, 0x61, 0x67, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x30, 0x75, 0x05, 0xc3, 0x52,
0x11, 0xbf, 0xc8, 0xe2, 0x06, 0xd8, 0x2d, 0x69, 0x58, 0xc1, 0xe4, 0x91, 0x1c, 0xf6, 0xfe, 0xf0, 0x01, 0x00, 0x00,
0x74, 0xe0, 0xf1, 0x7f, 0x07, 0xbe, 0xd5, 0x30, 0x7a, 0xfc, 0xeb, 0xef, 0x00, 0x00, 0x00, 0xff,
0xff, 0x18, 0x87, 0x57, 0xd8, 0x93, 0x01, 0x00, 0x00,
} }
...@@ -8,22 +8,12 @@ service DGraph { ...@@ -8,22 +8,12 @@ service DGraph {
rpc Query (GraphRequest) returns (GraphResponse) {} rpc Query (GraphRequest) returns (GraphResponse) {}
} }
message UidList {
repeated uint64 uids = 1;
}
message Result {
repeated bytes values = 1;
repeated UidList uidmatrix = 2;
}
message GraphRequest { message GraphRequest {
string query = 1; string query = 1;
} }
message GraphResponse { message GraphResponse {
string attribute = 1; string attribute = 1;
Result result = 2; map<string, bytes> values = 2;
UidList query = 3; repeated GraphResponse children = 3; // Each node can have multiple children
repeated GraphResponse children = 4; // Each node can have multiple children
} }
...@@ -252,59 +252,72 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) { ...@@ -252,59 +252,72 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) {
return json.Marshal(r) return json.Marshal(r)
} }
type result struct {
values [][]byte
uidmatrix [][]uint64
}
// This method take in a flatbuffer result, extracts values and uids from it // This method take in a flatbuffer result, extracts values and uids from it
// and converts it to a protocol buffer result // and converts it to a protocol buffer result
func extract(q *task.Query, r *task.Result) (*pb.UidList, *pb.Result, error) { func extract(q *task.Query, r *task.Result) ([]uint64, *result, error) {
result := &pb.Result{} re := new(result)
query := &pb.UidList{} var qu []uint64
var ul task.UidList var ul task.UidList
for i := 0; i < q.UidsLength(); i++ { for i := 0; i < q.UidsLength(); i++ {
uid := q.Uids(i) uid := q.Uids(i)
query.Uids = append(query.Uids, uid) qu = append(qu, uid)
} }
for i := 0; i < r.UidmatrixLength(); i++ { for i := 0; i < r.UidmatrixLength(); i++ {
if ok := r.Uidmatrix(&ul, i); !ok { if ok := r.Uidmatrix(&ul, i); !ok {
return query, result, fmt.Errorf("While parsing UidList") return qu, re, fmt.Errorf("While parsing UidList")
} }
uidList := &pb.UidList{} var uidList []uint64
for j := 0; j < ul.UidsLength(); j++ { for j := 0; j < ul.UidsLength(); j++ {
uid := ul.Uids(j) uid := ul.Uids(j)
uidList.Uids = append(uidList.Uids, uid) uidList = append(uidList, uid)
} }
result.Uidmatrix = append(result.Uidmatrix, uidList) re.uidmatrix = append(re.uidmatrix, uidList)
} }
var tv task.Value var tv task.Value
for i := 0; i < r.ValuesLength(); i++ { for i := 0; i < r.ValuesLength(); i++ {
if ok := r.Values(&tv, i); !ok { if ok := r.Values(&tv, i); !ok {
return query, result, fmt.Errorf("While parsing value") return qu, re, fmt.Errorf("While parsing value")
} }
var ival interface{} var ival interface{}
if err := posting.ParseValue(&ival, tv.ValBytes()); err != nil { if err := posting.ParseValue(&ival, tv.ValBytes()); err != nil {
return query, result, err return qu, re, err
} }
if ival == nil { if ival == nil {
ival = "" ival = ""
} }
result.Values = append(result.Values, []byte(ival.(string))) re.values = append(re.values, []byte(ival.(string)))
} }
return query, result, nil return qu, re, nil
}
// Struct to store reference to the subgraph associated with a protocol buffer
// response
type sgreference struct {
uid uint64
sg *SubGraph
} }
// This method performs a pre traversal on a subgraph and converts it to a // This method converts a subgraph to a protocol buffer response. It transforms
// protocol buffer Graph Response. // the predicate based subgraph to an entity based protocol buffer subgraph.
func (g *SubGraph) PreTraverse() (gr *pb.GraphResponse, rerr error) { func (g *SubGraph) ToProtocolBuffer() (gr *pb.GraphResponse, rerr error) {
gr = &pb.GraphResponse{} gr = &pb.GraphResponse{}
gr.Attribute = g.Attr
if len(g.query) == 0 { if len(g.query) == 0 {
return gr, nil return gr, nil
} }
gr.Attribute = g.Attr
ro := flatbuffers.GetUOffsetT(g.result) ro := flatbuffers.GetUOffsetT(g.result)
r := new(task.Result) r := new(task.Result)
r.Init(g.result, ro) r.Init(g.result, ro)
...@@ -313,24 +326,89 @@ func (g *SubGraph) PreTraverse() (gr *pb.GraphResponse, rerr error) { ...@@ -313,24 +326,89 @@ func (g *SubGraph) PreTraverse() (gr *pb.GraphResponse, rerr error) {
q := new(task.Query) q := new(task.Query)
q.Init(g.query, uo) q.Init(g.query, uo)
query, result, err := extract(q, r) _, result, err := extract(q, r)
if err != nil { if err != nil {
return gr, err return gr, err
} }
gr.Query = query re := &sgreference{}
gr.Result = result re.sg = g
// Stores the uid for the root node in the reference struct.
re.uid = result.uidmatrix[0][0]
for _, child := range g.Children { gr.Values, gr.Children, rerr = re.pretraverse()
childPb, err := child.PreTraverse() if rerr != nil {
x.Err(glog, rerr).Error("Error while traversal")
return gr, rerr
}
return gr, nil
}
// This function performs a binary search on the uids slice and returns the
// index at which it finds the uid, else returns -1
func indexOf(uid uint64, uids []uint64) int {
low, mid, high := 0, 0, len(uids)-1
for low <= high {
mid = (low + high) / 2
if uids[mid] == uid {
return mid
} else if uids[mid] > uid {
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}
// This method gets the values and children for a GraphResponse.
func (re *sgreference) pretraverse() (map[string][]byte,
[]*pb.GraphResponse, error) {
vals := make(map[string][]byte)
var children []*pb.GraphResponse
for _, child := range re.sg.Children {
ro := flatbuffers.GetUOffsetT(child.result)
r := new(task.Result)
r.Init(child.result, ro)
uo := flatbuffers.GetUOffsetT(child.query)
q := new(task.Query)
q.Init(child.query, uo)
query, result, err := extract(q, r)
if err != nil { if err != nil {
x.Err(glog, err).Error("Error while traversal") x.Err(glog, err).Error("Error while extracting query, result")
return gr, err return vals, children, fmt.Errorf("While extracting query, result")
} }
gr.Children = append(gr.Children, childPb) idx := indexOf(re.uid, query)
if len(child.Children) == 0 {
vals[child.Attr] = result.values[idx]
} else {
uids := result.uidmatrix[idx]
// We create as many predicate children as the number of uids.
for _, uid := range uids {
predChild := new(pb.GraphResponse)
predChild.Attribute = child.Attr
ref := new(sgreference)
ref.sg = child
ref.uid = uid
vals, ch, rerr := ref.pretraverse()
if rerr != nil {
x.Err(glog, rerr).Error("Error while traversal")
return vals, children, rerr
}
predChild.Values, predChild.Children = vals, ch
children = append(children, predChild)
}
}
} }
return gr, nil return vals, children, nil
} }
func treeCopy(gq *gql.GraphQuery, sg *SubGraph) { func treeCopy(gq *gql.GraphQuery, sg *SubGraph) {
......
...@@ -320,7 +320,7 @@ func TestToJson(t *testing.T) { ...@@ -320,7 +320,7 @@ func TestToJson(t *testing.T) {
fmt.Printf(string(js)) fmt.Printf(string(js))
} }
func TestPreTraverse(t *testing.T) { func TestToProtocolBuffer(t *testing.T) {
dir, _ := populateGraph(t) dir, _ := populateGraph(t)
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
...@@ -353,44 +353,39 @@ func TestPreTraverse(t *testing.T) { ...@@ -353,44 +353,39 @@ func TestPreTraverse(t *testing.T) {
t.Error(err) t.Error(err)
} }
ugr, err := sg.PreTraverse() gr, err := sg.ToProtocolBuffer()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
if len(ugr.Children) != 4 { if gr.Attribute != "_root_" {
t.Errorf("Expected len 4. Got: %v", ugr.Children) t.Errorf("Expected attribute _root_, Got: %v", gr.Attribute)
} }
child := ugr.Children[0] if len(gr.Values) != 3 {
if child.Attribute != "name" { t.Errorf("Expected values map to contain 3 properties, Got: %v",
t.Errorf("Expected attr name. Got: %v", child.Attribute) len(gr.Values))
} }
if string(child.Result.Values[0]) != "Michonne" { if string(gr.Values["name"]) != "Michonne" {
t.Errorf("Expected value Michonne. Got %v", t.Errorf("Expected property name to have value Michonne, Got: %v",
string(child.Result.Values[0])) string(gr.Values["name"]))
} }
child = ugr.Children[3] if len(gr.Children) != 5 {
t.Errorf("Expected 5 children, Got: %v", len(gr.Children))
}
child := gr.Children[0]
if child.Attribute != "friend" { if child.Attribute != "friend" {
t.Errorf("Expected attr friend. Got: %v", child.Attribute) t.Errorf("Expected attribute friend, Got: %v", child.Attribute)
} }
uids := child.Result.Uidmatrix[0].Uids if len(child.Values) != 1 {
if uids[0] != 23 || uids[1] != 24 || uids[2] != 25 || uids[3] != 31 || t.Errorf("Expected values map to contain 1 property, Got: %v",
uids[4] != 101 { len(child.Values))
t.Errorf("Friend ids don't match")
} }
// To check for name of friends if string(child.Values["name"]) != "Rick Grimes" {
child = child.Children[0] t.Errorf("Expected property name to have value Rick Grimes, Got: %v",
if child.Attribute != "name" { string(child.Values["name"]))
t.Errorf("Expected attr friend. Got: %v", child.Attribute)
} }
if len(child.Query.Uids) != 5 { if len(child.Children) != 0 {
t.Errorf("Expected 5 uids in query. Got: %v", len(child.Query.Uids)) t.Errorf("Expected 0 children, Got: %v", len(child.Children))
}
names := child.Result.Values
if string(names[0]) != "Rick Grimes" || string(names[1]) != "Glenn Rhee" ||
string(names[2]) != "Daryl Dixon" || string(names[3]) != "Andrea" {
t.Errorf("Names don't match")
} }
} }
...@@ -241,7 +241,7 @@ func (s *server) Query(ctx context.Context, ...@@ -241,7 +241,7 @@ func (s *server) Query(ctx context.Context,
} }
glog.WithField("q", req.Query).Debug("Graph processed.") glog.WithField("q", req.Query).Debug("Graph processed.")
resp, err = sg.PreTraverse() resp, err = sg.ToProtocolBuffer()
if err != nil { if err != nil {
x.Err(glog, err).Error("While converting to protocol buffer.") x.Err(glog, err).Error("While converting to protocol buffer.")
return resp, err return resp, err
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment