如果您需要通过维度数据扩展事件分析的数据范围,您需要在定义好数据分析所需的业务维度信息后,将相关的业务维度数据和行为数据一起接入DataFinder,相关数据成功上报后,您即可在DataFinder中查询分析维度数据。本文为您介绍在SaaS-非云原生环境中,业务维度数据接入流程和相关OpenAPI的使用指导。
注意
本文档仅针对SaaS-非云原生版本,不针对SaaS云原生版本和私有化版本;SaaS云原生版本和私有化版本接入请参考HTTP API文档中的6. 上报业务对象属性模块。
在进行业务维度数据接入前,您需要先根据业务情况,规划好需要分析的业务维度有哪些、每个业务维度需要有哪些属性,并在DataFinder的数据管理中创建好对应的业务维度。后续数据接入的业务维度和属性数据需与已添加的业务维度信息保持一致。添加业务维度的操作请参见业务维度。
该功能默认可以使用,但是上报item数据需要使用ak/sk,您可以通过页面右下角的工单功能或者联系您的客户成功经理告诉我们您要使用业务维度(Item)
功能。我们会将上报数据所需的 ak/sk 发送到您指定的邮箱。
在完成了业务维度创建和准备工作后,您可参考下文进行数据接入的配置,主要有两个环节:
**1)配置上报item的属性:**参考本文的 API 配置上报至DataFinder的 业务维度属性。
**2)配置item数据与事件数据关联:**配置业务维度数据和事件数据的关联规则,后续在上报事数据时,会根据配置的规则自动进行业务维度数据关联。
完成前提条件和准备工作后,您可以参考下文的API调用详情,进行接口调用完成数据接入的配置。
您需要调用属性值操作接口,配置需要上报的item id和其他属性,有多个属性时可使用多属性批量处理接口。
注意
使用OpenAPI配置数据接入时,相关属性的数据类型一定要满足数据格式要求,类型错误的数据会被丢弃。数据格式要求请参见支持的数据格式与事件/属性分类。
创建好的 item 对象需要与事件关联才可以使用。您需要在配置数据接入时,同时配置好业务维度和事件数据的关联规则,即将某一个或多个具体item的item id 值配置到事件的预置属性params.__items
当中,详细操作请参见HTTP API。
注意
SaaS场景下一个事件当前可最多支持三个item。
下列示例代码演示了将 sku 和 order 两个创建好的业务维度与事件 new_order 进行关联的方式。__items
为事件预置属性,仅用于上报业务维度。
示例如下:
... "event": "new_order", "params": { "__items": "[{\"sku\":[{\"id\":\"sku_id_1\"},{\"id\":\"sku_id_2\"}]},{\"order\":[{\"id\":\"order_id_1\"},{\"id\":\"order_id_2\"}]}]", ... }, ...
__items
是转为 string
的 json
对象,其格式为:
[ {"item_name_1": [ {"id": "id_value_1"}, {"id": "id_value_2"}, ... ]}, {"item_name_2": [ {"id": "id_value_1"}, {"id": "id_value_2"}, ... ]} ]
item_name_1
就是在上一步中定义的业务维度名称
,例如order;id_value_1
、id_value_2
即为item id的取值,例如订单号id1、订单号2。
注意
如果事件数据上时,item数据没有被定义(即没有在数据管理中添加业务维度),则关联关系不生效,则无法正常使用item分析。
当已经完成数据上报,并且属性没有被禁用的情况下。就可以在属性筛选、分组等处使用这些属性了。针对业务维度,我们还提供了业务维度分析
功能,可以以业务维度为主体进行分析。业务维度数据分析的操作指导详情请参见业务维度分析。
通过提供AccessKey/SecretKey的方式鉴权,简写为ak/sk。
注意
AccessKey是app请求的唯一标识,SecretKey是app的密钥,它们相当于用户名和密码。在DataFinder上接入一个应用(app)之后就会生成一个AccessKey和SecretKey,您需要联系火山引擎技术支持人员获取对应的ak/sk,获取后请妥善保存。
在所有请求的header中包括如下鉴权信息:
Header | Type | Description | Required |
---|---|---|---|
Authorization | string | api鉴权使用(Global) | TRUE |
国内: 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 | item名称 | TRUE |
item_id | string | item的id属性的取值。您可以自定义item id取值,取值结果会在后续数据上报时上报至对应item的id属性中。 | TRUE |
注意
其中的item_name 以及 item_id 需要满足规则:一个或多个字母、数字、下划线(_)或连字符(-)的组合,且item_name至少三个字符。
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/3**/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可选值见下文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可选值见下文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:
Parameter | Type | Description | Required |
---|---|---|---|
app_id | int64 | app_id | TRUE |
item_id | string | item的唯一id | TRUE |
item_name | string | 注册的item的名称 | TRUE |
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类型的属性值里删除一个值 |
注:请先确认您所在环境的item对象是否支持list类型属性,确认支持方可使用append和remove操作。
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) { let 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())