Pārlūkot izejas kodu

update filter greater

baichongyang 3 gadi atpakaļ
vecāks
revīzija
3e2301f2f8
100 mainītis faili ar 4410 papildinājumiem un 1957 dzēšanām
  1. 8 0
      .idea/.gitignore
  2. 8 0
      .idea/modules.xml
  3. 9 0
      .idea/tzld_rec.iml
  4. 6 0
      .idea/vcs.xml
  5. BIN
      tzld_rec
  6. 77 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_crowd.go
  7. 14 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_crowd_test.go
  8. 1 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment.go
  9. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment_group.go
  10. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment_room.go
  11. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_layer.go
  12. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_param.go
  13. 19 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_param_test.go
  14. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_scene.go
  15. 34 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_scene_test.go
  16. 3 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/client.go
  17. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/configuration.go
  18. 6 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/response_crowd_users.go
  19. 9 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/experiments/client_data.go
  20. 106 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/experiments/client_test.go
  21. 9 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/go.mod
  22. 366 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/go.sum
  23. 13 4
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/experiment.go
  24. 16 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/layer_params.go
  25. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment.go
  26. 18 2
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment_group.go
  27. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment_room.go
  28. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_layer.go
  29. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_param.go
  30. 1 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/.gitignore
  31. 5 12
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/algorithm.go
  32. 11 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec_request.go
  33. 61 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec_request_test.go
  34. 3 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/model.go
  35. 0 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out
  36. 20 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out.dSYM/Contents/Info.plist
  37. BIN
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out.dSYM/Contents/Resources/DWARF/a.out
  38. 30 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/tf_pb_test.go
  39. 5 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf_request.go
  40. 46 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf_request_test.go
  41. 0 320
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/arm_disjoint.go
  42. 0 572
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/arm_hybrid.go
  43. 0 81
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/cycle_queue.go
  44. 0 97
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/decompress.go
  45. 0 140
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/disjoint_policy.go
  46. 0 484
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/feature_hook.go
  47. 0 154
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/hybrid_policy.go
  48. 0 18
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/response.go
  49. 1 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/lookup.go
  50. 31 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/client.go
  51. 30 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/model.go
  52. 81 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/request.go
  53. 65 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/response.go
  54. 18 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/Makefile
  55. 22 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/app/options/config.go
  56. 55 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/app/server.go
  57. 119 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/commands/project.go
  58. 297 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/commands/project_data.go
  59. 10 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/go.mod
  60. 309 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/go.sum
  61. 17 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/log/log.go
  62. 21 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/main.go
  63. 15 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/config/app.go
  64. 26 3
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/context/recommend_context.go
  65. 1 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/datahub/datahub.go
  66. 23 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/hbase/hbase_test.go
  67. 21 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/kafka_test.go
  68. 176 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/bloomfilter/bloom_test.go
  69. 52 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/bloomfilter/redis_bloom_test.go
  70. 1 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/filter.go
  71. 1 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/priority_adjust_count_filter.go
  72. 1 1
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/go.mod
  73. 2 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/go.sum
  74. 38 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/main/main.go
  75. 38 2
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_dao.go
  76. 252 17
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_hologres_dao.go
  77. 360 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_mysql_dao.go
  78. 10 17
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_tablestore_dao.go
  79. 172 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/filter_op.go
  80. 12 11
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/item.go
  81. 56 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/trigger_test.go
  82. 3 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_collaborative_dao.go
  83. 196 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_collaborative_hologres_dao.go
  84. 2 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_dao.go
  85. 1 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_mysql_dao.go
  86. 105 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_redids_dao.go
  87. 2 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_item_exposure_dao.go
  88. 132 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_item_exposure_redis_dao.go
  89. 2 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_dao.go
  90. 61 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_hologres_dao.go
  91. 90 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_mysql_dao.go
  92. 2 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairec.go
  93. 47 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/cache/localcache_test.go
  94. 42 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/cache/redis_test.go
  95. 165 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/holo/postgres_test.go
  96. 37 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb/mysql_test.go
  97. 54 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/redisdb/redis_test.go
  98. 149 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/tablestoredb/tablestore_test.go
  99. 45 17
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf/recconf.go
  100. 38 0
      vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf/recconf_test.go

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/tzld_rec.iml" filepath="$PROJECT_DIR$/.idea/tzld_rec.iml" />
+    </modules>
+  </component>
+</project>

+ 9 - 0
.idea/tzld_rec.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="Go" enabled="true" />
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

BIN
tzld_rec


+ 77 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_crowd.go

@@ -0,0 +1,77 @@
+package api
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/url"
+	"strings"
+)
+
+type CrowdApiService service
+
+/*
+CrowdApiService Get Crowd users By crowd ID
+Get Crowd users By crowd ID
+ * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
+ * @param sceneId Scene Id to get scene info
+@return InlineResponse2001
+*/
+func (a *CrowdApiService) GetCrowdUsersById(ctx context.Context, crowdId int64) (ListCrowdUsersResponse, error) {
+	var (
+		localVarHttpMethod  = strings.ToUpper("Get")
+		localVarPostBody    interface{}
+		localVarFileName    string
+		localVarFileBytes   []byte
+		localVarReturnValue ListCrowdUsersResponse
+	)
+
+	// create path and map variables
+	localVarPath := a.client.cfg.BasePath + "/crowds/{crowd_id}/users"
+	localVarPath = strings.Replace(localVarPath, "{"+"crowd_id"+"}", fmt.Sprintf("%v", crowdId), -1)
+
+	localVarHeaderParams := make(map[string]string)
+	localVarQueryParams := url.Values{}
+	localVarFormParams := url.Values{}
+
+	// to determine the Content-Type header
+	localVarHttpContentTypes := []string{}
+
+	// set Content-Type header
+	localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes)
+	if localVarHttpContentType != "" {
+		localVarHeaderParams["Content-Type"] = localVarHttpContentType
+	}
+
+	r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes)
+	if err != nil {
+		return localVarReturnValue, err
+	}
+
+	localVarHttpResponse, err := a.client.callAPI(r)
+	if err != nil || localVarHttpResponse == nil {
+		return localVarReturnValue, err
+	}
+
+	localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body)
+	localVarHttpResponse.Body.Close()
+	if err != nil {
+		return localVarReturnValue, err
+	}
+
+	if localVarHttpResponse.StatusCode != 200 {
+		err = a.client.decodeResponse(&localVarReturnValue, localVarBody)
+		if err != nil {
+			return localVarReturnValue, err
+		}
+
+		return localVarReturnValue, errors.New(fmt.Sprintf("Http Status code:%d", localVarHttpResponse.StatusCode))
+	} else {
+		err = a.client.decodeResponse(&localVarReturnValue, localVarBody)
+		if err != nil {
+			return localVarReturnValue, err
+		}
+	}
+	return localVarReturnValue, nil
+}

+ 14 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_crowd_test.go

@@ -0,0 +1,14 @@
+package api
+
+import (
+	"context"
+	"fmt"
+	"testing"
+)
+
+func TestGetCrowdUsersById(t *testing.T) {
+	client := createClientApi()
+
+	response, err := client.CrowdApi.GetCrowdUsersById(context.Background(), 1)
+	fmt.Println(response, err)
+}

+ 1 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment.go

