最近更新时间:2023.08.04 11:51:01
首次发布时间:2021.02.23 10:41:48
本文档仅针对SaaS版本,不针对SaaS云原生版本和私有化版本;
SaaS云原生版本和私有化版本接入请参考HTTP API文档中的「6.上报业务对象属性」模块。
本文档涉及的上报和查询 API 接口,接口采用 Restful API 规范。
该功能默认可以使用,但是上报item数据需要使用ak/sk,您可以通过页面右下角的工单功能或者联系您的客户成功经理告诉我们您要使用业务对象(Item)
功能。我们会将上报数据所需的 ak/sk 发送到您指定的邮箱。
您可以进入数据管理 > 业务对象
点击创建业务对象
按钮开始使用。
上图是我们的电商行业Demo,该 Demo 中“商品”就是我们预先定义好的业务对象。
点击创建业务对象
可以在弹框中对您想添加的业务对象以及它的属性进行配置。
目前我们对业务对象做了一些限制,具体如下:
在完成了 item 对象的定义后,数据上报须分两部分进行:
1) 通过本文 API 上报 item 对象;
2) 在上报事件时进行关联;
完成属性配置后,可以按下文中的(4.API用法)以及(6.鉴权)进行接口调用完成数据上报。注意数据类型一定正确,类型错误的数据会被丢弃。
创建好的 item 对象需要与事件关联才可以使用。关联就是将某一个或多个具体业务对象的 id 值作为上报到事件的预置属性params.__item
当中的过程。
下列示例代码演示了将 sku 和 order 两个创建好的业务对象与事件 new_order 进行关联的方式。__items
为事件预置属性,仅用于上报业务对象;
示例如下:
... "event": "new_order", "params": { "__items": "[{\"sku\":[{\"id\":\"sku_id_1\"},{\"id\":\"sku_id_2\"}]}]", ... }, ...
__item
是转为 string
的 json
对象,其格式为:
[ {"item_name_1": [ {"id": "id_value_1"}, {"id": "id_value_2"}, ... ]} ]
item_name_1
就是在上一步中定义的业务对象名称
;
如果这里关联的业务对象名称
没有被定义过,那么相应的数据就会被抛掉,不会入库;
如果 id 值没有找到对应的业务对象,也同样会被抛掉,不会入库,无法使用。
当已经完成数据上报,并且属性没有被禁用的情况下。就可以在属性筛选、分组等处使用这些属性了。
针对业务对象,我们还提供了业务对象分析
功能,可以以业务对象为主体进行分析。
[a-zA-Z_0-9\\-/]+
通过提供AccessKey/SecretKey的方式鉴权,简写为ak/sk,AccessKey是app请求的唯一标识,SecretKey是app的密钥,它们相当于用户名和密码。注册app之后就会生成一个AccessKey和SecretKey,请妥善保存。在所有请求的header中包括如下鉴权信息:
Header | Type | Description | Required |
---|---|---|---|
Authorization | string | api鉴权使用(Global) | TRUE |
- 及appSecret的生成可联系客户经理
- 可以使用我们提供的sdk帮助鉴权
- Authorization的生成工具见下文 示例代码-6.1
- 生成Authorization code示例代码见下午 示例代码-6.2
国内: https://analytics.volcengineapi.com
海外: https://analytics.byteplusapi.com
Path: /dataprofile/openapi/v1/{app_id}/items/{item_name}/{item_id}?set_once=true
Method: PUT
Content-Type: application/json; charset=utf-8
Request-parameters:
Parameter | Type | Description | Required |
---|---|---|---|
app_id | int64 | app_id | TRUE |
item_name | string | 属性名称 | TRUE |
item_id | string | item id | TRUE |
Query-parameters:
Parameter | Type | Description | Required |
---|---|---|---|
set_once | boolean | 不存在则设置 | TRUE |
Put body:
{ "name":"price", "value":9.9 }
Request-example:
curl -X PUT -H 'Content-Type: application/json; charset=utf-8' -H 'Authorization: ******' -i https://analytics.volcengineapi.com/dataprofile/openapi/v1/341/items/your_item_name/185?set_once=true --data '{ "name":"price","value":9.9 }'
Response-fields:
Field | Type | Description |
---|---|---|
code | int32 | 业务响应状态码 |
message | string | 业务响应描述信息 |
Response-example:
{ "code":2000, "message":"success" }
Path: /dataprofile/openapi/v1/{app_id}/items/{item_name}/{item_id}/attributes/{attribute}
Method: PUT
Content-Type: application/json; charset=utf-8
Request-parameters:
Parameter | Type | Description | Required |
---|---|---|---|
app_id | int64 | app_id | TRUE |
item_name | string | item名称 | TRUE |
item_id | string | item_id | TRUE |
attribute | string | 需要修改的属性名称 | TRUE |
Body:
{ "operation":"INCREASE", "value":9 }
operation可选值见下文 4.6 Operation
Request-example:
curl -X PUT -H 'Content-Type: application/json; charset=utf-8' -H 'Authorization: ******' -i https://analytics.volcengineapi.com/dataprofile/openapi/v1/384/items/your_item_name/185/attributes/storage --data '{ "operation":"INCREASE","value":9 }'
Response-fields:
Field | Type | Description |
---|---|---|
code | int32 | 业务响应状态码 |
message | string | 业务响应描述信息 |
Response-example:
{ "code":2000, "message":"success" }
Path: /dataprofile/openapi/v1/{app_id}/items/{item_name}/{item_id}/attributes
Method: PUT
Content-Type: application/json; charset=utf-8
Request-parameters:
Parameter | Type | Description | Required |
---|---|---|---|
app_id | int64 | app_id | TRUE |
item_name | string | 注册的item的名称 | TRUE |
item_id | string | item的唯一id | TRUE |
Body:
{ "attributes": [ { "name": "price", "value": 9, "operation": "SET" }, { "name": "storage", "value": 900, "operation": "INCREASE" }, { "name": "color", "operation": "UNSET" } ] }
operation可选值见下文 4.6 Operation
Request-example:
curl -X PUT -H 'Content-Type: application/json; charset=utf-8' -H 'Authorization: ******' -i https://analytics.volcengineapi.com/dataprofile/openapi/v1/541/items/your_item_name/185/attributes --data '{ "attributes": [ { "name": "price", "value": 9, "operation": "SET" }, { "name": "storage", "value": 900, "operation": "INCREASE" }, { "name": "color", "operation": "UNSET" } ] }'
Response-fields:
Field | Type | Description |
---|---|---|
code | int32 | 业务响应状态码 |
message | string | 业务响应描述信息 |
Response-example:
{ "code":2000, "message":"success" }
Path: /dataprofile/openapi/v1/{app_id}/items/{item_name}/{item_id}
Method: GET
Content-Type: application/json; charset=utf-8
Request-parameters:
Field | Type | Description |
---|---|---|
code | int32 | 业务响应状态码 |
message | string | 业务响应状态信息 |
data | object | 属性值信息 |
data.appId | int64 | 应用id |
data.attributes | list | 具体信息 |
data.attributes.name | string | 属性名称 |
data.attributes.value | 根据注册类型而定 | 值信息 |
Request-example:
curl -X GET -H 'Authorization: ******' -i https://analytics.volcengineapi.com/dataprofile/openapi/v1/760/items/your_item_name/185
Response-fields:
Field | Type | Description |
---|---|---|
code | int32 | 业务响应状态码 |
message | string | 业务响应状态信息 |
data | object | 属性值信息 |
data.appId | int64 | 应用id |
data.attributes | list | 具体信息 |
data.attributes.name | string | 属性名称 |
data.attributes.value | 根据注册类型而定 | 值信息 |
Response-example:
{ "code": 2000, "message": "success", "data": { "appId": 182463, "attributes": [ { "name": "storage", "value": 40 }, { "name": "price", "value": 22.66 }, { "name": "name", "value": "一次性医用口罩" }, { "name": "color", "value": "green" } ] } }
Operation | 说明 |
---|---|
SET | 为属性设置一个值 |
SET_ONCE | 属性不存在则设置 |
UNSET | 删除一个属性 |
INCREASE | 对数值类型的属性执行累加操作 |
APPEND | 在list类型的属性值里插入一个值 |
REMOVE | 在list类型的属性值里删除一个值 |
Error code | Description |
---|---|
2000 | success |
4000 | parameter error |
4010 | token authenticate fail |
5010 | not supported request |
5030 | request too frequency |
5000 | something wrong, please retry later |
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; public class AuthUtils { /** * @param ak accessKey * @param sk secretKey * @param expirationSeconds 过期时间,单位秒 * @param method 方法,GET, POST, PUT * @param path 请求的path,非完整的url(不需要域名,有查询参数的也不需要拼接上去) * @param queryString 请求参数, param1=value1¶m2=value2 * @param body 请求的json体 * @return */ public static String sign(String ak, String sk, int expirationSeconds, String method, String path, String queryString, String body) { String cm = canonicalMethod(method); String cu = canonicalUrl(path); String cp = canonicalQueryString(queryString); String cb = canonicalBody(body); String text = cm + "\n" + cu + "\n" + cp + "\n" + cb; return doSign(ak, sk, expirationSeconds, text); } private static String canonicalMethod(String method) { return "HTTPMethod:" + method; } private static String canonicalUrl(String url) { return "CanonicalURI:" + url; } private static String canonicalQueryString(String queryString) { String res = "CanonicalQueryString:"; if (queryString == null || queryString.isEmpty()) { return res; } return res + queryString; } private static String canonicalBody(String body) { String res = "CanonicalBody:"; if (body == null) { return res; } else { return res + body; } } private static String doSign(String ak, String sk, int expiration, String text) { String signKeyInfo = "ak-v1/" + ak + "/" + (int) (System.currentTimeMillis() / 1000) + "/" + expiration; String signKey = sha256Hmac(signKeyInfo, sk); String signResult = sha256Hmac(text, signKey); return signKeyInfo + "/" + signResult; } private static String sha256Hmac(String message, String secret) { String hash = ""; try { Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256"); sha256_HMAC.init(secret_key); byte[] bytes = sha256_HMAC.doFinal(message.getBytes()); hash = byteArrayToHexString(bytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return hash; } private static String byteArrayToHexString(byte[] b) { StringBuilder hs = new StringBuilder(); String stmp; for (int n = 0; b != null && n < b.length; n++) { stmp = Integer.toHexString(b[n] & 0XFF); if (stmp.length() == 1) { hs.append('0'); } hs.append(stmp); } return hs.toString().toLowerCase(); } }
import time import hashlib import hmac def _do_sign(ak, sk, expiration, text): sign_key_info = 'ak-v1/%s/%d/%d' % (ak, time.time(), expiration) sign_key = _sha256_hmac(sk, sign_key_info) sign_result = _sha256_hmac(sign_key, text) return '%s/%s' % (sign_key_info, sign_result) def _canonical_method(method): return "HTTPMethod:" + method def _canonical_url(url): return "CanonicalURI:" + url def _canonical_query_string(query_string): res = 'CanonicalQueryString:' if not query_string: return res return res + query_string def _canonical_body(body): res = "CanonicalBody:" if not body: return res return res + body def _sha256_hmac(key, data): return hmac.new(str.encode(key, 'utf-8'), str.encode(data, 'utf-8'), hashlib.sha256).hexdigest() def sign(ak, sk, expiration_seconds, method, uri_path, query_string, body): """ :param ak:accessKey :param sk:secretKey :param expiration_seconds:过期时间,单位秒 :param method:方法,GET, POST, PUT :param uri_path: 请求的path,非完整的url(不需要域名,有查询参数的也不需要拼接上去) :param query_string:请求参数, param1=value1¶m2=value2 :param body:请求的json体 :return: """ canonical_method = _canonical_method(method) canonical_url = _canonical_url(uri_path) canonical_param = _canonical_query_string(query_string) canonical_body = _canonical_body(body) text = '{}\n{}\n{}\n{}'.format(canonical_method, canonical_url, canonical_param, canonical_body) return _do_sign(ak, sk, expiration_seconds, text)
const crypto = require('crypto'); function hash(ak, sk, expiration_seconds, method, path, queryString, body) { const timestamp = (+new Date() / 1000).toFixed(0); const signKeyInfo = `ak-v1/${ak}/${timestamp}/${expiration_seconds}`; const signKey = sha256HMAC(sk, signKeyInfo); const data = canonicalRequest(method, path, queryString, body); const signResult = sha256HMAC(signKey, data); return signKeyInfo + '/' + signResult; } function sha256HMAC(sk, data) { const hmac = crypto.createHmac('sha256', sk) return hmac.update(data).digest('hex') } function canonicalRequest(method, url, queryString, body) { let cm = canonicalMethod(method); let cu = canonicalUrl(url); let cp = canonicalQueryString(queryString); let cb = canonicalBody(body); return cm + '\n' + cu + '\n' + cp + '\n' + cb; } function canonicalMethod(method) { return 'HTTPMethod:' + method; } function canonicalUrl(url) { return 'CanonicalURI:' + url; } function canonicalQueryString(queryString) { let res = 'CanonicalQueryString:' if (!queryString) { return res; } return res + queryString; } function canonicalBody(body) { res = "CanonicalBody:" if (!body){ return res; } return res + body; }
public class AuthGenDemo { //分配的accessKey和secretKey private static String accessKey = "****"; private static String secretKey = "****"; // 单位秒 private static Integer expirationSeconds = 300; public static void main(String[] args) { String method = "PUT"; String host = "https://analytics.volcengineapi.com"; // /dataprofile/openapi/v1/{appId}/items/{item_name}/{itemId} String path = "/dataprofile/openapi/v1/751/items/book/book01"; // 请求参数,对于没有请求参数的接口,在生成authorization code的时候对应的参数传null即可 HashMap<String, String> exampleQueryParams = new HashMap<>(); exampleQueryParams.put("set_once", "true"); String exampleQueryBodyJson = "{\"name\":\"name\",\"value\":\"zhangsan\"}"; String authorization = AuthUtils.sign(accessKey, secretKey, expirationSeconds, method, path, exampleQueryParams, exampleQueryBodyJson); System.out.println("authorization: " + authorization); String url = host + path; Map<String, String> headers = new HashMap<>(); headers.put("Authorization", authorization); JSONObject result = HttpUtil.put(url, exampleQueryBodyJson, exampleQueryParams, headers); System.out.println(result); } }
import auth_util import json import requests if __name__=="__main__": ak = "****" sk = "****" expiration_seconds = 300 method = "PUT" host = "https://analytics.volcengineapi.com" # /dataprofile/openapi/v1/{appid}/items/{itemname}/{itemId} path = "/dataprofile/openapi/v1/751/items/book/book01" # 请求参数,对于没有请求参数的接口,在生成authorization code的时候对应的参数传null即可 query_string = {"set_once": "true"} request_body = { "name": "name", "value": "zhangsan" } auth = auth_util.sign(ak, sk, expiration_seconds, method, path, query_string, json.dumps(request_body)) print(auth) headers = {"Authorization": auth} url = host + path print(requests.put(url, data=json.dumps(request_body), params=query_string, headers=headers).json())