Skip to content

Commit

Permalink
Add row type, response type
Browse files Browse the repository at this point in the history
  • Loading branch information
zhilingc committed Oct 17, 2019
1 parent dfaa13b commit 0a7e767
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 40 deletions.
15 changes: 7 additions & 8 deletions sdk/go/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import (
"github.com/gojek/feast/sdk/go/protos/feast/serving"
"google.golang.org/grpc"

ocgrpc "go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/plugin/ocgrpc"
)

var (
ErrUnimplementedMethod = "%s is unimplemented for this client."
)
// Client is a feast serving client.
type Client interface {
GetOnlineFeatures(ctx context.Context, req *OnlineFeaturesRequest) (*OnlineFeaturesResponse, error)
GetFeastServingInfo(ctx context.Context, in *serving.GetFeastServingInfoRequest) (*serving.GetFeastServingInfoResponse, error)
}

// GrpcClient is a grpc client for feast serving.
type GrpcClient struct {
Expand Down Expand Up @@ -45,10 +47,7 @@ func (fc *GrpcClient) GetOnlineFeatures(ctx context.Context, req *OnlineFeatures
}
resp, err := fc.cli.GetOnlineFeatures(ctx, featuresRequest)

return &OnlineFeaturesResponse{
Features: req.Features,
RawResponse: resp,
}, nil;
return &OnlineFeaturesResponse{RawResponse: resp}, nil
}

// GetInfo gets information about the feast serving instance this client is connected to.
Expand Down
4 changes: 2 additions & 2 deletions sdk/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.13
require (
github.com/golang/protobuf v1.3.2
github.com/google/go-cmp v0.3.0
github.com/opentracing/opentracing-go v1.1.0 // indirect
go.opencensus.io v0.22.1 // indirect
github.com/opentracing/opentracing-go v1.1.0
go.opencensus.io v0.22.1
google.golang.org/grpc v1.24.0
)
3 changes: 3 additions & 0 deletions sdk/go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
Expand All @@ -26,6 +27,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -37,6 +39,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
5 changes: 1 addition & 4 deletions sdk/go/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package feast
import (
"fmt"
"github.com/gojek/feast/sdk/go/protos/feast/serving"
"github.com/gojek/feast/sdk/go/protos/feast/types"
"github.com/golang/protobuf/ptypes/duration"
"github.com/golang/protobuf/ptypes/timestamp"
"strconv"
Expand All @@ -16,8 +15,6 @@ var (
)

// OnlineFeaturesRequest wrapper on feast.serving.GetOnlineFeaturesRequest.
//
// Note that by default, the current timestamp is used.
type OnlineFeaturesRequest struct {

// Features is the list of features to obtain from Feast. Each feature must be given by its fully qualified ID,
Expand All @@ -30,7 +27,7 @@ type OnlineFeaturesRequest struct {
MaxAgeSeconds int

// Entities is the list of entity rows to retrieve features on. Each row is a map of entity name to entity value.
Entities []map[string]*types.Value
Entities []Row
}

// Builds the feast-specified request payload from the wrapper.
Expand Down
33 changes: 14 additions & 19 deletions sdk/go/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,19 @@ import (
)

func TestGetOnlineFeaturesRequest(t *testing.T) {
type args struct {
features []string
maxAgeSeconds int
entities []map[string]*types.Value
}
tt := []struct {
name string
args args
req OnlineFeaturesRequest
want *serving.GetOnlineFeaturesRequest
wantErr bool
err error
}{
{
name: "valid",
args: args{
features: []string{"fs:1:feature1", "fs:1:feature2", "fs:2:feature1"},
maxAgeSeconds: 10,
entities: []map[string]*types.Value{
req: OnlineFeaturesRequest{
Features: []string{"fs:1:feature1", "fs:1:feature2", "fs:2:feature1"},
MaxAgeSeconds: 10,
Entities: []Row{
{"entity1": Int64Val(1), "entity2": StrVal("bob")},
{"entity1": Int64Val(1), "entity2": StrVal("annie")},
{"entity1": Int64Val(1), "entity2": StrVal("jane")},
Expand Down Expand Up @@ -76,28 +71,28 @@ func TestGetOnlineFeaturesRequest(t *testing.T) {
},
{
name: "invalid_feature_name/wrong_format",
args: args{
features: []string{"fs1:feature1"},
maxAgeSeconds: 10,
entities: []map[string]*types.Value{},
req: OnlineFeaturesRequest{
Features: []string{"fs1:feature1"},
MaxAgeSeconds: 10,
Entities: []Row{},
},
wantErr: true,
err: fmt.Errorf(ErrInvalidFeatureName, "fs1:feature1"),
},
{
name: "invalid_feature_name/invalid_version",
args: args{
features: []string{"fs:a:feature1"},
maxAgeSeconds: 10,
entities: []map[string]*types.Value{},
req: OnlineFeaturesRequest{
Features: []string{"fs:a:feature1"},
MaxAgeSeconds: 10,
Entities: []Row{},
},
wantErr: true,
err: fmt.Errorf(ErrInvalidFeatureName, "fs:a:feature1"),
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
got, err := NewGetOnlineFeaturesRequest(tc.args.features, tc.args.maxAgeSeconds, tc.args.entities)
got, err := tc.req.buildRequest()
if (err != nil) != tc.wantErr {
t.Errorf("error = %v, wantErr %v", err, tc.wantErr)
return
Expand Down
46 changes: 39 additions & 7 deletions sdk/go/response.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
package feast

import (
"fmt"
"github.com/gojek/feast/sdk/go/protos/feast/serving"
)

var (
ErrLengthMismatch = "Length mismatch; number of na values (%d) not equal to number of features requested (%d)."
ErrFeatureNotFound = "Feature %s not found in response."
)

// OnlineFeaturesResponse is a wrapper around serving.GetOnlineFeaturesResponse.
type OnlineFeaturesResponse struct {
Features []string
RawResponse *serving.GetOnlineFeaturesResponse
}

func (res OnlineFeaturesResponse) ToInt64Array(missingVals map[string]int64) {
// convert the values here
//for _, fields := range res.FieldOrder {
//
//}
}
// Rows retrieves the result of the request as a list of Rows.
func (r OnlineFeaturesResponse) Rows() []Row {
rows := make([]Row, len(r.RawResponse.FieldValues))
for i, val := range r.RawResponse.FieldValues {
rows[i] = val.Fields
}
return rows
}

// Int64Arrays retrieves the result of the request as a list of int64 slices. Any missing values will be filled
// with the missing values provided.
func (r OnlineFeaturesResponse) Int64Arrays(order []string, fillNa []int64) ([][]int64, error) {
rows := make([][]int64, len(r.RawResponse.FieldValues))
if len(fillNa) != len(order) {
return nil, fmt.Errorf(ErrLengthMismatch, len(fillNa), len(order))
}
for i, val := range r.RawResponse.FieldValues {
rows[i] = make([]int64, len(order))
for j, fname := range order {
fValue, exists := val.Fields[fname]
if !exists {
return nil, fmt.Errorf(ErrFeatureNotFound, fname)
}
if fValue.GetVal() == nil {
rows[i][j] = fillNa[j]
} else {
rows[i][j] = fValue.GetInt64Val()
}
}
}
return rows, nil
}
99 changes: 99 additions & 0 deletions sdk/go/response_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package feast

import (
"fmt"
"github.com/gojek/feast/sdk/go/protos/feast/serving"
"github.com/gojek/feast/sdk/go/protos/feast/types"
"github.com/google/go-cmp/cmp"
"testing"
)

var response = OnlineFeaturesResponse{
RawResponse: &serving.GetOnlineFeaturesResponse{
FieldValues: []*serving.GetOnlineFeaturesResponse_FieldValues{
{
Fields: map[string]*types.Value{
"fs:1:feature1": Int64Val(1),
"fs:1:feature2": &types.Value{},
},
},
{
Fields: map[string]*types.Value{
"fs:1:feature1": Int64Val(2),
"fs:1:feature2": Int64Val(2),
},
},
},
},
}

func TestOnlineFeaturesResponseToRow(t *testing.T) {
actual := response.Rows()
expected := []Row{
{"fs:1:feature1": Int64Val(1), "fs:1:feature2": &types.Value{}},
{"fs:1:feature1": Int64Val(2), "fs:1:feature2": Int64Val(2)},
}
if !cmp.Equal(actual, expected) {
t.Errorf("expected: %v, got: %v", expected, actual)
}
}

func TestOnlineFeaturesResponseToInt64Array(t *testing.T) {
type args struct {
order []string
fillNa []int64
}
tt := []struct {
name string
args args
want [][]int64
wantErr bool
err error
}{
{
name: "valid",
args: args{
order: []string{"fs:1:feature2", "fs:1:feature1"},
fillNa: []int64{-1, -1},
},
want: [][]int64{{-1, 1}, {2, 2}},
wantErr: false,
},
{
name: "length mismatch",
args: args{
order: []string{"fs:1:feature2", "fs:1:feature1"},
fillNa: []int64{-1},
},
want: nil,
wantErr: true,
err: fmt.Errorf(ErrLengthMismatch, 1, 2),
},
{
name: "length mismatch",
args: args{
order: []string{"fs:1:feature2", "fs:1:feature3"},
fillNa: []int64{-1, -1},
},
want: nil,
wantErr: true,
err: fmt.Errorf(ErrFeatureNotFound, "fs:1:feature3"),
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
got, err := response.Int64Arrays(tc.args.order, tc.args.fillNa)
if (err != nil) != tc.wantErr {
t.Errorf("error = %v, wantErr %v", err, tc.wantErr)
return
}
if tc.wantErr && err.Error() != tc.err.Error() {
t.Errorf("error = %v, expected err = %v", err, tc.err)
return
}
if !cmp.Equal(got, tc.want) {
t.Errorf("got: \n%v\nwant:\n%v", got, tc.want)
}
})
}
}
2 changes: 2 additions & 0 deletions sdk/go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package feast

import "github.com/gojek/feast/sdk/go/protos/feast/types"

type Row map[string]*types.Value

// StrVal is a int64 type feast value
func StrVal(val string) *types.Value {
return &types.Value{Val: &types.Value_StringVal{StringVal: val}}
Expand Down

0 comments on commit 0a7e767

Please sign in to comment.