@@ -117,6 +117,7 @@ func (a *ExperimentApiService) CloneExperiment(ctx context.Context, experimentId
 
 	// to determine the Content-Type header
 	localVarHttpContentTypes := []string{}
+
 	// set Content-Type header
 	localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes)
 	if localVarHttpContentType != "" {

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment_group.go


+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_experiment_room.go


+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_layer.go


+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_param.go


+ 19 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_param_test.go

@@ -0,0 +1,19 @@
+package api
+
+import (
+	"context"
+	"fmt"
+	"testing"
+)
+
+func TestListParams(t *testing.T) {
+	client := createClientApi()
+
+	response, err := client.ParamApi.GetParam(context.Background(), 1, &ParamApiGetParamOpts{})
+
+	if err != nil {
+		t.Error(err)
+	}
+
+	fmt.Println(response)
+}

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_scene.go


+ 34 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/api_scene_test.go

@@ -0,0 +1,34 @@
+package api
+
+import (
+	"context"
+	"fmt"
+	"testing"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model"
+)
+
+func createClientApi() *APIClient {
+	cfg := NewConfiguration("http://localhost:8080", "")
+
+	return NewAPIClient(cfg)
+}
+
+func TestAddScene(t *testing.T) {
+	client := createClientApi()
+
+	scene := model.Scene{
+		SceneName: "live_feed",
+		SceneInfo: "推荐流",
+	}
+
+	response, err := client.SceneApi.AddScene(context.Background(), scene)
+	fmt.Println(response, err)
+}
+
+func TestGetSceneById(t *testing.T) {
+	client := createClientApi()
+
+	response, err := client.SceneApi.GetSceneById(context.Background(), 2)
+	fmt.Println(response, err)
+}

+ 3 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/client.go

@@ -71,6 +71,8 @@ type APIClient struct {
 	SceneApi *SceneApiService
 
 	ParamApi *ParamApiService
+
+	CrowdApi *CrowdApiService
 }
 
 type service struct {
@@ -95,6 +97,7 @@ func NewAPIClient(cfg *Configuration) *APIClient {
 	c.LayerApi = (*LayerApiService)(&c.common)
 	c.SceneApi = (*SceneApiService)(&c.common)
 	c.ParamApi = (*ParamApiService)(&c.common)
+	c.CrowdApi = (*CrowdApiService)(&c.common)
 
 	return c
 }

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/configuration.go


+ 6 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/api/response_crowd_users.go

@@ -0,0 +1,6 @@
+package api
+
+type ListCrowdUsersResponse struct {
+	BaseResponse
+	Data map[string][]string `json:"data,omitempty"`
+}

+ 9 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/experiments/client_data.go

@@ -82,6 +82,15 @@ func (e *ExperimentClient) LoadExperimentData() {
 				}
 
 				for _, experimentGroup := range listExperimentGroupResponse.Data["experiment_groups"] {
+					if experimentGroup.CrowdId != 0 {
+						listCrowdUsersResponse, err := e.APIClient.CrowdApi.GetCrowdUsersById(context.Background(), experimentGroup.CrowdId)
+						if err != nil {
+							e.logError(fmt.Errorf("list crowd users error, err=%v", err))
+							continue
+						}
+						experimentGroup.CrowdUsers = listCrowdUsersResponse.Data["users"]
+					}
+
 					// ExperimentGroup init
 					if err := experimentGroup.Init(); err != nil {
 						e.logError(fmt.Errorf("experiment group init error, err=%v", err))

+ 106 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/experiments/client_test.go

@@ -0,0 +1,106 @@
+package experiments
+
+import (
+	"fmt"
+	"log"
+	"testing"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/common"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model"
+)
+
+func TestCreateExperimentClient(t *testing.T) {
+	host := "http://localhost:8080"
+	client, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)))
+	if err != nil {
+		t.Error(err)
+	}
+	fmt.Println(client)
+}
+func TestLoadExperimentData(t *testing.T) {
+	host := "http://localhost:8080"
+	_, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)))
+	if err != nil {
+		t.Error(err)
+	}
+
+	// client.LoadExperimentData()
+}
+
+func TestMatchExperiment(t *testing.T) {
+	host := "http://localhost:8080"
+	client, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)), WithErrorLogger(LoggerFunc(log.Fatalf)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	experimentContext := model.ExperimentContext{
+		RequestId: "pvid",
+		Uid:       "2115",
+		FilterParams: map[string]interface{}{
+			"sex": "male",
+			//"age": 35,
+			"uid": 1,
+		},
+	}
+
+	experimentResult := client.MatchExperiment("home_feed", &experimentContext)
+
+	fmt.Println(experimentResult.Info())
+	fmt.Println(experimentResult.GetExpId())
+
+	fmt.Println(experimentResult.GetLayerParams("").GetString("a", "not exist"))
+	fmt.Println(experimentResult.GetExperimentParams().GetString("a", "not exist"))
+
+}
+
+func TestMatchExperiment2(t *testing.T) {
+	host := "http://1730760139076263.cn-beijing.pai-eas.aliyuncs.com/api/predict/pairec_experiment"
+	client, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)), WithErrorLogger(LoggerFunc(log.Fatalf)), WithToken("YjQ2MTczYThlMGE3MzQ0NzIyNDE5OTQ2N2I0NmE2MWUzZjRkM2UzNg=="))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	experimentContext := model.ExperimentContext{
+		RequestId: "pvid",
+		//Uid:       "211789768",
+		Uid: "102441835",
+		FilterParams: map[string]interface{}{
+			"sex": "male",
+			//"age": 35,
+			"uid": 1,
+		},
+	}
+
+	experimentResult := client.MatchExperiment("homepage", &experimentContext)
+
+	fmt.Println(experimentResult.Info())
+	fmt.Println(experimentResult.GetExpId())
+
+	fmt.Println(experimentResult.GetExperimentParams().GetInt("ivalue", 0))
+	fmt.Println(experimentResult.GetExperimentParams().GetString("svalue", "not exist"))
+	fmt.Println(experimentResult.GetExperimentParams().GetFloat("dvalue", 0))
+
+}
+func TestGetSceneParam(t *testing.T) {
+	host := "http://localhost:8000"
+	client, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)), WithErrorLogger(LoggerFunc(log.Fatalf)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	param := client.GetSceneParams("home_feed").GetString("_feature_consistency_job_", "not exist")
+	fmt.Println(param)
+}
+func TestGetFeatureConsistencyJob(t *testing.T) {
+	host := "http://localhost:8000"
+	client, err := NewExperimentClient(host, common.Environment_Prepub_Desc, WithLogger(LoggerFunc(log.Printf)), WithErrorLogger(LoggerFunc(log.Fatalf)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	jobs := client.GetSceneParams("home_feed").GetFeatureConsistencyJobs()
+	for _, job := range jobs {
+		fmt.Println(job)
+	}
+}

+ 9 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/go.mod

@@ -0,0 +1,9 @@
+module gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang
+
+go 1.13
+
+require (
+	github.com/Knetic/govaluate v3.0.0+incompatible
+	github.com/antihax/optional v1.0.0
+	golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93
+)

+ 366 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/go.sum

@@ -0,0 +1,366 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
+github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 h1:alLDrZkL34Y2bnGHfvC1CYBRBXCXgx8AC2vY4MRtYX4=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+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=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

+ 13 - 4
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/experiment.go

@@ -51,6 +51,8 @@ type ExperimentResult struct {
 	layer2Experiment map[string]*Experiment
 
 	layerParamsMap map[string]LayerParams
+
+	mergedLayerParams LayerParams
 }
 
 func NewExperimentResult(sceneName string, experimentContext *ExperimentContext) *ExperimentResult {
@@ -99,14 +101,12 @@ func (r *ExperimentResult) Init() {
 		buf.WriteString(strconv.Itoa(int(r.ExperimentRoom.ExpRoomId)))
 	}
 	for _, layer := range r.Layers {
-		buf.WriteString("_")
-		buf.WriteString("L")
+		buf.WriteString("_L")
 		buf.WriteString(strconv.Itoa(int(layer.LayerId)))
-		buf.WriteString("#")
 		if experimentGroup, found := r.layer2ExperimentGroup[layer.LayerName]; found {
+			buf.WriteString("#")
 			buf.WriteString("EG")
 			buf.WriteString(strconv.Itoa(int(experimentGroup.ExpGroupId)))
-			buf.WriteString("#")
 			layerParams := NewLayerParams()
 			params := make(map[string]interface{}, 0)
 			if experimentGroup.ExpGroupConfig != "" {
@@ -116,12 +116,14 @@ func (r *ExperimentResult) Init() {
 			}
 			if experiment, found := r.layer2Experiment[layer.LayerName]; found {
 				if experiment.Type != common.Experiment_Type_Default {
+					buf.WriteString("#")
 					buf.WriteString("E")
 					buf.WriteString(strconv.Itoa(int(experiment.ExperimentId)))
 				}
 				//buf.WriteString("#")
 				if experiment.ExperimentConfig != "" {
 					if err := json.Unmarshal([]byte(experiment.ExperimentConfig), &params); err == nil {
+						fmt.Println(params)
 						layerParams.AddParams(params)
 					}
 				}
@@ -174,3 +176,10 @@ func (r *ExperimentResult) Info() string {
 
 	return strings.Join(info, ",")
 }
+
+func (r *ExperimentResult) GetExperimentParams() LayerParams {
+	if r.mergedLayerParams == nil {
+		r.mergedLayerParams = MergeLayerParams(r.layerParamsMap)
+	}
+	return r.mergedLayerParams
+}

+ 16 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/layer_params.go

@@ -1,6 +1,8 @@
 package model
 
-import "strconv"
+import (
+	"strconv"
+)
 
 // LayerParams offers Get* function to get value by the key
 // If not found the key, defaultValue will return
@@ -142,3 +144,16 @@ func (r *layerParams) GetInt64(key string, defaultValue int64) int64 {
 		return defaultValue
 	}
 }
+
+func MergeLayerParams(layersParamsMap map[string]LayerParams) LayerParams {
+	mergedParams := NewLayerParams()
+	for _, unmergedParams := range layersParamsMap {
+		switch v := unmergedParams.(type) {
+		case *layerParams:
+			for k, p := range v.Parameters {
+				mergedParams.Parameters[k] = p
+			}
+		}
+	}
+	return LayerParams(mergedParams)
+}

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment.go


+ 18 - 2
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment_group.go

@@ -8,7 +8,9 @@
  */
 package model
 
-import "strings"
+import (
+	"strings"
+)
 
 type ExperimentGroup struct {
 	ExpGroupId     int64  `json:"exp_group_id,omitempty"`
@@ -20,6 +22,7 @@ type ExperimentGroup struct {
 	DebugUsers     string `json:"debug_users,omitempty"`
 	Owner          string `json:"owner"`
 	Filter         string `json:"filter,omitempty"`
+	CrowdId        int64  `json:"crowd_id,omitempty"`
 	ExpGroupConfig string `json:"exp_group_config,omitempty"`
 	ReserveBuckets string `json:"reserve_buckets,omitempty"`
 	Status         int32  `json:"status,omitempty"`
@@ -27,6 +30,8 @@ type ExperimentGroup struct {
 	Experiments     []*Experiment   `json:"experiments"`
 	debugUserMap    map[string]bool `json:"-"`
 	diversionBucket DiversionBucket
+	CrowdUsers      []string
+	crowdUserMap    map[string]struct{}
 }
 
 func (e *ExperimentGroup) Init() error {
@@ -47,6 +52,11 @@ func (e *ExperimentGroup) Init() error {
 		}
 	}
 
+	e.crowdUserMap = make(map[string]struct{}, len(e.CrowdUsers))
+	for _, uid := range e.CrowdUsers {
+		e.crowdUserMap[uid] = struct{}{}
+	}
+
 	return nil
 }
 func (e *ExperimentGroup) AddExperiment(experiment *Experiment) {
@@ -55,10 +65,16 @@ func (e *ExperimentGroup) AddExperiment(experiment *Experiment) {
 
 func (e *ExperimentGroup) Match(experimentContext *ExperimentContext) bool {
 
-	if e.DebugUsers == "" && e.Filter == "" {
+	if e.DebugUsers == "" && e.Filter == "" && e.CrowdId == 0 {
 		return true
 	}
 
+	if e.Filter == "" && e.CrowdId != 0 {
+		if _, found := e.crowdUserMap[experimentContext.Uid]; found {
+			return true
+		}
+	}
+
 	if _, found := e.debugUserMap[experimentContext.Uid]; found {
 		return true
 	}

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_experiment_room.go


+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_layer.go


+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model/model_param.go


+ 1 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/.gitignore

@@ -2,3 +2,4 @@ vendor/
 commands/pairecmd
 commands/bin/
 commands/tmp/
+.vscode/

+ 5 - 12
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/algorithm.go

@@ -5,10 +5,9 @@ import (
 	"fmt"
 	"sync"
 
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb"
-
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/faiss"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
 )
@@ -68,20 +67,14 @@ func (a *AlgorithmFactory) initAlgo(conf recconf.AlgoConfig) (IAlgorithm, error)
 		if err != nil {
 			return nil, fmt.Errorf("init algorithm error, name:%s, err:%v", conf.Name, err)
 		}
-	} else if conf.Type == "LINUCB_DISJOINT" {
-		algo = linucb.NewDisjointPolicy(conf.Name)
-		err := algo.Init(&conf)
-		if err != nil {
-			return nil, fmt.Errorf("init algorithm error, name:%s, err:%v", conf.Name, err)
-		}
-	} else if conf.Type == "LINUCB_HYBRID" {
-		algo = linucb.NewHybridPolicy(conf.Name)
+	} else if conf.Type == "LOOKUP" {
+		algo = NewLookupPolicy()
 		err := algo.Init(&conf)
 		if err != nil {
 			return nil, fmt.Errorf("init algorithm error, name:%s, err:%v", conf.Name, err)
 		}
-	} else if conf.Type == "LOOKUP" {
-		algo = NewLookupPolicy()
+	} else if conf.Type == "SELDON" {
+		algo = new(seldon.Model)
 		err := algo.Init(&conf)
 		if err != nil {
 			return nil, fmt.Errorf("init algorithm error, name:%s, err:%v", conf.Name, err)

+ 11 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec_request.go

@@ -6,9 +6,11 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"os"
 
 	proto "github.com/golang/protobuf/proto"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/config"
 )
 
 type EasyrecRequest struct {
@@ -23,6 +25,15 @@ func (r *EasyrecRequest) Invoke(requestData interface{}) (response interface{},
 	}
 
 	data, _ := proto.Marshal(request)
+	if config.AppConfig.WarmUpData {
+		warmupFunc := func(data []byte) {
+			if file, err := os.OpenFile("warm_up.bin", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0664); err == nil {
+				file.Write(data)
+				file.Close()
+			}
+		}
+		config.AppConfig.Once.Do(func() { warmupFunc(data) })
+	}
 	req, err := http.NewRequest("POST", r.url, bytes.NewBuffer(data))
 	if err != nil {
 		return

+ 61 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec_request_test.go

@@ -0,0 +1,61 @@
+package eas
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/easyrec"
+)
+
+func TestEasyrecRequest(t *testing.T) {
+
+	builder := easyrec.NewEasyrecRequestBuilder()
+
+	var id interface{}
+	id = 16
+	builder.AddItemId(strconv.Itoa(id.(int)))
+	builder.AddItemId("1")
+	builder.AddItemId("17")
+	builder.AddItemId("18")
+	builder.AddItemId("67552360")
+	builder.AddItemId("7")
+	builder.AddItemId("8")
+	builder.AddUserFeature("u_action_pv_30d", 1)
+	builder.AddUserFeature("u_action_pv_3d", 1)
+	builder.AddUserFeature("u_action_pv_7d", 1)
+	builder.AddUserFeature("u_active_delta_days", 1)
+	builder.AddUserFeature("u_age", 1)
+	builder.AddUserFeature("u_browse_uv_3d", 1)
+
+	request := builder.EasyrecRequest()
+
+	req := EasyrecRequest{}
+	req.SetUrl("http://1233177768936747.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/milian_cupai")
+	req.SetAuth("MGRkZWM0Yzg0ZjllYmNjNmMwMGI1NWU0NTE4ZDIxNzE4N2YyN2M5MA")
+	req.SetTimeout(5000)
+
+	response, err := req.Invoke(request)
+	if err != nil {
+		t.Error(err)
+	}
+	fmt.Println(response.(*easyrec.PBResponse))
+	fmt.Println(fmt.Sprintf("%v", response.(*easyrec.PBResponse)))
+
+	fmt.Println("=========")
+	for k, v := range response.(*easyrec.PBResponse).Results {
+		fmt.Println(k, v)
+		fmt.Println(fmt.Sprintf("%T, %v, %v", k, len(k), k))
+	}
+
+	ret, err := easyrecResponseFunc(response)
+	if err != nil {
+		t.Error(err)
+	}
+
+	fmt.Println("=========")
+	for _, r := range ret {
+		fmt.Println(r.GetScore())
+	}
+
+}

+ 3 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/model.go

@@ -44,6 +44,9 @@ func (m *EasModel) Init(conf *recconf.AlgoConfig) error {
 		req.SetSignatureName(conf.EasConf.SignatureName)
 		req.SetTimeout(conf.EasConf.Timeout)
 		req.SetResponseFunc(conf.EasConf.ResponseFuncName)
+		if len(conf.EasConf.Outputs) > 0 {
+			req.SetOutputs(conf.EasConf.Outputs)
+		}
 		m.request = &req
 
 		if conf.EasConf.RetryTimes > 0 {

+ 0 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out


+ 20 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out.dSYM/Contents/Info.plist

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>CFBundleDevelopmentRegion</key>
+		<string>English</string>
+		<key>CFBundleIdentifier</key>
+		<string>com.apple.xcode.dsym.a.out</string>
+		<key>CFBundleInfoDictionaryVersion</key>
+		<string>6.0</string>
+		<key>CFBundlePackageType</key>
+		<string>dSYM</string>
+		<key>CFBundleSignature</key>
+		<string>????</string>
+		<key>CFBundleShortVersionString</key>
+		<string>1.0</string>
+		<key>CFBundleVersion</key>
+		<string>1</string>
+	</dict>
+</plist>

BIN
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/a.out.dSYM/Contents/Resources/DWARF/a.out


+ 30 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf/tf_pb_test.go

@@ -0,0 +1,30 @@
+package tf
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/gogo/protobuf/proto"
+)
+
+func TestTFProto(t *testing.T) {
+	request := PredictRequest{SignatureName: "predict"}
+	x := ArrayProto{Dtype: ArrayDataType_DT_INT16, IntVal: []int32{5}, ArrayShape: &ArrayShape{Dim: []int64{0}}}
+	request.Inputs = make(map[string]*ArrayProto)
+	request.Inputs["x"] = &x
+
+	data, err := proto.Marshal(&request)
+
+	if err != nil {
+		t.Error(err)
+	}
+
+	fmt.Println(data)
+	newRequest := &PredictRequest{}
+	err = proto.Unmarshal(data, newRequest)
+	if err != nil {
+		t.Error(err)
+	}
+
+	fmt.Println(newRequest.SignatureName, newRequest.Inputs)
+}

+ 5 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf_request.go

@@ -14,11 +14,15 @@ import (
 type TFRequest struct {
 	EasRequest
 	SignatureName string
+	Outputs       []string
 }
 
 func (r *TFRequest) SetSignatureName(name string) {
 	r.SignatureName = name
 }
+func (r *TFRequest) SetOutputs(outputs []string) {
+	r.Outputs = outputs
+}
 func (r *TFRequest) Invoke(requestData interface{}) (response interface{}, err error) {
 	request, ok := requestData.(*tf.PredictRequest)
 	if !ok {
@@ -26,6 +30,7 @@ func (r *TFRequest) Invoke(requestData interface{}) (response interface{}, err e
 		return
 	}
 	request.SignatureName = r.SignatureName
+	request.OutputFilter = r.Outputs
 	data, _ := proto.Marshal(request)
 	req, err := http.NewRequest("POST", r.url, bytes.NewBuffer(data))
 	if err != nil {

+ 46 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf_request_test.go

@@ -0,0 +1,46 @@
+package eas
+
+import (
+	"fmt"
+	"testing"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/eas/tf"
+)
+
+func TestTFRequest(t *testing.T) {
+
+	request := &tf.PredictRequest{}
+
+	fv := make([]float32, 1485)
+	for k := range fv {
+		fv[k] = 0.1
+	}
+
+	image := tf.ArrayProto{
+		Dtype:      tf.ArrayDataType_DT_FLOAT,
+		ArrayShape: &tf.ArrayShape{Dim: []int64{1, 1485}},
+		FloatVal:   fv,
+	}
+
+	request.Inputs = make(map[string]*tf.ArrayProto)
+	request.Inputs["user_feature"] = &image
+	/**
+	request.Inputs["Placeholder_1"] = &tf.ArrayProto{
+		Dtype:      tf.ArrayDataType_DT_FLOAT,
+		ArrayShape: &tf.ArrayShape{Dim: []int64{1, 1}},
+		FloatVal:   []float32{0.1},
+	}
+	**/
+
+	req := TFRequest{}
+	req.SetUrl("http://1276757891219814.cn-beijing.pai-eas.aliyuncs.com/api/predict/tensorflow_demo4")
+	req.SetAuth("ZjNjODNjYzVmZjZlNTRhZGY1ZWFkOWNiMmI3NjEzZmU5OWIwOTM3Yw==")
+	req.SetSignatureName("serving_default")
+	req.SetTimeout(1000)
+
+	response, err := req.Invoke(request)
+	if err != nil {
+		t.Error(err)
+	}
+	fmt.Println(response)
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 320
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/arm_disjoint.go


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 572
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/arm_hybrid.go


+ 0 - 81
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/cycle_queue.go

@@ -1,81 +0,0 @@
-package linucb
-
-import "sync"
-
-type CycleQueue struct {
-	data  []interface{} //存储空间
-	front int           //前指针,前指针负责弹出数据移动
-	rear  int           //尾指针,后指针负责添加数据移动
-	cap   int           //设置切片最大容量
-	lock  sync.Mutex
-}
-
-//init Queue
-func NewCycleQueue(cap int) *CycleQueue {
-	cap++ // 因为有一个元素用不了
-	return &CycleQueue{
-		data:  make([]interface{}, cap),
-		cap:   cap,
-		front: 0,
-		rear:  0,
-	}
-}
-
-func (q *CycleQueue) Freeze() {
-	q.lock.Lock()
-}
-
-func (q *CycleQueue) Unfreeze() {
-	q.lock.Unlock()
-}
-
-//因为是循环队列, 后指针减去前指针 加上最大值, 然后与最大值 取余
-func (q *CycleQueue) Length() int {
-	return (q.rear - q.front + q.cap) % q.cap
-}
-
-//入队操作
-//判断队列是否队满,队满则不允许添加数据
-func (q *CycleQueue) Push(data interface{}) bool {
-	q.lock.Lock()
-	defer q.lock.Unlock()
-	//check queue is full
-	if (q.rear+1)%q.cap == q.front { //队列已满时,不执行入队操作
-		return false
-	}
-	q.data[q.rear] = data         //将元素放入队列尾部
-	q.rear = (q.rear + 1) % q.cap //尾部元素指向下一个空间位置,取模运算保证了索引不越界(余数一定小于除数)
-	return true
-}
-
-//出队操作 需要考虑: 队空没有数据返回了
-func (q *CycleQueue) Pop() interface{} {
-	if q.rear == q.front {
-		return nil
-	}
-	data := q.data[q.front]
-	q.data[q.front] = nil
-	q.front = (q.front + 1) % q.cap
-	return data
-}
-
-func (q *CycleQueue) Peek() interface{} {
-	if q.rear == q.front {
-		return nil
-	}
-	return q.data[q.front]
-}
-
-func (q *CycleQueue) IsFull() bool {
-	if (q.rear+1)%q.cap == q.front {
-		return true
-	}
-	return false
-}
-
-func (q *CycleQueue) IsEmpty() bool {
-	if q.front == q.rear {
-		return true
-	}
-	return false
-}

+ 0 - 97
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/decompress.go

@@ -1,97 +0,0 @@
-package linucb
-
-import (
-	"bytes"
-	"compress/zlib"
-	"encoding/binary"
-	"fmt"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
-	"io"
-	"math"
-	"unsafe"
-)
-
-func Decompress(input []byte) []byte {
-	buf := bytes.NewBuffer(input)
-	reader, _ := zlib.NewReader(buf)
-	defer reader.Close()
-
-	var out bytes.Buffer
-	_, err := io.Copy(&out, reader)
-	if err != nil {
-		log.Error(fmt.Sprintf("decompress error=%v", err))
-	}
-	return out.Bytes()
-}
-
-func ToFloat32(bytes []byte) float32 {
-	bits := binary.BigEndian.Uint32(bytes)
-	return math.Float32frombits(bits)
-}
-
-func ToByteArray(num int32) []byte {
-	size := int(unsafe.Sizeof(num))
-	arr := make([]byte, size)
-	for i := 0; i < size; i++ {
-		byt := *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&num)) + uintptr(i)))
-		arr[i] = byt
-	}
-	return arr
-}
-
-func BytesToFloat32(bytes []byte) []float32 {
-	length := len(bytes) / 4
-	result := make([]float32, 0, length)
-	for i := 0; i < length; i++ {
-		result = append(result, ToFloat32(bytes[i*4:(i+1)*4]))
-	}
-	return result
-}
-
-func ToDenseArray(values []float32) []float64 {
-	result := make([]float64, 0, len(values)*2)
-	for _, v := range values {
-		if math.IsNaN(float64(v)) {
-			length := getNumberFromFloatNaNWithNumber(v)
-			for i := uint32(0); i <= length; i++ {
-				result = append(result, 0)
-			}
-		} else {
-			result = append(result, float64(v))
-		}
-	}
-	return result
-}
-
-func getNumberFromFloatNaNWithNumber(value float32) uint32 {
-	i := math.Float32bits(value)
-	i = i & 0x0000FFFF
-	return i
-}
-
-func Decode(values []int32) []byte {
-	length := values[0]
-	capacity := length
-	if length%4 > 0 {
-		capacity++
-	}
-	result := make([]byte, 0, capacity)
-	for _, v := range values[1:] {
-		result = append(result, ToByteArray(v)...)
-	}
-	if capacity == length {
-		return result
-	} else {
-		return result[:length]
-	}
-}
-
-func Parse(values []int32) []float64 {
-	if len(values) == 0 {
-		return nil
-	}
-	byteArray := Decode(values)
-	decompressed := Decompress(byteArray)
-	floatValues := BytesToFloat32(decompressed)
-	return ToDenseArray(floatValues)
-}

+ 0 - 140
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/disjoint_policy.go

@@ -1,140 +0,0 @@
-package linucb
-
-import (
-	"errors"
-	"fmt"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/response"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/module"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/hook"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
-	"gonum.org/v1/gonum/mat"
-	"time"
-)
-
-type DisjointPolicy struct {
-	name                 string
-	armFactory           *ArmFactory
-	alpha                float64
-	armIdKey             string
-	featureName          string
-	sharedFeatureName    string
-	requestArmNumPerTime int
-	parallelism          int
-}
-
-func NewDisjointPolicy(name string) *DisjointPolicy {
-	return &DisjointPolicy{
-		name:                 name,
-		alpha:                1.0,
-		armIdKey:             "arm_id",
-		featureName:          "linucb_user_feature",
-		sharedFeatureName:    "linucb_arm_feature",
-		requestArmNumPerTime: 10,
-		parallelism:          8,
-	}
-}
-
-func (m *DisjointPolicy) Init(conf *recconf.AlgoConfig) error {
-	m.armFactory = NewArmFactory(conf)
-	if nil == m.armFactory {
-		log.Error("new arm factory failed")
-		return errors.New("new arm factory failed")
-	}
-	if conf.BanditConf.Alpha > 0 {
-		m.alpha = conf.BanditConf.Alpha
-	}
-	if conf.BanditConf.ArmIdKey != "" {
-		m.armIdKey = conf.BanditConf.ArmIdKey
-	}
-	if conf.BanditConf.FeatureName != "" {
-		m.featureName = conf.BanditConf.FeatureName
-	}
-	if conf.BanditConf.SharedFeatureName != "" {
-		m.sharedFeatureName = conf.BanditConf.SharedFeatureName
-	}
-	if conf.BanditConf.Parallelism > 0 {
-		m.parallelism = conf.BanditConf.Parallelism
-		if m.parallelism > 64 {
-			m.parallelism = 64
-		}
-	}
-	m.requestArmNumPerTime = m.armFactory.requestArmNum
-
-	fn := NewFeatureHook(conf)
-	if nil == fn {
-		log.Error("new feature hook failed")
-		return errors.New("new feature hook failed")
-	}
-	hook.AddRecommendCleanHook(fn.serializeFeature)
-	return nil
-}
-
-func (m *DisjointPolicy) Run(algoData interface{}) (interface{}, error) {
-	start := time.Now()
-	featureList := algoData.([]map[string]interface{})
-	if (len(featureList)) == 0 {
-		return nil, nil
-	}
-	armIds := make([]string, 0, len(featureList))
-	for _, item := range featureList {
-		armIdentity, ok := item[m.armIdKey]
-		if !ok {
-			log.Error("arm without id field:" + m.armIdKey)
-			continue
-		}
-		armId := string(armIdentity.(module.ItemId))
-		if armId == "" {
-			log.Error("arm id is empty")
-			continue
-		}
-		armIds = append(armIds, armId)
-	}
-	if len(armIds) == 0 {
-		return nil, nil
-	}
-
-	count, err := m.armFactory.SyncArms(armIds)
-	syncCost := utils.CostTime(start)
-
-	requestCh := make(chan int, m.parallelism) // 最多并发数量控制
-	responseCh := make(chan *Response, len(featureList))
-	defer close(requestCh)
-	defer close(responseCh)
-	for i, item := range featureList {
-		requestCh <- i
-		go func(index int, item map[string]interface{}) {
-			feature := item[m.featureName].([]float64)
-			if sharedFeature, ok := item[m.sharedFeatureName]; ok {
-				feature = append(feature, sharedFeature.([]float64)...) // concat
-			}
-			itemId := string(item[m.armIdKey].(module.ItemId))
-			arm := m.armFactory.GetDisjointArm(itemId)
-			var score float64
-			if arm == nil { // new item
-				context := mat.NewVecDense(len(feature), feature)
-				score = m.alpha * mat.Norm(context, 2)
-			} else {
-				score, err = arm.Score(feature, m.alpha)
-				if err != nil {
-					log.Warning(fmt.Sprintf("error=%v, init a new model", err))
-					context := mat.NewVecDense(len(feature), feature)
-					score = m.alpha * mat.Norm(context, 2)
-					m.armFactory.DeleteArm(itemId)
-				}
-			}
-			responseCh <- &Response{index: index, score: score}
-			<-requestCh // done
-		}(i, item)
-	}
-
-	result := make([]response.AlgoResponse, len(featureList))
-	for i := 0; i < len(featureList); i++ {
-		res := <-responseCh
-		result[res.index] = res
-	}
-	log.Info(fmt.Sprintf("Run LinUCB disjoint policy cost=%d, while sync %d model params cost=%d",
-		utils.CostTime(start), count, syncCost))
-	return result, nil
-}

+ 0 - 484
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/feature_hook.go

@@ -1,484 +0,0 @@
-package linucb
-
-import (
-	"database/sql"
-	"fmt"
-	"github.com/huandu/go-sqlbuilder"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/module"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/holo"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
-	"runtime/debug"
-	"strconv"
-	"strings"
-	"time"
-)
-
-type FeatureHook struct {
-	db                *sql.DB
-	table             string
-	algoType          string
-	featureName       string
-	sharedFeatureName string
-	queue             *CycleQueue
-	stmts             map[int]*sql.Stmt
-	syncInterval      time.Duration
-	scenes            map[string]bool
-}
-
-func NewFeatureHook(conf *recconf.AlgoConfig) *FeatureHook {
-	pg, err := holo.GetPostgres(conf.BanditConf.Hologres)
-	if err != nil {
-		log.Error(fmt.Sprintf("error=%v", err))
-		return nil
-	}
-	if conf.BanditConf.FeatureTable == "" {
-		log.Error("There is no 'FeatureTable' in BanditConf")
-		return nil
-	}
-	featureHook := &FeatureHook{
-		db:                pg.DB,
-		table:             conf.BanditConf.FeatureTable,
-		algoType:          conf.Type,
-		featureName:       "linucb_user_feature",
-		sharedFeatureName: "linucb_arm_feature",
-		queue:             NewCycleQueue(8192),
-		stmts:             make(map[int]*sql.Stmt),
-		syncInterval:      time.Minute,
-		scenes:            make(map[string]bool),
-	}
-	if conf.BanditConf.FeatureName != "" {
-		featureHook.featureName = conf.BanditConf.FeatureName
-	}
-	if conf.BanditConf.SharedFeatureName != "" {
-		featureHook.sharedFeatureName = conf.BanditConf.SharedFeatureName
-	}
-	featureHook.getScenes()
-	go featureHook.loopPersistFeature()
-	return featureHook
-}
-
-func (h *FeatureHook) getScenes() {
-	if recconf.Config == nil {
-		log.Error("module=FeatureHook.getScenes\trecconf.Config=nil")
-		return
-	}
-	linucbAlgoNames := make(map[string]bool, 0)
-	for _, algo := range recconf.Config.AlgoConfs {
-		if algo.Type == "LINUCB_DISJOINT" || algo.Type == "LINUCB_HYBRID" {
-			linucbAlgoNames[algo.Name] = true
-		}
-	}
-	if len(linucbAlgoNames) == 0 {
-		return
-	}
-	var b strings.Builder
-	for scene, conf := range recconf.Config.RankConf {
-		for _, algo := range conf.RankAlgoList {
-			if _, ok := linucbAlgoNames[algo]; ok {
-				h.scenes[scene] = true
-				b.WriteString(scene)
-				b.WriteString(",")
-			}
-		}
-	}
-	log.Info("Use LinUCB algo scenes:" + b.String())
-}
-
-func (h *FeatureHook) loopPersistFeature() {
-	defer func() {
-		if err := recover(); err != nil {
-			stack := string(debug.Stack())
-			log.Error(fmt.Sprintf("error=%v, stack=%s", err, strings.ReplaceAll(stack, "\n", "\t")))
-		}
-	}()
-
-	for {
-		time.Sleep(h.syncInterval)
-		_ = h.storageFeature()
-	}
-}
-
-type FeatureData struct {
-	recomId   string
-	userId    string
-	armId     string
-	feature   string
-	recomTime time.Time
-}
-
-func (h *FeatureHook) storageFeature() error {
-	if h.queue.IsEmpty() {
-		return nil
-	}
-	h.queue.Freeze() // storage未完成之前,不能再push
-	defer h.queue.Unfreeze()
-
-	total := h.queue.Length()
-	start := time.Now()
-	defer func() {
-		log.Info(fmt.Sprintf("module=storageFeature\tcount=%d\tcost=%d", total-h.queue.Length(), utils.CostTime(start)))
-	}()
-
-label:
-	if !h.queue.IsFull() {
-		head := h.queue.Peek()
-		if head != nil {
-			data := head.(*FeatureData)
-			if time.Now().Sub(data.recomTime) < h.syncInterval {
-				return nil
-			}
-		} else { // is empty
-			return nil
-		}
-	}
-
-	num := h.queue.Length()
-	batch := 1
-	if num >= 8192 {
-		batch = 8192
-	} else if num >= 4096 {
-		batch = 4096
-	} else if num >= 2048 {
-		batch = 2048
-	} else if num >= 1024 {
-		batch = 1024
-	} else if num >= 512 {
-		batch = 512
-	} else if num >= 256 {
-		batch = 256
-	} else if num >= 128 {
-		batch = 128
-	} else if num >= 64 {
-		batch = 64
-	} else if num >= 32 {
-		batch = 32
-	} else if num >= 16 {
-		batch = 16
-	} else {
-		batch = num // insert all left
-	}
-
-	builder := sqlbuilder.PostgreSQL.NewInsertBuilder()
-	builder.InsertInto(h.table)
-	builder.Cols("recom_id", "user_id", "arm_id", "recom_time", "feature")
-
-	count := 0
-	for i := 0; i < batch; i++ {
-		data := h.queue.Pop()
-		if data == nil {
-			break
-		}
-		feature := data.(*FeatureData)
-		builder.Values(feature.recomId, feature.userId, feature.armId, feature.recomTime, feature.feature)
-		count++
-	}
-	insertSql, args := builder.Build()
-
-	insertStmt, ok := h.stmts[count]
-	if !ok {
-		stmt, err := h.db.Prepare(insertSql)
-		if err != nil {
-			log.Error(fmt.Sprintf("perpare insert sql failed: %s", insertSql))
-			return err
-		}
-		h.stmts[count] = stmt
-		insertStmt = stmt
-	}
-
-	_, err := insertStmt.Exec(args...)
-	if err != nil {
-		log.Error(fmt.Sprintf("persist feature failed. \tmsg=insert error\terror=%v\tsql=%s", err, insertSql))
-		insertStmt.Close()
-		delete(h.stmts, count)
-		return err
-	}
-	if h.queue.IsEmpty() {
-		return nil
-	} else {
-		goto label
-	}
-}
-
-// RecommendCleanHooks
-func (h *FeatureHook) serializeFeature(context *context.RecommendContext, params ...interface{}) {
-	sceneName := context.GetParameter("scene").(string)
-	if _, ok := h.scenes[sceneName]; !ok {
-		return // 只有使用了算法的场景才需要持久化特征
-	}
-	if len(params) < 2 {
-		fmt.Println("persistFeature argument number is smaller than 2")
-		return
-	}
-	start := time.Now()
-	user := params[0].(*module.User)
-	if string(user.Id) == "" {
-		log.Error(fmt.Sprintf("[%s] user id is empty", sceneName))
-		return
-	}
-	items := params[1].([]*module.Item)
-	recomId := context.RecommendId
-	feature := user.GetProperty(h.featureName)
-	if feature == nil {
-		log.Error(fmt.Sprintf("[%s] user has no feature property %s", sceneName, h.featureName))
-		return
-	}
-	userFeature := feature.([]float64)
-	if len(userFeature) == 0 {
-		log.Error("There's no user feature, scene name=" + sceneName)
-		return
-	}
-	concat := h.algoType == "LINUCB_DISJOINT"
-	now := time.Now()
-	for _, item := range items {
-		if string(item.Id) == "" {
-			log.Error(fmt.Sprintf("[%s] item id is empty", sceneName))
-			continue
-		}
-		sharedFeature := item.GetProperty(h.sharedFeatureName)
-		var interactFeature []float64 = nil
-		if nil == sharedFeature || len(sharedFeature.([]float64)) == 0 {
-			log.Warning(fmt.Sprintf("item has no feature perperty %s", h.sharedFeatureName))
-		} else {
-			interactFeature = sharedFeature.([]float64)
-		}
-		compressFeature := compress(userFeature, interactFeature, concat)
-		if compressFeature == "" {
-			continue
-		}
-		var data = FeatureData{
-			recomId:   recomId,
-			userId:    string(user.Id),
-			armId:     string(item.Id),
-			feature:   compressFeature,
-			recomTime: now,
-		}
-	pushLabel:
-		if !h.queue.Push(&data) {
-			// queue is full
-			_ = h.storageFeature()
-			goto pushLabel
-		}
-	}
-	log.Info(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\tcost=%d", recomId, utils.CostTime(start)))
-}
-
-func compress(feature, sharedFeature []float64, concat bool) string {
-	dim := len(feature)
-	if dim == 0 {
-		return ""
-	}
-	length := dim
-	if concat && sharedFeature != nil {
-		length += len(sharedFeature)
-	}
-
-	var b strings.Builder
-	b.Grow(320)
-	b.WriteString(strconv.Itoa(length))
-	for i, v := range feature {
-		if v == 0 {
-			continue
-		}
-		b.WriteString(fmt.Sprintf(",%d:%g", i, float32(v)))
-	}
-
-	if sharedFeature == nil {
-		return b.String()
-	}
-	sharedDim := len(sharedFeature)
-	if sharedDim == 0 {
-		return b.String()
-	}
-
-	if concat {
-		for i, v := range sharedFeature {
-			if v == 0 {
-				continue
-			}
-			index := i + dim
-			b.WriteString(fmt.Sprintf(",%d:%g", index, float32(v)))
-		}
-	} else {
-		b.WriteString("|")
-		b.WriteString(strconv.Itoa(sharedDim))
-		for i, v := range sharedFeature {
-			if v == 0 {
-				continue
-			}
-			b.WriteString(fmt.Sprintf(",%d:%g", i, float32(v)))
-		}
-	}
-	return b.String()
-}
-
-/*
-func (h *FeatureHook) storageSmallBulk() error {
-	// INSERT in transaction is not supported now
-	if h.queue.IsEmpty() {
-		return nil
-	}
-	start := time.Now()
-	txn, err := h.db.Begin()
-	if err != nil {
-		log.Error(fmt.Sprintf("module=storageSmallBulk\terror=%v", err))
-		return err
-	}
-
-	insertSql := fmt.Sprintf("INSERT INTO %s(recom_id,user_id,arm_id,recom_time,feature) VALUES($1,$2,$3,$4,$5)", h.table)
-	fmt.Println(insertSql)
-	stmt, err := txn.Prepare(insertSql)
-	if err != nil {
-		log.Error(fmt.Sprintf("module=storageSmallBulk\terror=%v", err))
-		return err
-	}
-	defer stmt.Close()
-
-	count := h.queue.Length()
-	for i := 0; i < count; i++ {
-		data := h.queue.Pop()
-		if data == nil {
-			break
-		}
-		feature := data.(*FeatureData)
-		_, err = stmt.Exec(feature.recomId, feature.userId, feature.armId, feature.recomTime, feature.feature)
-		if err != nil {
-			log.Error(fmt.Sprintf("module=storageSmallBulk\terror=%v", err))
-		}
-	}
-	if err = txn.Commit(); err != nil {
-		log.Error(fmt.Sprintf("module=storageSmallBulk\terror=%v", err))
-		return err
-	}
-	log.Info(fmt.Sprintf("module=storageSmallBulk\tcount=%d\tcost=%d", count, utils.CostTime(start)))
-	return nil
-}
-
-func (h *FeatureHook) persistBulkFeature(context *context.RecommendContext, params ...interface{}) {
-	if len(params) < 2 {
-		fmt.Println("persistFeature argument number is smaller than 2")
-		return
-	}
-	start := time.Now()
-	user := params[0].(*module.User)
-	userId, err := strconv.ParseInt(string(user.Id), 10, 64)
-	if err != nil {
-		log.Error(fmt.Sprintf("parse user id %s to int failed", user.Id))
-	}
-	items := params[1].([]*module.Item)
-	recomId := context.RecommendId
-	feature := user.GetProperty(h.featureName)
-	if feature == nil {
-		log.Error(fmt.Sprintf("user has no feature property %s", h.featureName))
-		return
-	}
-	userFeature := feature.([]float64)
-	if len(userFeature) == 0 {
-		log.Error("There's no user feature")
-		return
-	}
-	concat := h.algoType == "LINUCB_DISJOINT"
-
-	txn, err := h.db.Begin()
-	if err != nil {
-		log.Error(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\terror=%v", recomId, err))
-		return
-	}
-	// error=pq: relation "contextual_bandit_features" does not exist
-	stmt, err := txn.Prepare(pq.CopyIn(h.table, "recom_id", "user_id", "arm_id", "recom_time", "feature"))
-	if err != nil {
-		log.Error(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\terror=%v", recomId, err))
-		return
-	}
-	defer stmt.Close()
-	now := "NOW()"
-	for _, item := range items {
-		itemId, err := strconv.ParseInt(string(item.Id), 10, 64)
-		if err != nil {
-			log.Error(fmt.Sprintf("parse item id %s to int failed", item.Id))
-			continue
-		}
-		sharedFeature := item.GetProperty(h.sharedFeatureName)
-		var interactFeature []float64 = nil
-		if nil == sharedFeature || len(sharedFeature.([]float64)) == 0 {
-			log.Warning(fmt.Sprintf("item has no feature perperty %s", h.sharedFeatureName))
-		} else {
-			interactFeature = sharedFeature.([]float64)
-		}
-		compressFeature := compress(userFeature, interactFeature, concat)
-		if compressFeature == "" {
-			continue
-		}
-		fmt.Println(recomId, userId, itemId, now, compressFeature)
-		_, err = stmt.Exec(recomId, userId, itemId, now, compressFeature)
-		if err != nil {
-			fmt.Println(err)
-			log.Error(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\terror=%v", recomId, err))
-		}
-	}
-	//err = stmt.Close()
-	//if err != nil {
-	//	log.Error(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\terror=%v", recomId, err))
-	//}
-	err = txn.Commit()
-	if err != nil {
-		log.Error(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\terror=%v", recomId, err))
-	}
-	log.Info(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\tcost=%d", recomId, utils.CostTime(start)))
-}
-
-// persistFeature(context *context.RecommendContext, user *module.User, items []*module.Item)
-func (h *FeatureHook) persistFeature(context *context.RecommendContext, params ...interface{}) {
-	// this method is too slow
-	if len(params) < 2 {
-		fmt.Println("persistFeature argument number is smaller than 2")
-		return
-	}
-	start := time.Now()
-	user := params[0].(*module.User)
-	items := params[1].([]*module.Item)
-
-	builder := sqlbuilder.PostgreSQL.NewInsertBuilder()
-	builder.InsertInto(h.table)
-	builder.Cols("recom_id", "user_id", "arm_id", "recom_time", "feature")
-
-	feature := user.GetProperty(h.featureName)
-	if feature == nil {
-		log.Error(fmt.Sprintf("user has no feature property %s", h.featureName))
-		return
-	}
-
-	now := sqlbuilder.Raw("NOW()")
-	userId, err := strconv.ParseInt(string(user.Id), 10, 64)
-	if err != nil {
-		log.Error(fmt.Sprintf("parse user id %s to int failed", user.Id))
-	}
-
-	concat := h.algoType == "LINUCB_DISJOINT"
-	recomId := context.RecommendId
-	for _, item := range items {
-		itemId, err := strconv.ParseInt(string(item.Id), 10, 64)
-		if err != nil {
-			log.Error(fmt.Sprintf("parse item id %s to int failed", item.Id))
-			continue
-		}
-		sharedFeature := item.GetProperty(h.sharedFeatureName)
-		if nil == sharedFeature || len(sharedFeature.([]float64)) == 0 {
-			log.Info(fmt.Sprintf("item has no feature perperty %s", h.sharedFeatureName))
-			builder.Values(recomId, userId, itemId, now, compress(feature.([]float64), nil, concat))
-		} else {
-			builder.Values(recomId, userId, itemId, now, compress(feature.([]float64), sharedFeature.([]float64), concat))
-		}
-	}
-
-	insertSql, args := builder.Build()
-	_, err = h.db.Exec(insertSql, args...)
-	if err != nil {
-		log.Error(fmt.Sprintf("persist feature failed. userId=%d\tmsg=insert error\terror=%v", userId, err))
-		return
-	}
-	log.Info(fmt.Sprintf("requestId=%s\tmodule=PersistFeature\tcost=%d", recomId, utils.CostTime(start)))
-}
-*/

+ 0 - 154
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/hybrid_policy.go

@@ -1,154 +0,0 @@
-package linucb
-
-import (
-	"errors"
-	"fmt"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/response"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/module"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service/hook"
-	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
-	"strconv"
-	"time"
-)
-
-type HybridPolicy struct {
-	name                 string
-	armFactory           *HybridArmFactory
-	alpha                float64
-	armIdKey             string
-	featureName          string
-	sharedFeatureName    string
-	globalId             string
-	requestArmNumPerTime int
-	parallelism          int
-}
-
-func NewHybridPolicy(name string) *HybridPolicy {
-	return &HybridPolicy{
-		name:                 name,
-		alpha:                1.0,
-		armIdKey:             "arm_id",
-		globalId:             "-1",
-		featureName:          "linucb_user_feature",
-		sharedFeatureName:    "linucb_arm_feature",
-		requestArmNumPerTime: 10,
-		parallelism:          8,
-	}
-}
-
-func (m *HybridPolicy) Init(conf *recconf.AlgoConfig) error {
-	m.armFactory = NewHybridArmFactory(conf)
-	if nil == m.armFactory {
-		log.Error("new hybrid arm factory failed")
-		return errors.New("new hybrid arm factory failed")
-	}
-	if conf.BanditConf.Alpha > 0 {
-		m.alpha = conf.BanditConf.Alpha
-	}
-	if conf.BanditConf.ArmIdKey != "" {
-		m.armIdKey = conf.BanditConf.ArmIdKey
-	}
-	if conf.BanditConf.FeatureName != "" {
-		m.featureName = conf.BanditConf.FeatureName
-	}
-	if conf.BanditConf.SharedFeatureName != "" {
-		m.sharedFeatureName = conf.BanditConf.SharedFeatureName
-	}
-	if conf.BanditConf.GlobalModelParamId != "" {
-		m.globalId = conf.BanditConf.GlobalModelParamId
-	}
-	if conf.BanditConf.Parallelism > 0 {
-		m.parallelism = conf.BanditConf.Parallelism
-		if m.parallelism > 64 {
-			m.parallelism = 64
-		}
-	}
-	m.requestArmNumPerTime = m.armFactory.requestArmNum
-
-	fn := NewFeatureHook(conf)
-	if nil == fn {
-		log.Error("new feature hook failed")
-		return errors.New("new feature hook failed")
-	}
-	hook.AddRecommendCleanHook(fn.serializeFeature)
-	return nil
-}
-
-func (m *HybridPolicy) Run(algoData interface{}) (interface{}, error) {
-	start := time.Now()
-	featureList := algoData.([]map[string]interface{})
-	if (len(featureList)) == 0 {
-		return nil, nil
-	}
-	armIds := make([]string, 0, len(featureList))
-	for _, item := range featureList {
-		armIdentity, ok := item[m.armIdKey]
-		if !ok {
-			log.Error("arm without id field:" + m.armIdKey)
-			continue
-		}
-		armId := string(armIdentity.(module.ItemId))
-		if armId == "" {
-			log.Error("arm id is empty")
-			continue
-		}
-		armIds = append(armIds, armId)
-	}
-	if len(armIds) == 0 {
-		return nil, nil
-	}
-
-	count, err := m.armFactory.SyncArms(armIds)
-	globalId, _ := strconv.ParseInt(m.globalId, 10, 64)
-	_ = m.armFactory.SyncGlobalParams()
-	syncCost := utils.CostTime(start)
-
-	requestCh := make(chan int, m.parallelism) // 最多并发数量控制
-	responseCh := make(chan *Response, len(featureList))
-	defer close(requestCh)
-	defer close(responseCh)
-	for i, item := range featureList {
-		requestCh <- i
-		go func(index int, item map[string]interface{}) {
-			sharedFeature := item[m.sharedFeatureName].([]float64)
-			if m.armFactory.globalParam.Version == 0 {
-				m.armFactory.mutex.Lock()
-				if m.armFactory.globalParam.Version == 0 {
-					m.armFactory.globalParam = NewDefaultHybridArm(globalId, len(sharedFeature))
-				}
-				m.armFactory.mutex.Unlock()
-			}
-			feature := item[m.featureName].([]float64)
-
-			armId := string(item[m.armIdKey].(module.ItemId))
-			arm := m.armFactory.GetHybridArm(armId)
-			var score float64
-			if arm == nil { // new item
-				score, err = m.armFactory.globalParam.DefaultScore(feature, sharedFeature, m.alpha)
-				if err != nil {
-					log.Warning(fmt.Sprintf("error=%v", err))
-				}
-			} else {
-				score, err = arm.Score(m.armFactory.globalParam, feature, sharedFeature, m.alpha)
-				if err != nil {
-					log.Warning(fmt.Sprintf("error=%v, use default score", err))
-					score, _ = m.armFactory.globalParam.DefaultScore(feature, sharedFeature, m.alpha)
-					m.armFactory.DeleteArm(armId)
-				}
-			}
-			responseCh <- &Response{index: index, score: score}
-			<-requestCh // done
-		}(i, item)
-	}
-
-	result := make([]response.AlgoResponse, len(featureList))
-	for i := 0; i < len(featureList); i++ {
-		res := <-responseCh
-		result[res.index] = res
-	}
-	log.Info(fmt.Sprintf("Run LinUCB hybrid policy cost=%d, while sync %d model params cost=%d",
-		utils.CostTime(start), count, syncCost))
-	return result, nil
-}

+ 0 - 18
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/linucb/response.go

@@ -1,18 +0,0 @@
-package linucb
-
-type Response struct {
-	index int
-	score float64
-}
-
-func (r *Response) GetScore() float64 {
-	return r.score
-}
-
-func (r *Response) GetScoreMap() map[string]float64 {
-	return nil
-}
-
-func (r *Response) GetModuleType() bool {
-	return false
-}

+ 1 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/lookup.go

@@ -47,5 +47,5 @@ func (m *LookupPolicy) Run(algoData interface{}) (interface{}, error) {
 			result[i] = &LookupResponse{score: 0.5}
 		}
 	}
-	return nil, nil
+	return result, nil
 }

+ 31 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/client.go

@@ -0,0 +1,31 @@
+package seldon
+
+import (
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/response"
+	"net"
+	"net/http"
+	"time"
+)
+
+var seldonClient *http.Client
+
+func init() {
+	tr := &http.Transport{
+		DialContext: (&net.Dialer{
+			Timeout:   100 * time.Millisecond, // 100ms
+			KeepAlive: 5 * time.Minute,
+		}).DialContext,
+		MaxIdleConnsPerHost:   200,
+		MaxIdleConns:          200,
+		IdleConnTimeout:       90 * time.Second,
+		TLSHandshakeTimeout:   10 * time.Second,
+		ExpectContinueTimeout: 10 * time.Second,
+	}
+
+	seldonClient = &http.Client{Transport: tr}
+}
+
+type ISeldonRequest interface {
+	Invoke(requestData interface{}) (body interface{}, err error)
+	GetResponseFunc() response.ResponseFunc
+}

+ 30 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/model.go

@@ -0,0 +1,30 @@
+package seldon
+
+import (
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+)
+
+type Model struct {
+	request ISeldonRequest
+}
+
+func (r *Model) Init(conf *recconf.AlgoConfig) error {
+	req := Request{}
+	req.SetUrl(conf.SeldonConf.Url)
+	req.SetResponseFunc(conf.SeldonConf.ResponseFuncName)
+	r.request = &req
+	return nil
+}
+
+func (r *Model) Run(algoData interface{}) (interface{}, error) {
+	data, err := r.request.Invoke(algoData)
+	if err != nil {
+		return nil, err
+	}
+
+	if r.request.GetResponseFunc() != nil {
+		return r.request.GetResponseFunc()(data)
+	}
+
+	return data, err
+}

+ 81 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/request.go

@@ -0,0 +1,81 @@
+package seldon
+
+import (
+	"bytes"
+	"encoding/json"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/response"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+)
+
+type Request struct {
+	url          string
+	responseFunc response.ResponseFunc
+}
+
+func (r *Request) SetUrl(url string) {
+	r.url = url
+}
+
+func (r *Request) SetResponseFunc(name string) {
+	r.responseFunc = ResponseFunc
+}
+
+func (r *Request) GetResponseFunc() response.ResponseFunc {
+	return r.responseFunc
+}
+
+type PredictRequest struct {
+	ReqJsonData ReqJsonData `json:"jsonData"`
+}
+
+type ReqJsonData struct {
+	Inputs map[string][]interface{} `json:"inputs"`
+}
+
+func (r *Request) Invoke(requestData interface{}) (body interface{}, err error) {
+	features := make(map[string][]interface{})
+	if data, ok := requestData.([]map[string]interface{}); ok {
+		for _, d := range data {
+			for k, v := range d {
+				if features[k] == nil {
+					features[k] = make([]interface{}, 0)
+				}
+				switch value := v.(type) {
+				case int:
+					v = strconv.Itoa(value)
+				case float64:
+					v = strconv.FormatFloat(value, 'f', -1, 64)
+				}
+				features[k] = append(features[k], v)
+			}
+		}
+	}
+
+	predictRequest := PredictRequest{ReqJsonData: ReqJsonData{Inputs: features}}
+	reqData, _ := json.Marshal(predictRequest)
+
+	header := map[string][]string{
+		"Content-Type": {"application/json"},
+	}
+
+	req, err := http.NewRequest("POST", r.url, bytes.NewBuffer(reqData))
+	if err != nil {
+		return
+	}
+	req.Header = header
+	resp, err := seldonClient.Do(req)
+	if err != nil {
+		return
+	}
+
+	defer resp.Body.Close()
+
+	body, err = ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return
+	}
+
+	return body, nil
+}

+ 65 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/seldon/response.go

@@ -0,0 +1,65 @@
+package seldon
+
+import (
+	"encoding/json"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm/response"
+)
+
+type Response struct {
+	score          float64
+	scoreArr       map[string]float64
+	multiValModule bool
+}
+
+func (r *Response) GetScore() float64 {
+	return r.score
+}
+
+func (r *Response) GetScoreMap() map[string]float64 {
+	return r.scoreArr
+}
+
+func (r *Response) GetModuleType() bool {
+	return r.multiValModule
+}
+
+type PredictResponse struct {
+	JsonData JsonData `json:"jsonData"`
+}
+
+type JsonData struct {
+	Outputs map[string][]float64 `json:"outputs"`
+}
+
+func ResponseFunc(data interface{}) (ret []response.AlgoResponse, err error) {
+	var predictResp PredictResponse
+
+	if v, ok := data.([]byte); ok {
+		err = json.Unmarshal(v, &predictResp)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	retLen := 0
+	for _, scores := range predictResp.JsonData.Outputs {
+		if len(scores) > retLen {
+			retLen = len(scores)
+		}
+	}
+
+	for i := 0; i < retLen; i++ {
+		scoreArr := make(map[string]float64)
+		for property, scores := range predictResp.JsonData.Outputs {
+			if i < len(scores) {
+				scoreArr[property] = scores[i]
+			}
+		}
+		ret = append(ret, &Response{
+			scoreArr:       scoreArr,
+			multiValModule: true,
+		})
+	}
+
+	return
+}

+ 18 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/Makefile

@@ -0,0 +1,18 @@
+## 定义通用变量
+BUILD=go build -ldflags '-s -w -extldflags "-static"'
+
+.PHONY : setup  clean pairecmd
+pairecmd: setup
+	GOOS=linux ${BUILD} -o pairecmd .
+	GOOS=darwin ${BUILD} -o pairecmdmac .
+	GOOS=windows ${BUILD} -o pairecmdwin .
+	-mv pairecmd pairecmdwin pairecmdmac bin/
+
+setup:
+	if [ ! -d bin ]; then\
+		mkdir bin; \
+	fi
+
+clean:
+	-rm -rf build
+	-rm -rf bin

+ 22 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/app/options/config.go

@@ -0,0 +1,22 @@
+package options
+
+import "github.com/spf13/pflag"
+
+type RootConfiguration struct {
+	ShowVersion bool // Show version information
+}
+
+func (cfg *RootConfiguration) AddFlags(flags *pflag.FlagSet) {
+	flags.BoolVarP(&cfg.ShowVersion, "version", "v", false,
+		"show version")
+	// flags.AddGoFlagSet(flag.CommandLine)
+}
+
+type ProjectConfiguration struct {
+	Name string // project name
+}
+
+func (cfg *ProjectConfiguration) AddFlags(flags *pflag.FlagSet) {
+	flags.StringVarP(&cfg.Name, "name", "", "",
+		"project name")
+}

+ 55 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/app/server.go

@@ -0,0 +1,55 @@
+package app
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/app/options"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/commands"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/log"
+)
+
+func NewProjectCommand(v *viper.Viper, rootcfg *options.RootConfiguration) *cobra.Command {
+	cfg := &options.ProjectConfiguration{}
+	cmd := &cobra.Command{
+		Use:     "project",
+		Short:   "Create a new pairec application ",
+		Aliases: []string{"pr"},
+		Run: func(cmd *cobra.Command, args []string) {
+			// rootcfg.ParseConfigFromViper(v)
+			if err := commands.Project(rootcfg, cfg); err != nil {
+				log.Error(err.Error())
+			}
+		},
+	}
+	cfg.AddFlags(cmd.Flags())
+	return cmd
+}
+
+func NewPairecCommand() *cobra.Command {
+	cfg := &options.RootConfiguration{}
+	rootcmd := &cobra.Command{
+		Use:              "pairecmd",
+		Long:             `pairecmd is a command line tool  for managing your Pairec Application`,
+		TraverseChildren: true,
+		Run: func(cmd *cobra.Command, args []string) {
+			if cfg.ShowVersion {
+				fmt.Println("pairecmd version 1.0.0")
+			} else {
+				cmd.Usage()
+			}
+		},
+	}
+	cfg.AddFlags(rootcmd.Flags())
+
+	v := viper.New()
+	rootcmd.AddCommand(NewProjectCommand(v, cfg))
+	/**
+	rootcmd.AddCommand(NewUpdateCommand(v, cfg))
+	rootcmd.AddCommand(NewListCommand(v, cfg))
+	rootcmd.AddCommand(NewListAllCommand(v, cfg))
+	**/
+
+	return rootcmd
+}

+ 119 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/commands/project.go

@@ -0,0 +1,119 @@
+package commands
+
+import (
+	"os"
+	"strings"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/app/options"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/log"
+)
+
+func Project(rootcfg *options.RootConfiguration, cfg *options.ProjectConfiguration) error {
+
+	// create project dir
+	if err := createDir(cfg.Name); err != nil {
+		return err
+	}
+
+	// create src dir
+	srcDir := cfg.Name + string(os.PathSeparator) + "src"
+	if err := createDir(srcDir); err != nil {
+		return err
+	}
+
+	// create src/controller dir
+	if err := createDir(cfg.Name + string(os.PathSeparator) + "src" + string(os.PathSeparator) + "controller"); err != nil {
+		return err
+	}
+
+	// create conf dir
+	if err := createDir(cfg.Name + string(os.PathSeparator) + "conf"); err != nil {
+		return err
+	}
+
+	// create docker dir
+	if err := createDir(cfg.Name + string(os.PathSeparator) + "docker"); err != nil {
+		return err
+	}
+
+	if err := createMakefile(cfg.Name); err != nil {
+		return err
+	}
+
+	if err := createGomodfile(cfg.Name); err != nil {
+		return err
+	}
+
+	if err := createMainfile(cfg.Name); err != nil {
+		return err
+	}
+
+	if err := createFile(cfg.Name+string(os.PathSeparator)+"conf"+string(os.PathSeparator)+"config.json.production", confS); err != nil {
+		return err
+	}
+
+	if err := createFile(cfg.Name+string(os.PathSeparator)+"docker"+string(os.PathSeparator)+"Dockerfile", dockerfileS); err != nil {
+		return err
+	}
+
+	if err := createFile(cfg.Name+string(os.PathSeparator)+"src"+string(os.PathSeparator)+"controller"+string(os.PathSeparator)+"feed.go", controllerfileS); err != nil {
+		return err
+	}
+
+	log.Info("create project " + cfg.Name + " finished.")
+
+	return nil
+}
+
+func createDir(dir string) error {
+	if _, err := os.Stat(dir); os.IsNotExist(err) {
+		if err := os.Mkdir(dir, 0755); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func createMakefile(projectName string) error {
+
+	file := projectName + string(os.PathSeparator) + "Makefile"
+	bin := strings.ReplaceAll(projectName, "-", "_")
+
+	content := strings.ReplaceAll(makefileS, "${BINNAME}", bin)
+
+	return createFile(file, content)
+
+}
+
+func createGomodfile(projectName string) error {
+
+	file := projectName + string(os.PathSeparator) + "go.mod"
+	bin := strings.ReplaceAll(projectName, "-", "_")
+
+	content := strings.ReplaceAll(gomodS, "${BINNAME}", bin)
+
+	return createFile(file, content)
+}
+
+func createMainfile(projectName string) error {
+
+	file := projectName + string(os.PathSeparator) + "src" + string(os.PathSeparator) + "main.go"
+	bin := strings.ReplaceAll(projectName, "-", "_")
+
+	content := strings.ReplaceAll(mainfileS, "${BINNAME}", bin)
+
+	return createFile(file, content)
+}
+
+func createFile(file, content string) error {
+	f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		return err
+	}
+
+	defer f.Close()
+	if _, err := f.WriteString(content); err != nil {
+		return err
+	}
+	return nil
+}

+ 297 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/commands/project_data.go

@@ -0,0 +1,297 @@
+package commands
+
+var makefileS = `BUILD=go build -mod vendor
+DOCKER?=docker
+SOURCE_DIR=src
+BIN_NAME=${BINNAME}
+REGISTRY?=registry.cn-beijing.cr.aliyuncs.com
+DOCKER_TAG?=0.0.1
+TEMP_DIR_SERVER:=$(shell mktemp -d)
+
+.PHONY: setup build clean
+setup:
+	go mod vendor
+build:
+	cd ${SOURCE_DIR}; CGO_ENABLED=0 GOOS=linux ${BUILD} -o ${BIN_NAME} .
+	cd ${SOURCE_DIR}; mv ${BIN_NAME} ../
+release:
+	cd ${SOURCE_DIR}; CGO_ENABLED=0 GOOS=linux ${BUILD} -o ${BIN_NAME} .
+	cd ${SOURCE_DIR}; mv ${BIN_NAME} ${TEMP_DIR_SERVER}/appd
+	cp docker/Dockerfile ${TEMP_DIR_SERVER}/
+	cp conf/config.json.production ${TEMP_DIR_SERVER}/config.json
+	cd ${TEMP_DIR_SERVER}  &&  ${DOCKER} build  -t ${REGISTRY}/${BIN_NAME}:${DOCKER_TAG} .
+	${DOCKER} push ${REGISTRY}/${BIN_NAME}:${DOCKER_TAG}
+
+clean:
+	-rm -rf ${BIN_NAME}
+`
+
+var gomodS = `module ${BINNAME} 
+
+go 1.13
+
+require (
+	gitlab.alibaba-inc.com/pai_biz_arch/pairec v1.2.0
+	gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210923051233-81df3e351556 
+)
+`
+
+var confS = `{
+	"RunMode": "product",
+	"ListenConf": {
+	  "HttpAddr": "",
+	  "HttpPort": 8000
+	},
+	"ABTestConf": {
+	  "Host": "",
+	  "Token": ""
+	},
+	"FilterConfs": [
+	],
+	"RecallConfs": [
+	],
+	"SortNames": {
+	  "default": [
+	  ]
+	},
+	"FilterNames": {
+	  "default": [
+		"UniqueFilter"
+	  ]
+	},
+	"AlgoConfs": [
+	],
+	"HologresConfs": {
+		"pairec-holo" :{
+			"DSN": "postgres://<AccessID>:<AccessKey>@<Endpoint>:<Port>/<database>?sslmode=disable&connect_timeout=1"
+		}
+	},
+	"KafkaConfs": {
+	},
+	"RedisConfs": {
+	},
+	"SceneConfs": {
+	},
+	"LogConf": {
+	  "RetensionDays": 3,
+	  "DiskSize": 20,
+	  "LogLevel": "INFO"
+	},
+	"RankConf": {
+	},
+	"FeatureConfs": {
+	}
+ }
+`
+
+var mainfileS = `package main
+
+import (
+	"${BINNAME}/src/controller"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec"
+)
+
+func main() {
+	pairec.AddStartHook(func() error {
+		return nil
+	})
+
+	pairec.Route("/api/rec/feed", &controller.FeedController{})
+	pairec.Run()
+}
+`
+
+var dockerfileS = `FROM centos
+LABEL pro="recommend"
+
+RUN mkdir -p /go/config && \
+    mkdir /go/log
+ADD appd /go/bin/
+ADD config.json /go/config/
+
+
+RUN echo -e '#!/bin/sh \n\n\
+/go/bin/appd --config=/go/config/config.json \
+--log_dir=/go/log --alsologtostderr \
+"$@"' > /usr/bin/rec_entrypoint.sh \
+&& chmod +x /usr/bin/rec_entrypoint.sh
+
+ENTRYPOINT ["/usr/bin/rec_entrypoint.sh"]
+`
+
+var controllerfileS = `package controller
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"time"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/abtest"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/service"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/web"
+)
+
+type RecommendParam struct {
+` + "    SceneId  string                 `json:\"scene_id\"`\n" +
+	"    Category string                 `json:\"category\"`\n" +
+	"    Uid      string                 `json:\"uid\"`  // user id \n" +
+	"    Size     int                    `json:\"size\"` // get recommend items size \n" +
+	"    Debug    bool                   `json:\"debug\"` \n" +
+	"    Features map[string]interface{} `json:\"features\"` \n" +
+	`}
+func (r *RecommendParam) GetParameter(name string) interface{} {
+	if name == "uid" {
+		return r.Uid
+	} else if name == "scene" {
+		return r.SceneId
+	} else if name == "category" {
+		if r.Category != "" {
+			return r.Category
+		}
+		return "default"
+	} else if name == "features" {
+		return r.Features
+	}
+
+	return nil
+}
+
+type RecommendResponse struct {
+	web.Response
+` +
+	"    Size  int         `json:\"size\"` \n" +
+	"    Items []*ItemData `json:\"items\"` \n" +
+	`}
+type ItemData struct {
+` +
+	"    ItemId     string `json:\"item_id\"` \n" +
+	"    ItemType   string `json:\"item_type\"` \n" +
+	"    RetrieveId string `json:\"retrieve_id\"` \n" +
+	`}
+
+func (r *RecommendResponse) ToString() string {
+	j, _ := json.Marshal(r)
+	return string(j)
+}
+
+type FeedController struct {
+	web.Controller
+	param   RecommendParam
+	context *context.RecommendContext
+}
+
+func (c *FeedController) Process(w http.ResponseWriter, r *http.Request) {
+	c.Start = time.Now()
+	var err error
+	c.RequestBody, err = ioutil.ReadAll(r.Body)
+	if err != nil {
+		c.SendError(w, web.ERROR_PARAMETER_CODE, "read parammeter error")
+		return
+	}
+	if len(c.RequestBody) == 0 {
+		c.SendError(w, web.ERROR_PARAMETER_CODE, "request body empty")
+		return
+	}
+	c.RequestId = utils.UUID()
+	c.LogRequestBegin(r)
+	if err := c.CheckParameter(); err != nil {
+		c.SendError(w, web.ERROR_PARAMETER_CODE, err.Error())
+		return
+	}
+	c.doProcess(w, r)
+	c.End = time.Now()
+	c.LogRequestEnd(r)
+}
+func (r *FeedController) CheckParameter() error {
+	if err := json.Unmarshal(r.RequestBody, &r.param); err != nil {
+		return err
+	}
+
+	if len(r.param.Uid) == 0 {
+		return errors.New("uid not empty")
+	}
+	if r.param.Size <= 0 {
+		r.param.Size = 10
+	}
+	if r.param.SceneId == "" {
+		r.param.SceneId = "default_scene"
+	}
+	if r.param.Category == "" {
+		r.param.Category = "default"
+	}
+
+	return nil
+}
+func (c *FeedController) doProcess(w http.ResponseWriter, r *http.Request) {
+	c.makeRecommendContext()
+	userRecommendService := service.NewUserRecommendService()
+	items := userRecommendService.Recommend(c.context)
+	data := make([]*ItemData, 0)
+	for _, item := range items {
+		if c.param.Debug {
+			fmt.Println(item)
+		}
+
+		idata := &ItemData{
+			ItemId:     string(item.Id),
+			ItemType:   item.ItemType,
+			RetrieveId: item.RetrieveId,
+		}
+
+		data = append(data, idata)
+	}
+
+	if len(data) < c.param.Size {
+		response := RecommendResponse{
+			Size:  len(data),
+			Items: data,
+			Response: web.Response{
+				RequestId: c.RequestId,
+				Code:      299,
+				Message:   "items size not enough",
+			},
+		}
+		io.WriteString(w, response.ToString())
+		return
+	}
+
+	response := RecommendResponse{
+		Size:  len(data),
+		Items: data,
+		Response: web.Response{
+			RequestId: c.RequestId,
+			Code:      200,
+			Message:   "success",
+		},
+	}
+	io.WriteString(w, response.ToString())
+}
+func (c *FeedController) makeRecommendContext() {
+	c.context = context.NewRecommendContext()
+	c.context.Size = c.param.Size
+	c.context.Debug = c.param.Debug
+	c.context.Param = &c.param
+	c.context.RecommendId = c.RequestId
+	c.context.Config = recconf.Config
+
+	abcontext := model.ExperimentContext{
+		Uid:          c.param.Uid,
+		RequestId:    c.RequestId,
+		FilterParams: map[string]interface{}{},
+	}
+
+	if abtest.GetExperimentClient() != nil {
+		c.context.ExperimentResult = abtest.GetExperimentClient().MatchExperiment(c.param.SceneId, &abcontext)
+		log.Info(c.context.ExperimentResult.Info())
+	}
+}
+`

+ 10 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/go.mod

@@ -0,0 +1,10 @@
+module gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd
+
+go 1.13
+
+require (
+	github.com/fatih/color v1.10.0
+	github.com/spf13/cobra v1.1.3
+	github.com/spf13/pflag v1.0.5
+	github.com/spf13/viper v1.7.1
+)

+ 309 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/go.sum

@@ -0,0 +1,309 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
+github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+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/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+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=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

+ 17 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/log/log.go

@@ -0,0 +1,17 @@
+package log
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/fatih/color"
+)
+
+func Error(message string) {
+	fmt.Printf("[%v] %v\n", color.RedString("FAILED"), message)
+	os.Exit(-1)
+}
+
+func Info(message string) {
+	fmt.Printf("[%v] %v\n", color.GreenString("SUCCESS"), message)
+}

+ 21 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/commands/main.go

@@ -0,0 +1,21 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"os"
+	"time"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairecmd/app"
+)
+
+func main() {
+	rand.Seed(time.Now().UTC().UnixNano())
+
+	command := app.NewPairecCommand()
+
+	if err := command.Execute(); err != nil {
+		fmt.Fprintf(os.Stderr, "%v\n", err)
+		os.Exit(1)
+	}
+}

+ 15 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/config/app.go

@@ -0,0 +1,15 @@
+package config
+
+import "sync"
+
+var AppConfig *AppConf
+
+func init() {
+	AppConfig = &AppConf{}
+}
+
+type AppConf struct {
+	WarmUpData bool
+	Mu         sync.Mutex
+	Once       sync.Once
+}

+ 26 - 3
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/context/recommend_context.go

@@ -1,26 +1,49 @@
 package context
 
 import (
+	"fmt"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang/model"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+	"strings"
 )
 
 type IParam interface {
 	GetParameter(name string) interface{}
 }
 type RecommendContext struct {
-	RecommendId      string
+	Debug            bool
 	Size             int
 	Param            IParam
 	Config           *recconf.RecommendConfig
-	Debug            bool
 	ExperimentResult *model.ExperimentResult
+	RecommendId      string
+	ExpId            string
+	Log              []string
 }
 
 func NewRecommendContext() *RecommendContext {
-	context := RecommendContext{Size: -1, Debug: false}
+	context := RecommendContext{Size: -1, Debug: false, Log: make([]string, 0, 16)}
 	return &context
 }
 func (r *RecommendContext) GetParameter(name string) interface{} {
 	return r.Param.GetParameter(name)
 }
+
+func (r *RecommendContext) LogDebug(msg string) {
+	if r.Debug {
+		r.Log = append(r.Log, fmt.Sprintf("[DEBUG] %s", strings.Replace(msg, "\t", "  ", -1)))
+	}
+}
+func (r *RecommendContext) LogInfo(msg string) {
+	r.Log = append(r.Log, fmt.Sprintf("[INFO] %s", strings.Replace(msg, "\t", "  ", -1)))
+	log.Info(fmt.Sprintf("req=%s\t%s", r.RecommendId, msg))
+}
+func (r *RecommendContext) LogWarning(msg string) {
+	r.Log = append(r.Log, fmt.Sprintf("[WARN] %s", strings.Replace(msg, "\t", "  ", -1)))
+	log.Warning(fmt.Sprintf("req=%s\t%s", r.RecommendId, msg))
+}
+func (r *RecommendContext) LogError(msg string) {
+	r.Log = append(r.Log, fmt.Sprintf("[ERROR] %s", strings.Replace(msg, "\t", "  ", -1)))
+	log.Error(fmt.Sprintf("req=%s\t%s", r.RecommendId, msg))
+}

+ 1 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/datahub/datahub.go

@@ -95,7 +95,7 @@ func (d *Datahub) loopListShards() error {
 	for {
 		ls, err := d.datahubApi.ListShard(d.projectName, d.topicName)
 		if err != nil {
-			log.Error("get shard list failed")
+			log.Error(fmt.Sprintf("error=get shard list failed(%v)", err))
 			time.Sleep(time.Second * 10)
 			continue
 		}

+ 23 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/hbase/hbase_test.go

@@ -0,0 +1,23 @@
+package hbase
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestHBase(t *testing.T) {
+	h := NewHBase("11.158.166.161", 100)
+
+	err := h.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	rsp, err := h.Insert("test", "key1", "t", "test", []byte("1"))
+	if err != nil {
+		t.Error(err)
+	}
+	fmt.Println(rsp)
+	rsp, err = h.Get("test", "key1", "t", "test")
+	fmt.Println(rsp)
+}

+ 21 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/kafka_test.go

@@ -0,0 +1,21 @@
+package datasource
+
+import (
+	"strconv"
+	"testing"
+)
+
+func TestProducer(t *testing.T) {
+	p := NewKafkaProducer("127.0.0.1:9092", "test")
+
+	err := p.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	for i := 0; i < 10000000; i++ {
+		p.SendMessage(strconv.Itoa(i))
+	}
+
+	defer p.Close()
+}

+ 176 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/bloomfilter/bloom_test.go

@@ -0,0 +1,176 @@
+package bloomfilter
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+	"github.com/spaolacci/murmur3"
+)
+
+var (
+	seeds = []uint32{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199}
+)
+
+func hash(data [][]byte, m uint, k uint) (ret [][]uint) {
+	locations := make([][]uint, 0, len(data))
+	for _, d := range data {
+		ret := make([]uint, 0, k)
+		for i := uint(0); i < k; i++ {
+			mmh3 := murmur3.New32WithSeed(seeds[i])
+			mmh3.Write(d)
+			ret = append(ret, uint(mmh3.Sum32())%m)
+		}
+		locations = append(locations, ret)
+	}
+	return locations
+}
+func TestBitSet(t *testing.T) {
+	pool := &redis.Pool{
+		MaxIdle:     30,
+		IdleTimeout: 240 * time.Second,
+		Dial:        func() (redis.Conn, error) { return redis.Dial("tcp", "127.0.0.1:6379") },
+	}
+	m, k := EstimateParameters(1000000, 0.05)
+	fmt.Printf("m:%d, k:%d\n", m, k)
+	redisBitSet := NewRedisBitSet(pool)
+	redisBitSet.SetBatchCount(5000)
+
+	bloom := New(m, k)
+	bloom.AddBitSetProvider("default", redisBitSet)
+
+	bloom.SetHashFunc(hash)
+
+	count := 3000
+	base := 10000000
+	testStrings := [][]byte{}
+	for i := base; i < base+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+	err := bloom.Add("mykey", testStrings)
+	if err != nil {
+		t.Error(err)
+	}
+
+	start := time.Now().UnixNano()
+	result, err := bloom.Exists("mykey", testStrings)
+	fmt.Println(result, err)
+
+	testStrings = testStrings[:0]
+	fmt.Println(count)
+	for i := base * 2; i < base*2+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+
+	start1 := time.Now().UnixNano()
+	result, err = bloom.Exists("mykey", testStrings)
+	fmt.Println("time1", (time.Now().UnixNano()-start1)/1e6)
+	fmt.Println(result, err)
+	fmt.Println("time", (time.Now().UnixNano()-start)/1e6)
+}
+func redisPool(db int) *redis.Pool {
+	pool := &redis.Pool{
+		MaxIdle:     30,
+		IdleTimeout: 240 * time.Second,
+		Dial: func() (redis.Conn, error) {
+			conn, err := redis.Dial("tcp", "127.0.0.1:6379")
+			if err != nil {
+				return conn, err
+			}
+
+			_, err = conn.Do("SELECT", db)
+			return conn, err
+		},
+	}
+
+	return pool
+}
+func TestRotationDB(t *testing.T) {
+	redis1 := redisPool(1)
+	redis2 := redisPool(2)
+	m, k := EstimateParameters(1000000, 0.05)
+	fmt.Printf("m:%d, k:%d\n", m, k)
+	redisBitSet1 := NewRedisBitSet(redis1)
+	redisBitSet1.SetBatchCount(5000)
+
+	redisBitSet2 := NewRedisBitSet(redis2)
+	redisBitSet2.SetBatchCount(5000)
+
+	bloom := New(m, k)
+	bloom.AddBitSetProvider("db1", redisBitSet1)
+	bloom.AddBitSetProvider("db2", redisBitSet2)
+
+	bloom.SetHashFunc(hash)
+	bloom.SetBloomMetaStore(&ReidsBloomMetaStore{pool: redisPool(0)})
+
+	bloom.StartRotation("db1", []string{"db1", "db2"}, 80, false)
+	count := 3000
+	base := 10000000
+	testStrings := [][]byte{}
+	for i := base; i < base+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+	err := bloom.Add("mykey", testStrings)
+	if err != nil {
+		t.Error(err)
+	}
+
+	for {
+		time.Sleep(time.Second * 30)
+		result, err := bloom.Exists("mykey", testStrings)
+		fmt.Println(result, err)
+	}
+}
+
+func redisReset(conn redis.Conn) {
+	conn.Do("FLUSHDB")
+	for i := 0; i < 200; i++ {
+		args := []interface{}{}
+		keyName := "user_suffix_" + strconv.Itoa(i)
+		fmt.Println(keyName)
+		args = append(args, keyName, 0.05, 1250000)
+		conn.Do("bf.reserve", args...)
+	}
+}
+func TestRedistBloomRotationDB(t *testing.T) {
+	redis1 := redisPool(1)
+	redis2 := redisPool(2)
+	redis3 := redisPool(3)
+	m, k := EstimateParameters(1000000, 0.05)
+	fmt.Printf("m:%d, k:%d\n", m, k)
+	redisBitSet1 := NewRedisBitSet(redis1)
+	redisBitSet1.SetResetFunc(redisReset)
+
+	redisBitSet2 := NewRedisBitSet(redis2)
+	redisBitSet2.SetResetFunc(redisReset)
+
+	redisBitSet3 := NewRedisBitSet(redis3)
+	redisBitSet3.SetResetFunc(redisReset)
+
+	bloom := NewRedisBloom()
+	bloom.AddBitSetProvider("db1", redisBitSet1)
+	bloom.AddBitSetProvider("db2", redisBitSet2)
+	bloom.AddBitSetProvider("db3", redisBitSet3)
+
+	bloom.SetBloomMetaStore(&ReidsBloomMetaStore{pool: redisPool(0)})
+
+	bloom.StartRotation("db1", []string{"db1", "db2", "db3"}, 80, false)
+	count := 3000
+	base := 10000000
+	testStrings := [][]byte{}
+	for i := base; i < base+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+	err := bloom.Add("mykey", testStrings)
+	if err != nil {
+		t.Error(err)
+	}
+
+	for {
+		time.Sleep(time.Second * 30)
+		result, err := bloom.Exists("mykey", testStrings)
+		fmt.Println(result, err)
+	}
+}

+ 52 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/bloomfilter/redis_bloom_test.go

@@ -0,0 +1,52 @@
+package bloomfilter
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+)
+
+func TestRedisBloom(t *testing.T) {
+	pool := &redis.Pool{
+		MaxIdle:     30,
+		IdleTimeout: 240 * time.Second,
+		Dial:        func() (redis.Conn, error) { return redis.Dial("tcp", "127.0.0.1:6379") },
+	}
+	m, k := EstimateParameters(1000000, 0.05)
+	fmt.Printf("m:%d, k:%d\n", m, k)
+	redisBitSet := NewRedisBitSet(pool)
+	// redisBitSet.SetBatchCount(2000)
+
+	bloom := NewRedisBloom()
+	bloom.AddBitSetProvider("default", redisBitSet)
+
+	count := 3000
+	base := 10000000
+	testStrings := [][]byte{}
+	for i := base; i < base+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+	err := bloom.Add("mykey1", testStrings)
+	if err != nil {
+		t.Error(err)
+	}
+
+	start := time.Now().UnixNano()
+	result, err := bloom.Exists("mykey1", testStrings)
+	fmt.Println(result, err)
+
+	testStrings = testStrings[:0]
+	fmt.Println(count)
+	for i := base * 2; i < base*2+count; i++ {
+		testStrings = append(testStrings, []byte(strconv.Itoa(i)))
+	}
+
+	start1 := time.Now().UnixNano()
+	result, err = bloom.Exists("mykey1", testStrings)
+	fmt.Println("time1", (time.Now().UnixNano()-start1)/1e6)
+	fmt.Println(result, err)
+	fmt.Println("time", (time.Now().UnixNano()-start)/1e6)
+}

+ 1 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/filter.go

@@ -58,7 +58,7 @@ func (fs *FilterService) Filter(filterData *FilterData, tag string) {
 
 	var filters []IFilter
 	if context.ExperimentResult != nil {
-		names := context.ExperimentResult.GetLayerParams("recall").Get("filterNames", nil)
+		names := context.ExperimentResult.GetExperimentParams().Get("filterNames", nil)
 		if names != nil {
 			if values, ok := names.([]interface{}); ok {
 				for _, v := range values {

+ 1 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/filter/priority_adjust_count_filter.go

@@ -33,7 +33,7 @@ func NewPriorityAdjustCountFilter(config recconf.FilterConfig) *PriorityAdjustCo
 func (f *PriorityAdjustCountFilter) Filter(filterData *FilterData) error {
 	context := filterData.Context
 	if context.ExperimentResult != nil {
-		rankconf := context.ExperimentResult.GetLayerParams("general_rank").Get("generalRankConf", "")
+		rankconf := context.ExperimentResult.GetExperimentParams().Get("generalRankConf", "")
 		if rankconf != "" {
 			return nil
 		}

+ 1 - 1
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/go.mod

@@ -24,7 +24,7 @@ require (
 	github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
 	github.com/spaolacci/murmur3 v1.1.0
 	github.com/tsuna/gohbase v0.0.0-20200414231402-ae5d5a2cd032
-	gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210807034701-52a5c464d8cd
+	gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210923051233-81df3e351556
 	gonum.org/v1/gonum v0.8.2
 	google.golang.org/grpc v1.31.0
 	google.golang.org/protobuf v1.25.0

+ 2 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/go.sum

@@ -265,6 +265,8 @@ gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210
 gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210807031734-6dbaf6493640/go.mod h1:gK4y9pFsUSAkeSgJK56xLBXXuaORbUkBaOTSPQeWEDc=
 gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210807034701-52a5c464d8cd h1:74PVA8uyp+cT/gt0BYig4rlJP3lAZZPQX7S+qcPqREc=
 gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210807034701-52a5c464d8cd/go.mod h1:gK4y9pFsUSAkeSgJK56xLBXXuaORbUkBaOTSPQeWEDc=
+gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210923051233-81df3e351556 h1:JdK2iAo3aPh0oQP8qPZpIj6Jj1nx/9odL1mqPpwG1/Y=
+gitlab.alibaba-inc.com/pai_biz_arch/pairec-experiment/client_golang v0.0.0-20210923051233-81df3e351556/go.mod h1:gK4y9pFsUSAkeSgJK56xLBXXuaORbUkBaOTSPQeWEDc=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=

+ 38 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/main/main.go

@@ -0,0 +1,38 @@
+package main
+
+import "C"
+import (
+	"bytes"
+	"fmt"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec"
+	"io/ioutil"
+	"net/http/httptest"
+	"os"
+)
+
+//export CommandRun
+func CommandRun(configFile *C.char) bool {
+	file := C.GoString(configFile)
+	os.Setenv("CONFIG_PATH", file)
+	os.Setenv("RUN_MODE", "COMMAND")
+	pairec.Run()
+	return true
+}
+
+//export Recommend
+func Recommend(requestBody *C.char) *C.char {
+	body := C.GoString(requestBody)
+	readBuf := bytes.NewBufferString(body)
+	req := httptest.NewRequest("POST", "/api/recall", readBuf)
+	w := httptest.NewRecorder()
+	pairec.PairecApp.Handlers.ServeHTTP(w, req)
+	resp := w.Result()
+	defer resp.Body.Close()
+	responseBody, _ := ioutil.ReadAll(resp.Body)
+	fmt.Println(resp.StatusCode)
+	fmt.Println(string(responseBody))
+
+	return C.CString(string(responseBody))
+}
+func main() {
+}

+ 38 - 2
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_dao.go

@@ -1,13 +1,17 @@
 package module
 
 import (
+	"strconv"
+	"strings"
+
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
 )
 
 const (
-	Feature_Store_User = "user"
-	Feature_Store_Item = "item"
+	Feature_Store_User    = "user"
+	Feature_Store_Item    = "item"
+	Feature_Type_Sequence = "sequence_feature"
 )
 
 // FeatureDao is interface, it define FeatureFetch to featch feature from implement
@@ -24,6 +28,8 @@ func NewFeatureDao(config recconf.FeatureDaoConfig) FeatureDao {
 		return NewFeatureHologresDao(config)
 	} else if config.AdapterType == recconf.DaoConf_Adapter_TableStore {
 		return NewFeatureTablestoreDao(config)
+	} else if config.AdapterType == recconf.DaoConf_Adapter_Mysql {
+		return NewFeatureMysqlDao(config)
 	}
 
 	panic("not found FeatureDao implement")
@@ -32,13 +38,43 @@ func NewFeatureDao(config recconf.FeatureDaoConfig) FeatureDao {
 type FeatureBaseDao struct {
 	featureKey   string // use the value of key to featch data
 	featureStore string // user or item
+	featureType  string
+
+	// sequence feature has under attribute
+	sequenceLength      int
+	sequenceName        string
+	sequenceEvent       string
+	sequenceDelim       string
+	sequenceDimFields   []string
+	sequencePlayTimeMap map[string]float64
 }
 
 func NewFeatureBaseDao(config *recconf.FeatureDaoConfig) *FeatureBaseDao {
 	dao := FeatureBaseDao{
 		featureKey:   config.FeatureKey,
 		featureStore: config.FeatureStore,
+		featureType:  config.FeatureType,
+
+		sequenceLength:      config.SequenceLength,
+		sequenceName:        config.SequenceName,
+		sequenceEvent:       config.SequenceEvent,
+		sequenceDelim:       config.SequenceDelim,
+		sequencePlayTimeMap: make(map[string]float64, 0),
 	}
 
+	if config.SequencePlayTime != "" {
+		playTimes := strings.Split(config.SequencePlayTime, ";")
+		for _, eventTime := range playTimes {
+			strs := strings.Split(eventTime, ":")
+			if len(strs) == 2 {
+				if t, err := strconv.ParseFloat(strs[1], 64); err == nil {
+					dao.sequencePlayTimeMap[strs[0]] = t
+				}
+			}
+		}
+	}
+	if config.SequenceDimFields != "" {
+		dao.sequenceDimFields = strings.Split(config.SequenceDimFields, ",")
+	}
 	return &dao
 }

+ 252 - 17
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_hologres_dao.go

@@ -6,6 +6,7 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"runtime/debug"
 	"strconv"
 	"strings"
 	"sync"
@@ -22,26 +23,32 @@ import (
 
 type FeatureHologresDao struct {
 	*FeatureBaseDao
-	db                 *sql.DB
-	table              string
-	userFeatureKeyName string
-	itemFeatureKeyName string
-	userSelectFields   string
-	itemSelectFields   string
-	mu                 sync.RWMutex
-	userStmt           *sql.Stmt
-	itemStmtMap        map[int]*sql.Stmt
+	db                   *sql.DB
+	table                string
+	userFeatureKeyName   string
+	itemFeatureKeyName   string
+	userSelectFields     string
+	itemSelectFields     string
+	sequenceOfflineTable string
+	mu                   sync.RWMutex
+	userStmt             *sql.Stmt
+	itemStmtMap          map[int]*sql.Stmt
+	userSequenceStmtMap  map[string]*sql.Stmt
+	onlineSequenceStmt   *sql.Stmt
+	offlineSequenceStmt  *sql.Stmt
 }
 
 func NewFeatureHologresDao(config recconf.FeatureDaoConfig) *FeatureHologresDao {
 	dao := &FeatureHologresDao{
-		FeatureBaseDao:     NewFeatureBaseDao(&config),
-		table:              config.HologresTableName,
-		userFeatureKeyName: config.UserFeatureKeyName,
-		itemFeatureKeyName: config.ItemFeatureKeyName,
-		userSelectFields:   config.UserSelectFields,
-		itemSelectFields:   config.ItemSelectFields,
-		itemStmtMap:        make(map[int]*sql.Stmt),
+		FeatureBaseDao:       NewFeatureBaseDao(&config),
+		table:                config.HologresTableName,
+		userFeatureKeyName:   config.UserFeatureKeyName,
+		itemFeatureKeyName:   config.ItemFeatureKeyName,
+		userSelectFields:     config.UserSelectFields,
+		itemSelectFields:     config.ItemSelectFields,
+		sequenceOfflineTable: config.SequenceOfflineTableName,
+		itemStmtMap:          make(map[int]*sql.Stmt),
+		userSequenceStmtMap:  make(map[string]*sql.Stmt),
 	}
 	hologres, err := holo.GetPostgres(config.HologresName)
 	if err != nil {
@@ -56,8 +63,15 @@ func (d *FeatureHologresDao) getItemStmt(key int) *sql.Stmt {
 	defer d.mu.RUnlock()
 	return d.itemStmtMap[key]
 }
+func (d *FeatureHologresDao) getUserSequenceStmt(key string) *sql.Stmt {
+	d.mu.RLock()
+	defer d.mu.RUnlock()
+	return d.userSequenceStmtMap[key]
+}
 func (d *FeatureHologresDao) FeatureFetch(user *User, items []*Item, context *context.RecommendContext) {
-	if d.featureStore == Feature_Store_User {
+	if d.featureStore == Feature_Store_User && d.featureType == Feature_Type_Sequence {
+		d.userSequenceFeatureFetch(user, context)
+	} else if d.featureStore == Feature_Store_User {
 		d.userFeatureFetch(user, context)
 	} else {
 		d.itemsFeatureFetch(items, context)
@@ -161,6 +175,227 @@ func (d *FeatureHologresDao) userFeatureFetch(user *User, context *context.Recom
 	}
 }
 
+type sequenceInfo struct {
+	itemId          string
+	event           string
+	playTime        float64
+	timestamp       int64
+	dimensionFields []sql.NullString
+}
+
+func (d *FeatureHologresDao) userSequenceFeatureFetch(user *User, context *context.RecommendContext) {
+	defer func() {
+		if err := recover(); err != nil {
+			stack := string(debug.Stack())
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=%v\tstack=%v", context.RecommendId, err, strings.ReplaceAll(stack, "\n", "\t")))
+			return
+		}
+	}()
+
+	comms := strings.Split(d.featureKey, ":")
+	if len(comms) < 2 {
+		log.Error(fmt.Sprintf("requestId=%s\tuid=%s\terror=featureKey error(%s)", context.RecommendId, user.Id, d.featureKey))
+		return
+	}
+
+	key := user.StringProperty(comms[1])
+	if key == "" {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=property not found(%s)", context.RecommendId, comms[1]))
+		return
+	}
+
+	currTime := time.Now().Unix()
+	var onlineSequences []*sequenceInfo
+	selectFields := []string{"item_id", "event", "play_time", "timestamp"}
+	if len(d.sequenceDimFields) > 0 {
+		selectFields = append(selectFields, d.sequenceDimFields...)
+	}
+
+	onlineFunc := func() {
+		builder := sqlbuilder.PostgreSQL.NewSelectBuilder()
+		builder.Select(selectFields...)
+		builder.From(d.table)
+		where := []string{builder.Equal(d.userFeatureKeyName, key), builder.GreaterThan("timestamp", currTime-86400*5)}
+		if d.sequenceEvent != "" {
+			where = append(where, builder.Equal("event", d.sequenceEvent))
+		}
+		builder.Where(where...).Limit(d.sequenceLength)
+		builder.OrderBy("timestamp").Desc()
+
+		sqlquery, args := builder.Build()
+		if d.onlineSequenceStmt == nil {
+			d.mu.Lock()
+			if d.onlineSequenceStmt == nil {
+				stmt, err := d.db.Prepare(sqlquery)
+				if err != nil {
+					log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+					d.mu.Unlock()
+					return
+				}
+				d.onlineSequenceStmt = stmt
+				d.mu.Unlock()
+			} else {
+				d.mu.Unlock()
+			}
+		}
+		ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 100*time.Millisecond)
+		defer cancel()
+		rows, err := d.onlineSequenceStmt.QueryContext(ctx, args...)
+		if err != nil {
+			if errors.Is(err, gocontext.DeadlineExceeded) {
+				log.Warning("module=FeatureHologresDao\tevent=userSequenceFeatureFetch\ttimeout=100")
+				return
+			}
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+			return
+		}
+
+		defer rows.Close()
+		for rows.Next() {
+			seq := new(sequenceInfo)
+			dst := []interface{}{&seq.itemId, &seq.event, &seq.playTime, &seq.timestamp}
+			if len(d.sequenceDimFields) > 0 {
+				seq.dimensionFields = make([]sql.NullString, len(d.sequenceDimFields))
+				for i := range seq.dimensionFields {
+					dst = append(dst, &seq.dimensionFields[i])
+				}
+			}
+			if err := rows.Scan(dst...); err == nil {
+				if t, exist := d.sequencePlayTimeMap[seq.event]; exist {
+					if seq.playTime <= t {
+						continue
+					}
+				}
+				onlineSequences = append(onlineSequences, seq)
+			} else {
+				log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+			}
+		}
+
+	}
+
+	var offlineSequences []*sequenceInfo
+	offlineFunc := func() {
+		builder := sqlbuilder.PostgreSQL.NewSelectBuilder()
+		builder.Select(selectFields...)
+		builder.From(d.sequenceOfflineTable)
+		where := []string{builder.Equal(d.userFeatureKeyName, key)}
+		if d.sequenceEvent != "" {
+			where = append(where, builder.Equal("event", d.sequenceEvent))
+		}
+		builder.Where(where...).Limit(d.sequenceLength)
+		builder.OrderBy("timestamp").Desc()
+
+		sqlquery, args := builder.Build()
+		if d.offlineSequenceStmt == nil {
+			d.mu.Lock()
+			if d.offlineSequenceStmt == nil {
+				stmt, err := d.db.Prepare(sqlquery)
+				if err != nil {
+					log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+					d.mu.Unlock()
+					return
+				}
+				d.offlineSequenceStmt = stmt
+				d.mu.Unlock()
+			} else {
+				d.mu.Unlock()
+			}
+		}
+		ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 100*time.Millisecond)
+		defer cancel()
+		rows, err := d.offlineSequenceStmt.QueryContext(ctx, args...)
+		if err != nil {
+			if errors.Is(err, gocontext.DeadlineExceeded) {
+				log.Warning("module=FeatureHologresDao\tevent=userSequenceFeatureFetch\ttimeout=100")
+				return
+			}
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+			return
+		}
+
+		defer rows.Close()
+		for rows.Next() {
+			seq := new(sequenceInfo)
+			dst := []interface{}{&seq.itemId, &seq.event, &seq.playTime, &seq.timestamp}
+			if len(d.sequenceDimFields) > 0 {
+				seq.dimensionFields = make([]sql.NullString, len(d.sequenceDimFields))
+				for i := range seq.dimensionFields {
+					dst = append(dst, &seq.dimensionFields[i])
+				}
+			}
+			if err := rows.Scan(dst...); err == nil {
+				if t, exist := d.sequencePlayTimeMap[seq.event]; exist {
+					if seq.playTime <= t {
+						continue
+					}
+				}
+				offlineSequences = append(offlineSequences, seq)
+			} else {
+				log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+			}
+		}
+
+	}
+
+	var wg sync.WaitGroup
+
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		onlineFunc()
+	}()
+	if d.sequenceOfflineTable != "" {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			offlineFunc()
+		}()
+	}
+	wg.Wait()
+
+	if len(offlineSequences) > 0 {
+		index := 0
+		for index < len(onlineSequences) {
+			if onlineSequences[index].timestamp < offlineSequences[0].timestamp {
+				break
+			}
+			index++
+		}
+
+		onlineSequences = onlineSequences[:index]
+		onlineSequences = append(onlineSequences, offlineSequences...)
+		if len(onlineSequences) > d.sequenceLength {
+			onlineSequences = onlineSequences[:d.sequenceLength]
+		}
+	}
+
+	var sequences []string
+	sequenceMap := make(map[string]bool, 0)
+
+	for _, seq := range onlineSequences {
+		key := fmt.Sprintf("%s#%s", seq.itemId, seq.event)
+		if _, exist := sequenceMap[key]; !exist {
+			sequenceMap[key] = true
+			seqStr := fmt.Sprintf("%s#%d#%s#%.2f#%d", seq.itemId, seq.timestamp, seq.event, seq.playTime, currTime-seq.timestamp)
+			for _, field := range seq.dimensionFields {
+				if field.Valid {
+					seqStr += "#" + field.String
+				} else {
+					seqStr += "#"
+				}
+			}
+			sequences = append(sequences, seqStr)
+		}
+	}
+
+	delim := d.sequenceDelim
+	if delim == "" {
+		delim = ";"
+	}
+	user.AddProperty(d.sequenceName, strings.Join(sequences, delim))
+}
+
 func (d *FeatureHologresDao) itemsFeatureFetch(items []*Item, context *context.RecommendContext) {
 	defer func() {
 		if err := recover(); err != nil {

+ 360 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_mysql_dao.go

@@ -0,0 +1,360 @@
+package module
+
+import (
+	gocontext "context"
+	"database/sql"
+	"errors"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils/sqlutil"
+
+	"github.com/huandu/go-sqlbuilder"
+)
+
+type FeatureMysqlDao struct {
+	*FeatureBaseDao
+
+	db                 *sql.DB
+	table              string
+	userFeatureKeyName string
+	itemFeatureKeyName string
+	userSelectFields   string
+	itemSelectFields   string
+
+	mu          sync.RWMutex
+	userStmt    *sql.Stmt
+	itemStmtMap map[int]*sql.Stmt
+}
+
+func NewFeatureMysqlDao(config recconf.FeatureDaoConfig) *FeatureMysqlDao {
+	dao := &FeatureMysqlDao{
+		FeatureBaseDao:     NewFeatureBaseDao(&config),
+		table:              config.MysqlTable,
+		userFeatureKeyName: config.UserFeatureKeyName,
+		itemFeatureKeyName: config.ItemFeatureKeyName,
+		userSelectFields:   config.UserSelectFields,
+		itemSelectFields:   config.ItemSelectFields,
+		itemStmtMap:        make(map[int]*sql.Stmt),
+	}
+	mysql, err := mysqldb.GetMysql(config.MysqlName)
+	if err != nil {
+		log.Error(fmt.Sprintf("error=%v", err))
+		return nil
+	}
+	dao.db = mysql.DB
+	return dao
+}
+
+func (d *FeatureMysqlDao) FeatureFetch(user *User, items []*Item, context *context.RecommendContext) {
+	if d.featureStore == Feature_Store_User {
+		d.userFeatureFetch(user, context)
+	} else {
+		d.itemsFeatureFetch(items, context)
+	}
+}
+
+func (d *FeatureMysqlDao) userFeatureFetch(user *User, context *context.RecommendContext) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=%v", context.RecommendId, err))
+			return
+		}
+	}()
+
+	comms := strings.Split(d.featureKey, ":")
+	if len(comms) < 2 {
+		log.Error(fmt.Sprintf("requestId=%s\tuid=%s\terror=featureKey error(%s)", context.RecommendId, user.Id, d.featureKey))
+		return
+	}
+
+	key := user.StringProperty(comms[1])
+	if key == "" {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=property not found(%s)", context.RecommendId, comms[1]))
+		return
+	}
+
+	builder := sqlbuilder.MySQL.NewSelectBuilder()
+	builder.Select(d.userSelectFields)
+	builder.From(d.table)
+	builder.Where(builder.Equal(d.userFeatureKeyName, key))
+
+	sqlquery, args := builder.Build()
+	if d.userStmt == nil {
+		d.mu.Lock()
+		if d.userStmt == nil {
+			stmt, err := d.db.Prepare(sqlquery)
+			if err != nil {
+				log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+				d.mu.Unlock()
+				return
+			}
+			d.userStmt = stmt
+			d.mu.Unlock()
+		} else {
+			d.mu.Unlock()
+		}
+	}
+
+	ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 100*time.Millisecond)
+	defer cancel()
+	rows, err := d.userStmt.QueryContext(ctx, args...)
+	if err != nil {
+		if errors.Is(err, gocontext.DeadlineExceeded) {
+			log.Warning("module=FeatureMysqlDao\tevent=userFeatureFetch\ttimeout=100")
+			return
+		}
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+		return
+	}
+
+	defer rows.Close()
+	columns, err := rows.ColumnTypes()
+	if err != nil {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+		return
+	}
+	values := sqlutil.ColumnValues(columns)
+
+	for rows.Next() {
+		if err := rows.Scan(values...); err == nil {
+			for i, column := range columns {
+				name := column.Name()
+				if name == d.userFeatureKeyName {
+					continue
+				}
+
+				val := values[i]
+				switch v := val.(type) {
+				case *sql.NullString:
+					if v.Valid {
+						user.AddProperty(name, v.String)
+					}
+				case *sql.NullInt32:
+					if v.Valid {
+						user.AddProperty(name, v.Int32)
+					}
+				case *sql.NullInt64:
+					if v.Valid {
+						user.AddProperty(name, v.Int64)
+					}
+				case *sql.NullFloat64:
+					if v.Valid {
+						user.AddProperty(name, v.Float64)
+					}
+				default:
+				}
+			}
+		} else {
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+		}
+	}
+}
+
+func (d *FeatureMysqlDao) itemsFeatureFetch(items []*Item, context *context.RecommendContext) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=%v", context.RecommendId, err))
+			return
+		}
+	}()
+
+	fk := d.featureKey
+	if fk != "item:id" {
+		comms := strings.Split(d.featureKey, ":")
+		if len(comms) < 2 {
+			log.Error(fmt.Sprintf("requestId=%s\tevent=itemsFeatureFetch\terror=featureKey error(%s)", context.RecommendId, d.featureKey))
+			return
+		}
+
+		fk = comms[1]
+	}
+
+	cpuCount := utils.MaxInt(int(math.Ceil(float64(len(items))/float64(1000))), 1)
+	requestCh := make(chan []*Item, cpuCount)
+	defer close(requestCh)
+
+	if cpuCount == 1 {
+		requestCh <- items
+	} else {
+		maps := make(map[int][]*Item)
+		for i, item := range items {
+			maps[i%cpuCount] = append(maps[i%cpuCount], item)
+		}
+
+		for _, itemlist := range maps {
+			requestCh <- itemlist
+		}
+
+	}
+
+	var wg sync.WaitGroup
+	for i := 0; i < cpuCount; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			select {
+			case itemlist := <-requestCh:
+				var keys []interface{}
+				key2Item := make(map[string]*Item, len(itemlist))
+				for _, item := range itemlist {
+					var key string
+					if fk == "item:id" {
+						key = string(item.Id)
+					} else {
+						key = item.StringProperty(fk)
+					}
+					keys = append(keys, key)
+					key2Item[key] = item
+				}
+
+				builder := sqlbuilder.MySQL.NewSelectBuilder()
+				builder.Select(d.itemSelectFields)
+				builder.From(d.table)
+				builder.Where(builder.In(d.itemFeatureKeyName, keys...))
+
+				sqlquery, args := builder.Build()
+				stmtkey := len(keys)
+				stmt := d.getItemStmt(stmtkey)
+				if stmt == nil {
+					d.mu.Lock()
+					stmt = d.itemStmtMap[stmtkey]
+					if stmt == nil {
+						stmt2, err := d.db.Prepare(sqlquery)
+						if err != nil {
+							log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+							d.mu.Unlock()
+							return
+						}
+						d.itemStmtMap[stmtkey] = stmt2
+						stmt = stmt2
+						d.mu.Unlock()
+					} else {
+						d.mu.Unlock()
+					}
+				}
+
+				rowsChannel := make(chan *sql.Rows, 1)
+				ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 100*time.Millisecond)
+				defer cancel()
+				// async invoke sql query
+				go func() {
+					rows, err := stmt.Query(args...)
+					if err != nil {
+						rowsChannel <- nil
+						log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+						return
+					}
+
+					// check query is timeout
+					select {
+					case <-ctx.Done():
+						if rows != nil {
+							rows.Close()
+						}
+						log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=%v", context.RecommendId, ctx.Err()))
+						return
+					default:
+					}
+					rowsChannel <- rows
+					return
+				}()
+
+				var rows *sql.Rows
+				select {
+				case <-ctx.Done():
+					log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, ctx.Err()))
+					return
+				case rows = <-rowsChannel:
+					if rows == nil {
+						return
+					}
+				}
+
+				defer rows.Close()
+				columns, err := rows.ColumnTypes()
+				if err != nil {
+					log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+					return
+				}
+
+				values := sqlutil.ColumnValues(columns)
+				for rows.Next() {
+					if err := rows.Scan(values...); err == nil {
+						var item *Item
+						properties := make(map[string]interface{}, len(values))
+						for i, column := range columns {
+							name := column.Name()
+							val := values[i]
+							if i == 0 {
+								var key string
+								switch v := val.(type) {
+								case *sql.NullString:
+									if v.Valid {
+										key = v.String
+									}
+								case *sql.NullInt32:
+									if v.Valid {
+										key = strconv.Itoa(int(v.Int32))
+									}
+								case *sql.NullInt64:
+									if v.Valid {
+										key = strconv.Itoa(int(v.Int64))
+									}
+								}
+								if key == "" {
+									break
+								}
+								item = key2Item[key]
+								continue
+							}
+
+							switch v := val.(type) {
+							case *sql.NullString:
+								if v.Valid {
+									properties[name] = v.String
+								}
+							case *sql.NullInt32:
+								if v.Valid {
+									properties[name] = v.Int32
+								}
+							case *sql.NullInt64:
+								if v.Valid {
+									properties[name] = v.Int64
+								}
+							case *sql.NullFloat64:
+								if v.Valid {
+									properties[name] = v.Float64
+								}
+							default:
+							}
+						}
+						if nil != item && len(properties) > 0 {
+							item.AddProperties(properties)
+						}
+
+					} else {
+						log.Error(fmt.Sprintf("requestId=%s\tmodule=FeatureMysqlDao\terror=mysql error(%v)", context.RecommendId, err))
+					}
+				}
+			default:
+			}
+		}()
+	}
+	wg.Wait()
+}
+
+func (d *FeatureMysqlDao) getItemStmt(key int) *sql.Stmt {
+	d.mu.RLock()
+	defer d.mu.RUnlock()
+	return d.itemStmtMap[key]
+}

+ 10 - 17
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/feature_tablestore_dao.go

@@ -3,7 +3,6 @@ package module
 import (
 	"fmt"
 	"math"
-	"strconv"
 	"strings"
 	"sync"
 
@@ -87,14 +86,11 @@ func (d *FeatureTablestoreDao) userFeatureFetch(user *User, context *context.Rec
 		name := column.ColumnName
 		switch val := column.Value.(type) {
 		case string:
-			if val != "" {
-				f, err := strconv.ParseFloat(val, 64)
-				if err == nil {
-					user.AddProperty(name, f)
-				} else {
-					user.AddProperty(name, val)
-				}
-			}
+			user.AddProperty(name, val)
+		case int:
+			user.AddProperty(name, val)
+		case float64:
+			user.AddProperty(name, val)
 		default:
 			user.AddProperty(name, val)
 		}
@@ -189,14 +185,11 @@ func (d *FeatureTablestoreDao) itemsFeatureFetch(items []*Item, context *context
 						name := column.ColumnName
 						switch val := column.Value.(type) {
 						case string:
-							if val != "" {
-								f, err := strconv.ParseFloat(val, 64)
-								if err == nil {
-									properties[name] = f
-								} else {
-									properties[name] = val
-								}
-							}
+							properties[name] = val
+						case int:
+							properties[name] = val
+						case float64:
+							properties[name] = val
 						default:
 							properties[name] = val
 						}

+ 172 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/filter_op.go

@@ -180,6 +180,14 @@ func NewFitlerParamWithConfig(configs []recconf.FilterParamConfig) *FilterParam
 			p.operators = append(p.operators, NewNotEqualFilterOp(config))
 		} else if config.Operator == "in" {
 			p.operators = append(p.operators, NewInFilterOp(config))
+		} else if config.Operator == "greater" {
+			p.operators = append(p.operators, NewGreaterFilterOp(config))
+		} else if config.Operator == "greaterThan" {
+			p.operators = append(p.operators, NewGreaterThanFilterOp(config))
+		} else if config.Operator == "less" {
+			p.operators = append(p.operators, NewLessFilterOp(config))
+		} else if config.Operator == "lessThan" {
+			p.operators = append(p.operators, NewLessThanFilterOp(config))
 		}
 	}
 
@@ -195,3 +203,167 @@ func (p *FilterParam) Evaluate(properties map[string]interface{}) (bool, error)
 	}
 	return true, nil
 }
+
+type GreaterFilterOp struct {
+	Name  string
+	Type  string
+	Value interface{}
+}
+
+func NewGreaterFilterOp(config recconf.FilterParamConfig) *GreaterFilterOp {
+
+	return &GreaterFilterOp{
+		Name:  config.Name,
+		Type:  config.Type,
+		Value: config.Value,
+	}
+}
+
+func (p *GreaterFilterOp) Evaluate(properties map[string]interface{}) (bool, error) {
+
+	left, ok := properties[p.Name]
+	if !ok {
+		return false, nil
+	}
+
+	switch p.Type {
+	case "float":
+		v1 := utils.ToFloat(left, 0)
+		v2 := utils.ToFloat(p.Value, 0)
+
+		return v1 > v2, nil
+	case "int":
+		v1 := utils.ToInt(left, 0)
+		v2 := utils.ToInt(p.Value, 0)
+		return v1 > v2, nil
+	case "int64":
+		v1 := utils.ToInt64(left, 0)
+		v2 := utils.ToInt64(p.Value, 0)
+		return v1 > v2, nil
+	default:
+		return false, nil
+	}
+}
+
+type GreaterThanFilterOp struct {
+	Name  string
+	Type  string
+	Value interface{}
+}
+
+func NewGreaterThanFilterOp(config recconf.FilterParamConfig) *GreaterThanFilterOp {
+
+	return &GreaterThanFilterOp{
+		Name:  config.Name,
+		Type:  config.Type,
+		Value: config.Value,
+	}
+}
+
+func (p *GreaterThanFilterOp) Evaluate(properties map[string]interface{}) (bool, error) {
+
+	left, ok := properties[p.Name]
+	if !ok {
+		return false, nil
+	}
+
+	switch p.Type {
+	case "float":
+		v1 := utils.ToFloat(left, 0)
+		v2 := utils.ToFloat(p.Value, 0)
+
+		return v1 >= v2, nil
+	case "int":
+		v1 := utils.ToInt(left, 0)
+		v2 := utils.ToInt(p.Value, 0)
+		return v1 >= v2, nil
+	case "int64":
+		v1 := utils.ToInt64(left, 0)
+		v2 := utils.ToInt64(p.Value, 0)
+		return v1 >= v2, nil
+	default:
+		return false, nil
+	}
+}
+
+type LessFilterOp struct {
+	Name  string
+	Type  string
+	Value interface{}
+}
+
+func NewLessFilterOp(config recconf.FilterParamConfig) *LessFilterOp {
+
+	return &LessFilterOp{
+		Name:  config.Name,
+		Type:  config.Type,
+		Value: config.Value,
+	}
+}
+
+func (p *LessFilterOp) Evaluate(properties map[string]interface{}) (bool, error) {
+
+	left, ok := properties[p.Name]
+	if !ok {
+		return false, nil
+	}
+
+	switch p.Type {
+	case "float":
+		v1 := utils.ToFloat(left, 0)
+		v2 := utils.ToFloat(p.Value, 0)
+
+		return v1 < v2, nil
+	case "int":
+		v1 := utils.ToInt(left, 0)
+		v2 := utils.ToInt(p.Value, 0)
+		return v1 < v2, nil
+	case "int64":
+		v1 := utils.ToInt64(left, 0)
+		v2 := utils.ToInt64(p.Value, 0)
+		return v1 < v2, nil
+	default:
+		return false, nil
+	}
+}
+
+type LessThanFilterOp struct {
+	Name  string
+	Type  string
+	Value interface{}
+}
+
+func NewLessThanFilterOp(config recconf.FilterParamConfig) *LessThanFilterOp {
+
+	return &LessThanFilterOp{
+		Name:  config.Name,
+		Type:  config.Type,
+		Value: config.Value,
+	}
+}
+
+func (p *LessThanFilterOp) Evaluate(properties map[string]interface{}) (bool, error) {
+
+	left, ok := properties[p.Name]
+	if !ok {
+		return false, nil
+	}
+
+	switch p.Type {
+	case "float":
+		v1 := utils.ToFloat(left, 0)
+		v2 := utils.ToFloat(p.Value, 0)
+
+		return v1 <= v2, nil
+	case "int":
+		v1 := utils.ToInt(left, 0)
+		v2 := utils.ToInt(p.Value, 0)
+		return v1 <= v2, nil
+	case "int64":
+		v1 := utils.ToInt64(left, 0)
+		v2 := utils.ToInt64(p.Value, 0)
+		return v1 <= v2, nil
+	default:
+		return false, nil
+	}
+}

+ 12 - 11
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/item.go

@@ -16,8 +16,9 @@ type Item struct {
 	RetrieveId string
 	ItemType   string
 	// ItemStatus int
+	Embedding []float64
 
-	mutex sync.Mutex
+	mutex sync.RWMutex
 	// TimeStamp  time.Time
 	Properties map[string]interface{} `json:"properties"`
 	algoScores map[string]float64
@@ -44,8 +45,8 @@ func (t *Item) GetRecallName() string {
 	return t.RetrieveId
 }
 func (t *Item) GetAlgoScores() map[string]float64 {
-	t.mutex.Lock()
-	defer t.mutex.Unlock()
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	return t.algoScores
 }
 func (t *Item) AddProperty(key string, value interface{}) {
@@ -54,8 +55,8 @@ func (t *Item) AddProperty(key string, value interface{}) {
 	t.Properties[key] = value
 }
 func (t *Item) GetProperty(key string) interface{} {
-	t.mutex.Lock()
-	defer t.mutex.Unlock()
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	val, ok := t.Properties[key]
 	if !ok {
 		return nil
@@ -63,8 +64,8 @@ func (t *Item) GetProperty(key string) interface{} {
 	return val
 }
 func (t *Item) StringProperty(key string) string {
-	t.mutex.Lock()
-	defer t.mutex.Unlock()
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	val, ok := t.Properties[key]
 	if !ok {
 		return ""
@@ -85,8 +86,8 @@ func (t *Item) StringProperty(key string) string {
 	return ""
 }
 func (t *Item) FloatProperty(key string) (float64, error) {
-	t.mutex.Lock()
-	defer t.mutex.Unlock()
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	val, ok := t.Properties[key]
 	if !ok {
 		return float64(0), errors.New("property key not exist")
@@ -105,8 +106,8 @@ func (t *Item) FloatProperty(key string) (float64, error) {
 	}
 }
 func (t *Item) IntProperty(key string) (int, error) {
-	t.mutex.Lock()
-	defer t.mutex.Unlock()
+	t.mutex.RLock()
+	defer t.mutex.RUnlock()
 	val, ok := t.Properties[key]
 	if !ok {
 		return int(0), errors.New("property key not exist")

+ 56 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/trigger_test.go

@@ -0,0 +1,56 @@
+package module
+
+import (
+	"fmt"
+	"testing"
+
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+)
+
+func TestTrigger(t *testing.T) {
+	config := []recconf.TriggerConfig{
+		recconf.TriggerConfig{
+			TriggerKey: "sex",
+		},
+		recconf.TriggerConfig{
+			TriggerKey: "age",
+			Boundaries: []int{20, 30, 40, 50},
+		},
+		recconf.TriggerConfig{
+			TriggerKey: "os",
+		},
+	}
+
+	trigger := NewTrigger(config)
+
+	features := []map[string]interface{}{
+		map[string]interface{}{"sex": "Male",
+			"os":  "IOS",
+			"age": 23,
+		},
+
+		map[string]interface{}{"sex": "Male",
+			"os": "Android",
+		},
+		map[string]interface{}{"sex": "Male",
+			"os":  "Android",
+			"age": 60,
+		},
+		map[string]interface{}{"sex": "Male",
+			"os":  "Android",
+			"age": 50,
+		},
+		map[string]interface{}{"sex": "Male",
+			"os":  "Android",
+			"age": 40,
+		},
+		map[string]interface{}{"sex": "Male",
+			"os":  "Android",
+			"age": 20,
+		},
+	}
+
+	for _, f := range features {
+		fmt.Println(trigger.GetValue(f))
+	}
+}

+ 3 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_collaborative_dao.go

@@ -18,6 +18,9 @@ func NewUserCollaborativeDao(config recconf.RecallConfig) UserCollaborativeDao {
 		}
 	} else if config.UserCollaborativeDaoConf.AdapterType == recconf.DaoConf_Adapter_TableStore {
 		return NewUserCollaborativeTableStoreDao(config)
+	} else if config.UserCollaborativeDaoConf.AdapterType == recconf.DaoConf_Adapter_Hologres {
+		return NewUserCollaborativeHologresDao(config)
 	}
+
 	panic("not found UserCollaborativeDao implement")
 }

+ 196 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_collaborative_hologres_dao.go

@@ -0,0 +1,196 @@
+package module
+
+import (
+	gocontext "context"
+	"database/sql"
+	"fmt"
+	"math/rand"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/huandu/go-sqlbuilder"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/holo"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+)
+
+type UserCollaborativeHologresDao struct {
+	db          *sql.DB
+	userTable   string
+	itemTable   string
+	itemType    string
+	recallName  string
+	userStmt    *sql.Stmt
+	mu          sync.RWMutex
+	itemStmtMap map[int]*sql.Stmt
+}
+
+func NewUserCollaborativeHologresDao(config recconf.RecallConfig) *UserCollaborativeHologresDao {
+	dao := &UserCollaborativeHologresDao{
+		itemStmtMap: make(map[int]*sql.Stmt, 0),
+	}
+	hologres, err := holo.GetPostgres(config.UserCollaborativeDaoConf.HologresName)
+	if err != nil {
+		log.Error(fmt.Sprintf("%v", err))
+		return nil
+	}
+	dao.db = hologres.DB
+	dao.userTable = config.UserCollaborativeDaoConf.User2ItemTable
+	dao.itemTable = config.UserCollaborativeDaoConf.Item2ItemTable
+	dao.itemType = config.ItemType
+	dao.recallName = config.Name
+	return dao
+}
+
+func (d *UserCollaborativeHologresDao) getItemStmt(key int) *sql.Stmt {
+	d.mu.RLock()
+	defer d.mu.RUnlock()
+	return d.itemStmtMap[key]
+}
+func (d *UserCollaborativeHologresDao) ListItemsByUser(user *User, context *context.RecommendContext) (ret []*Item) {
+	uid := string(user.Id)
+	sb := sqlbuilder.PostgreSQL.NewSelectBuilder()
+	sb.Select("item_ids").
+		From(d.userTable).
+		Where(
+			sb.Equal("user_id", uid),
+		)
+	sqlquery, args := sb.Build()
+	if d.userStmt == nil {
+		stmt, err := d.db.Prepare(sqlquery)
+		if err != nil {
+			log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCollaborativeHologresDao\tuid=%s\terror=%v", context.RecommendId, uid, err))
+			return
+		}
+		d.userStmt = stmt
+	}
+	rows, err := d.userStmt.Query(args...)
+	if err != nil {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCollaborativeHologresDao\tuid=%s\terror=%v", context.RecommendId, uid, err))
+		return
+	}
+	itemIds := make([]string, 0)
+	for rows.Next() {
+		var ids string
+		if err := rows.Scan(&ids); err == nil {
+			idList := strings.Split(ids, ",")
+			for _, id := range idList {
+				if len(id) > 0 {
+					itemIds = append(itemIds, id)
+				}
+			}
+		}
+	}
+	rows.Close()
+
+	if len(itemIds) == 0 {
+		log.Info(fmt.Sprintf("module=UserCollaborativeHologresDao\tuid=%s\terr=item ids empty", uid))
+		return
+	}
+
+	if len(itemIds) > 200 {
+		rand.Shuffle(len(itemIds)/2, func(i, j int) {
+			itemIds[i], itemIds[j] = itemIds[j], itemIds[i]
+		})
+
+		itemIds = itemIds[:200]
+	}
+
+	cpuCount := 4
+	maps := make(map[int][]interface{})
+	for i, id := range itemIds {
+		maps[i%cpuCount] = append(maps[i%cpuCount], id)
+	}
+
+	itemIdCh := make(chan []interface{}, cpuCount)
+	for _, ids := range maps {
+		itemIdCh <- ids
+	}
+
+	itemCh := make(chan []*Item, cpuCount)
+	for i := 0; i < cpuCount; i++ {
+		go func() {
+			result := make([]*Item, 0)
+		LOOP:
+			for {
+				select {
+				case ids := <-itemIdCh:
+					sb := sqlbuilder.PostgreSQL.NewSelectBuilder()
+					sb.Select("similar_item_ids").
+						From(d.itemTable).
+						Where(
+							sb.In("item_id", ids...),
+						)
+					sql, args := sb.Build()
+
+					stmtkey := len(ids)
+					stmt := d.getItemStmt(stmtkey)
+					if stmt == nil {
+						d.mu.Lock()
+						stmt = d.itemStmtMap[stmtkey]
+						if stmt == nil {
+							stmt2, err := d.db.Prepare(sql)
+							if err != nil {
+								log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCollaborativeHologresDao\terror=hologres error(%v)", context.RecommendId, err))
+								goto LOOP
+							}
+							d.itemStmtMap[stmtkey] = stmt2
+							stmt = stmt2
+							d.mu.Unlock()
+						} else {
+							d.mu.Unlock()
+						}
+					}
+					ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 100*time.Millisecond)
+					defer cancel()
+					rows, err := stmt.QueryContext(ctx, args...)
+					if err != nil {
+						log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCollaborativeHologresDao\tsql=%s\terror=%v", context.RecommendId, sql, err))
+						goto LOOP
+					}
+
+					for rows.Next() {
+						var ids string
+						if err := rows.Scan(&ids); err != nil {
+							log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCollaborativeHologresDao\terror=%v", context.RecommendId, err))
+							continue
+						}
+
+						list := strings.Split(ids, ",")
+						for _, str := range list {
+							strs := strings.Split(str, ":")
+							if len(strs) == 2 && len(strs[0]) > 0 && strs[0] != "null" {
+								item := NewItem(strs[0])
+								item.RetrieveId = d.recallName
+								item.ItemType = d.itemType
+								if tmpScore, err := strconv.ParseFloat(strs[1], 64); err == nil {
+									item.Score = tmpScore
+								}
+
+								result = append(result, item)
+							}
+
+						}
+
+					}
+					rows.Close()
+				default:
+					goto DONE
+
+				}
+			}
+		DONE:
+			itemCh <- result
+		}()
+	}
+	for i := 0; i < cpuCount; i++ {
+		items := <-itemCh
+		ret = append(ret, items...)
+	}
+	close(itemCh)
+	close(itemIdCh)
+	return
+}

+ 2 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_dao.go

@@ -16,6 +16,8 @@ func NewUserCustomRecallDao(config recconf.RecallConfig) UserCustomRecallDao {
 		return NewUserCustomRecallTableStoreDao(config)
 	} else if config.DaoConf.AdapterType == recconf.DaoConf_Adapter_Hologres {
 		return NewUserCusteomRecallHologresDao(config)
+	} else if config.DaoConf.AdapterType == recconf.DaoConf_Adapter_Redis {
+		return NewUserCusteomRecallRedisDao(config)
 	}
 
 	panic("not found UserCustomRecallDao implement")

+ 1 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_mysql_dao.go

@@ -80,6 +80,7 @@ func (d *UserCustomRecallMysqlDao) ListItemsByUser(user *User, context *context.
 			Id:         ItemId(id),
 			ItemType:   d.itemType,
 			RetrieveId: d.recallName,
+			Properties: make(map[string]interface{}),
 		}
 
 		ret = append(ret, item)

+ 105 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_custom_recall_redids_dao.go

@@ -0,0 +1,105 @@
+package module
+
+import (
+	"fmt"
+	"math/rand"
+	"strings"
+
+	"github.com/gomodule/redigo/redis"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/redisdb"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/utils"
+)
+
+type UserCustomRecallRedisDao struct {
+	redis       *redisdb.Redis
+	itemType    string
+	recallName  string
+	prefix      string
+	recallCount int
+}
+
+func NewUserCusteomRecallRedisDao(config recconf.RecallConfig) *UserCustomRecallRedisDao {
+	redis, err := redisdb.GetRedis(config.DaoConf.RedisName)
+	if err != nil {
+		log.Error(fmt.Sprintf("error=%v", err))
+		return nil
+	}
+
+	dao := &UserCustomRecallRedisDao{
+		recallCount: config.RecallCount,
+		redis:       redis,
+		prefix:      config.DaoConf.RedisPrefix,
+		itemType:    config.ItemType,
+		recallName:  config.Name,
+	}
+	return dao
+}
+
+func (d *UserCustomRecallRedisDao) ListItemsByUser(user *User, context *context.RecommendContext) (ret []*Item) {
+	conn := d.redis.Get()
+	defer conn.Close()
+	uid := string(user.Id)
+	key := d.prefix + uid
+	value, err := redis.String(conn.Do("GET", key))
+	if err != nil {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=UserCustomRecallRedisDao\tuid=%s\terror=%v", context.RecommendId, uid, err))
+		return
+	}
+	itemIds := make([]string, 0, d.recallCount)
+	if value != "" {
+		idList := strings.Split(value, ",")
+		for _, id := range idList {
+			if len(id) > 0 {
+				itemIds = append(itemIds, id)
+			}
+		}
+	}
+
+	if len(itemIds) == 0 {
+		return
+	}
+
+	if len(itemIds) > d.recallCount {
+		rand.Shuffle(len(itemIds)/2, func(i, j int) {
+			itemIds[i], itemIds[j] = itemIds[j], itemIds[i]
+		})
+
+		itemIds = itemIds[:d.recallCount]
+	}
+
+	for _, id := range itemIds {
+		strs := strings.Split(id, ":")
+		if len(strs) == 1 {
+			// itemid
+			item := NewItem(strs[0])
+			item.ItemType = d.itemType
+			item.RetrieveId = d.recallName
+			ret = append(ret, item)
+		} else if len(strs) == 2 {
+			// itemid:RetrieveId
+			item := NewItem(strs[0])
+			item.ItemType = d.itemType
+			if strs[1] != "" {
+				item.RetrieveId = strs[1]
+			} else {
+				item.RetrieveId = d.recallName
+			}
+			ret = append(ret, item)
+		} else if len(strs) == 3 {
+			item := NewItem(strs[0])
+			item.ItemType = d.itemType
+			if strs[1] != "" {
+				item.RetrieveId = strs[1]
+			} else {
+				item.RetrieveId = d.recallName
+			}
+			item.Score = utils.ToFloat(strs[2], float64(0))
+			ret = append(ret, item)
+		}
+	}
+
+	return
+}

+ 2 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_item_exposure_dao.go

@@ -44,6 +44,8 @@ func NewUser2ItemExposureDao(config recconf.FilterConfig) User2ItemExposureDao {
 		dao = NewUser2ItemExposureTableStoreDao(config)
 	} else if config.DaoConf.AdapterType == recconf.DaoConf_Adapter_Hologres {
 		dao = NewUser2ItemExposureHologresDao(config)
+	} else if config.DaoConf.AdapterType == recconf.DaoConf_Adapter_Redis {
+		dao = NewUser2ItemExposureRedisDao(config)
 	} else {
 		panic("not found User2ItemExposureDao implement")
 	}

+ 132 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/user_item_exposure_redis_dao.go

@@ -0,0 +1,132 @@
+package module
+
+import (
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/context"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/redisdb"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+)
+
+type User2ItemExposureRedisDao struct {
+	redis        *redisdb.Redis
+	prefix       string
+	maxItems     int
+	timeInterval int //  second
+}
+
+func NewUser2ItemExposureRedisDao(config recconf.FilterConfig) *User2ItemExposureRedisDao {
+	dao := &User2ItemExposureRedisDao{
+		maxItems:     100,
+		timeInterval: -1,
+	}
+	redis, err := redisdb.GetRedis(config.DaoConf.RedisName)
+	if err != nil {
+		log.Error(fmt.Sprintf("%v", err))
+		return nil
+	}
+
+	dao.redis = redis
+	if config.MaxItems > 0 {
+		dao.maxItems = config.MaxItems
+	}
+
+	if config.TimeInterval > 0 {
+		dao.timeInterval = config.TimeInterval
+	}
+
+	dao.prefix = config.DaoConf.RedisPrefix
+	return dao
+}
+
+type exposureItemRedis struct {
+	ItemIds   []string `json:"item_ids"`
+	Timestamp int64    `json:"timestamp"`
+}
+
+func (d *User2ItemExposureRedisDao) LogHistory(user *User, items []*Item, context *context.RecommendContext) {
+	if len(items) == 0 {
+		log.Warning(fmt.Sprintf("requestId=%s\tmodule=User2ItemExposureRedisDao\terr=items empty", context.RecommendId))
+		return
+	}
+
+	prefix := d.prefix
+	/**
+	if prefix == "" {
+		scene := context.GetParameter("scene").(string)
+		prefix = scene + "_"
+	}
+	**/
+	addTime := time.Now().Unix()
+	uid := string(user.Id)
+	key := prefix + uid
+
+	exposureItem := exposureItemRedis{
+		Timestamp: addTime,
+	}
+
+	for i := 0; i < len(items); i++ {
+		exposureItem.ItemIds = append(exposureItem.ItemIds, string(items[i].Id))
+	}
+
+	data, _ := json.Marshal(exposureItem)
+	conn := d.redis.Get()
+	defer conn.Close()
+
+	len, err := redis.Int(conn.Do("LPUSH", key, string(data)))
+	if err != nil {
+		log.Error(fmt.Sprintf("requestId=%s\tmodule=User2ItemExposureRedisDao\tuid=%s\terr=%v", context.RecommendId, uid, err))
+		return
+	}
+
+	if len > d.maxItems {
+		conn.Do("LTRIM", key, 0, d.maxItems-1)
+	}
+
+	if d.timeInterval > 0 {
+		conn.Do("EXPIRE", key, d.timeInterval)
+	}
+
+	log.Info(fmt.Sprintf("requestId=%s\tuid=%s\tmsg=log history success", context.RecommendId, user.Id))
+
+}
+func (d *User2ItemExposureRedisDao) FilterByHistory(uid UID, items []*Item) (ret []*Item) {
+	prefix := d.prefix
+	key := prefix + string(uid)
+	conn := d.redis.Get()
+	defer conn.Close()
+
+	bytes, err := redis.ByteSlices(conn.Do("LRANGE", key, 0, d.maxItems-1))
+	if err != nil {
+		log.Error(fmt.Sprintf("module=User2ItemExposureRedisDao\tuid=%s\terr=%v", uid, err))
+		ret = items
+		return
+	}
+
+	fiterIds := make(map[string]bool)
+	t := time.Now().Unix()
+	for _, byte := range bytes {
+		exposureItem := exposureItemRedis{}
+		if err := json.Unmarshal(byte, &exposureItem); err == nil {
+			if d.timeInterval > 0 && (exposureItem.Timestamp < t-int64(d.timeInterval)) {
+				continue
+			}
+
+			for _, id := range exposureItem.ItemIds {
+				fiterIds[id] = true
+			}
+
+		}
+	}
+
+	for _, item := range items {
+		if _, ok := fiterIds[string(item.Id)]; !ok {
+			ret = append(ret, item)
+		}
+	}
+	return
+}

+ 2 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_dao.go

@@ -21,6 +21,8 @@ func NewVectorDao(config recconf.RecallConfig) VectorDao {
 		return NewVectorHBaseDao(config)
 	} else if config.VectorDaoConf.AdapterType == recconf.DaoConf_Adapter_Hologres {
 		return NewVectorHologresDao(config)
+	} else if config.VectorDaoConf.AdapterType == recconf.DaoConf_Adapter_Mysql {
+		return NewVectorMysqlDao(config)
 	}
 
 	panic("not found VectorDao implement")

+ 61 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_hologres_dao.go

@@ -5,6 +5,7 @@ import (
 	"database/sql"
 	"fmt"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"strings"
 	"sync"
 	"time"
 
@@ -34,6 +35,30 @@ func NewVectorHologresDao(config recconf.RecallConfig) *VectorHologresDao {
 		embeddingField: config.VectorDaoConf.EmbeddingField,
 		keyField:       config.VectorDaoConf.KeyField,
 	}
+
+	go func(dao *VectorHologresDao) {
+		partition := "{partition}"
+		for {
+			hologresName := config.VectorDaoConf.HologresName
+			table := config.VectorDaoConf.PartitionInfoTable
+			field := config.VectorDaoConf.PartitionInfoField
+			if config.RecallType == "HologresVectorRecall" && table != "" && field != "" {
+				newPartition := FetchPartition(hologresName, table, field)
+				if newPartition != "" && newPartition != partition {
+					dao.table = strings.Replace(dao.table, partition, newPartition, -1)
+					partition = newPartition
+
+					dao.mu.Lock()
+					dao.dbStmt = nil
+					dao.mu.Unlock()
+				}
+				time.Sleep(time.Minute)
+			} else {
+				break
+			}
+		}
+	}(dao)
+
 	return dao
 }
 
@@ -86,3 +111,39 @@ func (d *VectorHologresDao) VectorString(id string) (string, error) {
 
 	return embedding, nil
 }
+
+func FetchPartition(hologresName, table, field string) string {
+	hologres, err := holo.GetPostgres(hologresName)
+	if err != nil {
+		log.Error(fmt.Sprintf("module=VectorHologresDao\tevent=FetchPartition\terror=%v", err))
+		return ""
+	}
+	builder := sqlbuilder.PostgreSQL.NewSelectBuilder()
+	builder.Select(field)
+	builder.From(table)
+	builder.Limit(1)
+	sqlquery, args := builder.Build()
+	stmt, err := hologres.DB.Prepare(sqlquery)
+	if err != nil {
+		log.Error(fmt.Sprintf("module=VectorHologresDao\tevent=FetchPartition\terror=%v", err))
+		return ""
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+	defer cancel()
+	rows, err := stmt.QueryContext(ctx, args...)
+	if err != nil {
+		log.Error(fmt.Sprintf("module=VectorHologresDao\tevent=FetchPartition\terror=%v", err))
+		return ""
+	}
+	var partition string
+
+	for rows.Next() {
+		if err := rows.Scan(&partition); err != nil {
+			log.Error(fmt.Sprintf("module=VectorHologresDao\tevent=FetchPartition\terror=%v", err))
+			return ""
+		}
+		return partition
+	}
+
+	return ""
+}

+ 90 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/module/vector_mysql_dao.go

@@ -0,0 +1,90 @@
+package module
+
+import (
+	"context"
+	"database/sql"
+	"fmt"
+	"github.com/huandu/go-sqlbuilder"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
+	"strings"
+	"sync"
+	"time"
+)
+
+type VectorMysqlDao struct {
+	db             *sql.DB
+	table          string
+	embeddingField string
+	keyField       string
+	mu             sync.RWMutex
+	dbStmt         *sql.Stmt
+}
+
+func NewVectorMysqlDao(config recconf.RecallConfig) *VectorMysqlDao {
+	mysql, err := mysqldb.GetMysql(config.VectorDaoConf.MysqlName)
+	if err != nil {
+		panic(err)
+	}
+
+	dao := &VectorMysqlDao{
+		db:             mysql.DB,
+		table:          config.VectorDaoConf.MysqlTable,
+		embeddingField: config.VectorDaoConf.EmbeddingField,
+		keyField:       config.VectorDaoConf.KeyField,
+	}
+
+	return dao
+}
+
+func (d *VectorMysqlDao) VectorString(id string) (string, error) {
+	builder := sqlbuilder.MySQL.NewSelectBuilder()
+	builder.Select(d.embeddingField)
+	builder.From(d.table)
+	builder.Where(builder.Equal(d.keyField, id))
+
+	sqlquery, args := builder.Build()
+	if d.dbStmt == nil {
+		d.mu.Lock()
+		if d.dbStmt == nil {
+			stmt, err := d.db.Prepare(sqlquery)
+			if err != nil {
+				d.mu.Unlock()
+				return "", err
+			}
+			d.dbStmt = stmt
+			d.mu.Unlock()
+		} else {
+			d.mu.Unlock()
+		}
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+	defer cancel()
+	rows, err := d.dbStmt.QueryContext(ctx, args...)
+	if err != nil {
+		log.Error(fmt.Sprintf("module=VectorMysqlDao\tevent=VectorString\terror=%v", err))
+		return "", err
+	}
+	var embedding string
+	for rows.Next() {
+		if err := rows.Scan(&embedding); err != nil {
+			return conversionEmbeddingFormat(embedding), err
+		}
+	}
+
+	if embedding == "" {
+		return embedding, VectoryEmptyError
+	}
+
+	return conversionEmbeddingFormat(embedding), nil
+}
+
+func conversionEmbeddingFormat(emb string) string {
+	vectors := strings.Split(emb, ",")
+	for i, v := range vectors {
+		vectors[i] = fmt.Sprintf("%d:%s", i+1, v)
+	}
+	return strings.Join(vectors, " ")
+}

+ 2 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/pairec.go

@@ -9,6 +9,7 @@ import (
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/abtest"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/algorithm"
+	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/config"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/datahub"
 	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/datasource/hbase"
@@ -33,6 +34,7 @@ var configFile string
 
 func init() {
 	flag.StringVar(&configFile, "config", "", "config file path")
+	flag.BoolVar(&config.AppConfig.WarmUpData, "warm-up-data", false, "create eas warm up data flag")
 }
 func AddStartHook(hf ...hookfunc) {
 	hooks = append(hooks, hf...)

+ 47 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/cache/localcache_test.go

@@ -0,0 +1,47 @@
+package cache
+
+import (
+	"testing"
+	"time"
+)
+
+func TestLocalCache(t *testing.T) {
+	tests := []struct {
+		Key    string
+		Value  string
+		Expire time.Duration
+		Want   bool
+	}{
+		{
+			"foo",
+			"var",
+			10 * time.Second,
+			true,
+		},
+	}
+
+	config := "{\"defaultExpiration\":1800, \"cleanupInterval\":1800}"
+	cache, err := NewCache("localCache", config)
+	if err != nil {
+		t.Error(err)
+	}
+	for _, test := range tests {
+		cache.Put(test.Key, test.Value, test.Expire)
+		v := cache.DefaultGet(test.Key, "")
+		if val, ok := v.(string); !ok {
+			t.Errorf("get cache error, key=%s", test.Key)
+		} else if val != test.Value {
+			t.Errorf("get cache error, key=%s, want=%v, get=%v", test.Key, test.Want, false)
+		}
+	}
+	for _, test := range tests {
+		cache.Put(test.Key, test.Value, test.Expire)
+		time.Sleep(test.Expire + time.Second)
+		v := cache.DefaultGet(test.Key, "")
+		if val, ok := v.(string); !ok {
+			t.Errorf("get cache error, key=%s", test.Key)
+		} else if val == test.Value {
+			t.Errorf("get cache error, key=%s, want nothing, get=%s", test.Key, val)
+		}
+	}
+}

+ 42 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/cache/redis_test.go

@@ -0,0 +1,42 @@
+package cache
+
+import (
+	"fmt"
+	"testing"
+	"time"
+)
+
+func TestRedisInit(t *testing.T) {
+	config := "{\"host\":\"127.0.0.1\", \"port\":6379, \"maxIdle\":3, \"password\":\"\"}"
+
+	cache, err := NewCache("redis", config)
+	if err != nil {
+		t.Error(err)
+	}
+
+	if cache == nil {
+		t.Errorf("cache is nil")
+	}
+}
+func getCache() (Cache, error) {
+	config := "{\"host\":\"127.0.0.1\", \"port\":6379, \"maxIdle\":3, \"password\":\"\"}"
+
+	cache, err := NewCache("redis", config)
+	return cache, err
+}
+func TestRedisPut(t *testing.T) {
+	cache, err := getCache()
+	if err != nil {
+		t.Error(err)
+	}
+
+	err = cache.Put("foo", "bar", 10*time.Second)
+	if err != nil {
+		t.Error(err)
+	}
+
+	val := cache.Get("foo")
+
+	fmt.Println(string(val.([]uint8)))
+
+}

+ 165 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/holo/postgres_test.go

@@ -0,0 +1,165 @@
+package holo
+
+import (
+	"context"
+	"database/sql"
+	"errors"
+	"fmt"
+	"reflect"
+	"strconv"
+	"testing"
+	"time"
+)
+
+func TestPostgres(t *testing.T) {
+	dsn := "postgres://rec:test123456@11.158.166.161/mydb?sslmode=disable"
+	psql := &Postgres{
+		DSN: dsn,
+	}
+
+	err := psql.Init()
+	if err != nil {
+		t.Error(err)
+	}
+	query := "select count(*) from test"
+
+	stmt, err := psql.DB.Prepare(query)
+	if err != nil {
+		t.Error(err)
+	}
+	rows, err := stmt.Query()
+	if err != nil {
+		t.Error(err)
+	}
+	defer stmt.Close()
+	defer rows.Close()
+	var count int
+
+	for rows.Next() {
+		if err := rows.Scan(&count); err != nil {
+			t.Error(err)
+		}
+
+		fmt.Println("rows count:", count)
+
+	}
+
+}
+
+func TestPostgresSelect(t *testing.T) {
+	dsn := "postgres://LTAIm398VwCMfDhK:vFNt9TQTQTlbzwtzlIH4HTegWHqJrw@hgpostcn-cn-st21oucpr001-cn-beijing.hologres.aliyuncs.com:80/mydb?sslmode=disable"
+	psql := &Postgres{
+		DSN: dsn,
+	}
+
+	err := psql.Init()
+	if err != nil {
+		t.Error(err)
+	}
+	query := "select * from t_test where id=1"
+
+	stmt, err := psql.DB.Prepare(query)
+	if err != nil {
+		t.Error(err)
+	}
+	rows, err := stmt.Query()
+	if err != nil {
+		t.Error(err)
+	}
+	defer stmt.Close()
+	defer rows.Close()
+
+	columns, err := rows.ColumnTypes()
+	if err != nil {
+		t.Error(err)
+	}
+	values := make([]interface{}, len(columns))
+	for i, column := range columns {
+		fmt.Println(column.Name(), column.ScanType())
+		switch column.ScanType().Kind() {
+		case reflect.Int32:
+			// values[i] = reflect.New(sql.NullInt32).Interface()
+			values[i] = &sql.NullInt32{}
+		case reflect.Bool:
+			// values[i] = reflect.New(sql.NullInt32).Interface()
+			values[i] = &sql.NullBool{}
+		case reflect.String:
+			values[i] = &sql.NullString{}
+		default:
+			values[i] = &sql.NullFloat64{}
+		}
+		// values[i] = reflect.New(column.ScanType()).Interface()
+	}
+	fmt.Println(columns)
+	for rows.Next() {
+		if err := rows.Scan(values...); err == nil {
+			for i, column := range columns {
+				name := column.Name()
+				nullable, ok := column.Nullable()
+				if ok && nullable {
+					continue
+				}
+
+				val := values[i]
+				switch v := val.(type) {
+				case *sql.NullInt32:
+					if v.Valid {
+						fmt.Println(name, "int valid", v.Int32)
+					}
+
+				case string:
+					f, err := strconv.ParseFloat(v, 64)
+					fmt.Println(name, v, f, err)
+				default:
+					fmt.Println("default", name, v)
+				}
+			}
+		} else {
+			t.Error(err)
+		}
+	}
+
+}
+func TestPostgresConnection(t *testing.T) {
+	dsn := "postgres://LTAIm398VwCMfDhK:vFNt9TQTQTlbzwtzlIH4HTegWHqJrw@hgpostcn-cn-st21oucpr001-cn-beijing.hologres.aliyuncs.com:80/mydb?sslmode=disable"
+	psql := &Postgres{
+		DSN: dsn,
+	}
+
+	err := psql.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	conn, err := psql.DB.Conn(context.Background())
+	if err != nil {
+		t.Error(err)
+	}
+	query := "select val from t_test2 where id=%d"
+
+	for i := 1; i < 4; i++ {
+		go func(i int) {
+			sqlquery := fmt.Sprintf(query, i)
+			for {
+				rows, err := conn.QueryContext(context.Background(), sqlquery)
+				if err != nil {
+					t.Error(err)
+				}
+
+				fmt.Println(sqlquery, rows, err)
+				for rows.Next() {
+					var v int
+					if err := rows.Scan(&v); err == nil {
+						if v != i {
+							fmt.Println(i, v)
+							t.Error(errors.New("query error"))
+						}
+					}
+				}
+				rows.Close()
+			}
+		}(i)
+	}
+
+	time.Sleep(time.Minute)
+}

+ 37 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/mysqldb/mysql_test.go

@@ -0,0 +1,37 @@
+package mysqldb
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestMysql(t *testing.T) {
+	dsn := "root:mysql@tcp/zqkd"
+	mysql := &Mysql{
+		DSN: dsn,
+	}
+
+	err := mysql.Init()
+	if err != nil {
+		t.Error(err)
+	}
+	query := "select count(*) from wx_past_cate_457"
+
+	stmt, _ := mysql.DB.Prepare(query)
+	rows, err := stmt.Query()
+	if err != nil {
+		t.Error(err)
+	}
+
+	var count int
+
+	for rows.Next() {
+		if err := rows.Scan(&count); err != nil {
+			t.Error(err)
+		}
+
+		fmt.Println("rows count:", count)
+
+	}
+
+}

+ 54 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/redisdb/redis_test.go

@@ -0,0 +1,54 @@
+package redisdb
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestRedis(t *testing.T) {
+	r := &Redis{
+		Host:    "127.0.0.1",
+		Port:    6379,
+		MaxIdle: 3,
+	}
+	err := r.Init()
+	if err != nil {
+		t.Error(err)
+	}
+	c := r.Pool.Get()
+	defer c.Close()
+	_, err = c.Do("SETEX", "foo1", 100, "bar")
+	if err != nil {
+		t.Error(err)
+	}
+}
+func TestPipleline(t *testing.T) {
+	r := &Redis{
+		Host:    "127.0.0.1",
+		Port:    6379,
+		MaxIdle: 3,
+	}
+	err := r.Init()
+	if err != nil {
+		t.Error(err)
+	}
+	c := r.Pool.Get()
+	defer c.Close()
+	c.Send("SET", "foo", "bar")
+	c.Send("GET", "foo")
+	c.Flush()
+	c.Receive()           // reply from SET
+	v, err := c.Receive() // reply from GET
+	if err != nil {
+		t.Error(err)
+	}
+	fmt.Println(string(v.([]uint8)))
+
+	c.Send("MULTI")
+	c.Send("INCR", "foo2")
+	c.Send("INCR", "bar2")
+	c.Send("SET", "foo", "bar")
+	c.Send("GET", "foo")
+	v, err = c.Do("EXEC")
+	fmt.Println(v, err)
+}

+ 149 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/persist/tablestoredb/tablestore_test.go

@@ -0,0 +1,149 @@
+package tablestoredb
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
+)
+
+func TestTableStoreInsert(t *testing.T) {
+	ots := &TableStore{
+		EndPoint:     "https://pai-test.cn-beijing.ots.aliyuncs.com",
+		InstanceName: "pai-test",
+		RoleArn:      "acs:ram::1730760139076263:role/otsadmin",
+	}
+
+	err := ots.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	putRowRequest := new(tablestore.PutRowRequest)
+	putRowChange := new(tablestore.PutRowChange)
+	putRowChange.TableName = "user_expose_log"
+	putPk := new(tablestore.PrimaryKey)
+	putPk.AddPrimaryKeyColumn("did", "123456")
+
+	putRowChange.PrimaryKey = putPk
+	putRowChange.AddColumn("itemid", "itemid_123")
+	putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE)
+	putRowRequest.PutRowChange = putRowChange
+	_, err = ots.Client.PutRow(putRowRequest)
+
+	if err != nil {
+		fmt.Println("putrow failed with error:", err)
+		t.Error(err)
+	} else {
+		fmt.Println("putrow finished")
+	}
+
+	getRowRequest := new(tablestore.GetRowRequest)
+	criteria := new(tablestore.SingleRowQueryCriteria)
+	putPk = new(tablestore.PrimaryKey)
+	putPk.AddPrimaryKeyColumn("did", "123456")
+
+	criteria.PrimaryKey = putPk
+	getRowRequest.SingleRowQueryCriteria = criteria
+	getRowRequest.SingleRowQueryCriteria.TableName = "user_expose_log"
+	getRowRequest.SingleRowQueryCriteria.MaxVersion = 1
+	getResp, err := ots.Client.GetRow(getRowRequest)
+	if err != nil {
+		fmt.Println("getrow failed with error:", err)
+	} else {
+		fmt.Println("get row col0 result is ", getResp.Columns[0].ColumnName, getResp.Columns[0].Value)
+	}
+}
+func TestTableStoreGet(t *testing.T) {
+	ots := &TableStore{
+		EndPoint:     "https://pai-test.cn-beijing.ots.aliyuncs.com",
+		InstanceName: "pai-test",
+		RoleArn:      "acs:ram::1730760139076263:role/otsadmin",
+	}
+	err := ots.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	getRowRequest := new(tablestore.GetRowRequest)
+	criteria := new(tablestore.SingleRowQueryCriteria)
+	putPk := new(tablestore.PrimaryKey)
+	putPk.AddPrimaryKeyColumn("topic", "topic_1")
+
+	criteria.PrimaryKey = putPk
+
+	getRowRequest.SingleRowQueryCriteria = criteria
+	getRowRequest.SingleRowQueryCriteria.TableName = "user_topic"
+	getRowRequest.SingleRowQueryCriteria.MaxVersion = 10
+
+	getResp, err := ots.Client.GetRow(getRowRequest)
+
+	fmt.Println(getResp, err, len(getResp.Columns))
+
+	for _, col := range getResp.Columns {
+		fmt.Println(col)
+	}
+}
+func TestPutRow(t *testing.T) {
+	ots := &TableStore{
+		EndPoint:     "https://pai-test.cn-beijing.ots.aliyuncs.com",
+		InstanceName: "pai-test",
+		RoleArn:      "acs:ram::1730760139076263:role/otsadmin",
+	}
+	err := ots.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	putRowRequest := new(tablestore.PutRowRequest)
+	putRowChange := new(tablestore.PutRowChange)
+	putRowChange.TableName = "topic_item"
+	putPk := new(tablestore.PrimaryKey)
+	// putPk.AddPrimaryKeyColumn("id", "")
+	putPk.AddPrimaryKeyColumnWithAutoIncrement("id")
+	//
+	putRowChange.PrimaryKey = putPk
+	putRowChange.AddColumn("topic", "topic_1")
+	putRowChange.AddColumn("item_id", "123456")
+	putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE)
+	putRowRequest.PutRowChange = putRowChange
+	resp, err1 := ots.Client.PutRow(putRowRequest)
+
+	fmt.Println(resp, err1)
+	if err1 != nil {
+		fmt.Println("putrow failed with error:", err1)
+	} else {
+		fmt.Println("putrow finished")
+	}
+}
+
+func TestUpdateRow(t *testing.T) {
+	ots := &TableStore{
+		EndPoint:     "https://pai-test.cn-beijing.ots.aliyuncs.com",
+		InstanceName: "pai-test",
+		RoleArn:      "acs:ram::1730760139076263:role/otsadmin",
+	}
+	err := ots.Init()
+	if err != nil {
+		t.Error(err)
+	}
+
+	putRowRequest := new(tablestore.UpdateRowRequest)
+	putRowChange := new(tablestore.UpdateRowChange)
+	putRowChange.TableName = "user_topic"
+	putPk := new(tablestore.PrimaryKey)
+	putPk.AddPrimaryKeyColumn("topic", "topic_1")
+
+	putRowChange.PrimaryKey = putPk
+	putRowChange.PutColumn("item_id", "1234")
+	putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE)
+	putRowRequest.UpdateRowChange = putRowChange
+	resp, err1 := ots.Client.UpdateRow(putRowRequest)
+
+	fmt.Println(resp, err1)
+	if err1 != nil {
+		fmt.Println("putrow failed with error:", err1)
+	} else {
+		fmt.Println("putrow finished")
+	}
+}

+ 45 - 17
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf/recconf.go

@@ -19,6 +19,7 @@ const (
 	DaoConf_Adapter_HBase      = "hbase"
 	DaoConf_Adapter_Hologres   = "hologres"
 	DataSource_Type_Kafka      = "kafka"
+	DataSource_Type_Datahub    = "datahub"
 )
 
 func init() {
@@ -49,6 +50,7 @@ type RecommendConfig struct {
 	CallBackConfs      map[string]CallBackConfig
 	GeneralRankConfs   map[string]GeneralRankConfig
 	ColdStartRankConfs map[string]ColdStartRankConfig
+	DPPConf            []DPPSortConfig
 }
 type ListenConfig struct {
 	HttpAddr string
@@ -91,6 +93,18 @@ type FeatureDaoConfig struct {
 	ItemFeatureKeyName string
 	UserSelectFields   string
 	ItemSelectFields   string
+	FeatureType        string // per feature type has different way of build
+	SequenceLength     int
+	SequenceName       string
+	SequenceEvent      string
+	SequenceDelim      string
+	// SequencePlayTime filter event by as least play time
+	// like play event need to large than 10s, so set value is "play:10000", timeunit is ms
+	// if has  more than one event to filter, use ';' as delim , like "play:10000;read:50000"
+	SequencePlayTime         string
+	SequenceOfflineTableName string
+	// SequenceDimFields fetch other dimension fields from db
+	SequenceDimFields string
 }
 type FeatureConfig struct {
 	FeatureType         string
@@ -106,29 +120,14 @@ type AlgoConfig struct {
 	Type       string
 	EasConf    EasConfig
 	VectorConf VectorConfig
-	BanditConf BanditConfig
 	LookupConf LookupConfig
+	SeldonConf SeldonConfig
 }
 
 type LookupConfig struct {
 	FieldName string
 }
 
-type BanditConfig struct {
-	Alpha                float64
-	FeatureName          string
-	SharedFeatureName    string
-	ArmIdKey             string
-	Hologres             string
-	ModelTable           string
-	FeatureTable         string
-	CacheExpire          int
-	CacheMaxSize         int
-	GlobalModelParamId   string
-	RequestArmNumPerTime int
-	RequestArmInterval   int
-	Parallelism          int
-}
 type EasConfig struct {
 	Processor        string
 	Url              string
@@ -137,6 +136,11 @@ type EasConfig struct {
 	Timeout          int
 	RetryTimes       int
 	ResponseFuncName string
+	Outputs          []string
+}
+type SeldonConfig struct {
+	Url              string
+	ResponseFuncName string
 }
 type VectorConfig struct {
 	ServerAddress string
@@ -174,7 +178,7 @@ type SqlDaoConfig struct {
 	SelectFields string
 }
 type HologresVectorConfig struct {
-	VectorTable          string
+	VectorTable          string // example: "item_emb_{partition}", '{partition}' will be replaced by partition info
 	VectorKeyField       string
 	VectorEmbeddingField string
 }
@@ -202,6 +206,11 @@ type VectorDaoConfig struct {
 	DaoConfig
 	EmbeddingField string
 	KeyField       string
+
+	// set the following fields to get partition info,
+	// if not set, '{partition}' in table name won't be replaced (if it exists)
+	PartitionInfoTable string
+	PartitionInfoField string
 }
 type RedisConfig struct {
 	Host           string
@@ -245,6 +254,7 @@ type SceneConfig struct {
 }
 type CategoryConfig struct {
 	RecallNames []string
+	AlwaysRank  bool // when recall size is not enough, also need to rank
 }
 type RankConfig struct {
 	RankAlgoList []string
@@ -324,6 +334,24 @@ type TriggerConfig struct {
 	Boundaries   []int
 }
 
+type DPPSortConfig struct {
+	Name               string
+	DaoConf            DaoConfig
+	TableName          string
+	TableSuffixParam   string
+	TablePKey          string
+	EmbeddingColumn    string
+	EmbeddingSeparator string
+	Alpha              float64
+	CacheTimeInMinutes int
+	EmbeddingHookNames []string
+	NormalizeEmb       string
+	WindowSize         int
+	EmbMissedThreshold float64
+	FilterRetrieveIds  []string
+	EnsurePositiveSim  string
+}
+
 func newRecommendConfig() *RecommendConfig {
 	conf := RecommendConfig{
 		RunMode: "daily",

+ 38 - 0
vendor/gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf/recconf_test.go

@@ -0,0 +1,38 @@
+package recconf
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestCopyConfig(t *testing.T) {
+
+	src := &RecommendConfig{
+		RunMode: "dev",
+		ListenConf: ListenConfig{
+			HttpAddr: "",
+			HttpPort: 80,
+		},
+//		SortNames:   []string{"item_score"},
+//	    FilterNames: []string{"item_exposure_filter"},
+	}
+
+	dst := &RecommendConfig{
+		RunMode: "dev",
+		ListenConf: ListenConfig{
+			HttpAddr: "",
+			HttpPort: 80,
+		},
+	}
+
+	fmt.Println(dst)
+	CopyConfig(src, dst, func(name string) bool {
+		if name == "SortNames" {
+			return true
+		}
+		return false
+	})
+	fmt.Println(dst)
+	CopyConfig(src, dst)
+	fmt.Println(dst)
+}

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels