You need to enable JavaScript to run this app.
导航
业务维度(item)数据接入(SaaS-非云原生版)
最近更新时间:2024.05.30 12:00:48首次发布时间:2024.04.30 15:17:27

如果您需要通过维度数据扩展事件分析的数据范围,您需要在定义好数据分析所需的业务维度信息后,将相关的业务维度数据和行为数据一起接入DataFinder,相关数据成功上报后,您即可在DataFinder中查询分析维度数据。本文为您介绍在SaaS-非云原生环境中,业务维度数据接入流程和相关OpenAPI的使用指导。

注意

本文档仅针对SaaS-非云原生版本,不针对SaaS云原生版本和私有化版本;SaaS云原生版本和私有化版本接入请参考HTTP API文档中的6. 上报业务对象属性模块。

使用限制
  • 本文档涉及的上报和查询 OpenAPI 接口均采用 Restful API 规范,且API使用QPS上限为500。
  • 接入业务维度(item)数据时,需将业务维度数据与事件数据进行关联,SaaS场景下,当前一个事件可最多支持三个item。

数据接入流程

前提条件

在进行业务维度数据接入前,您需要先根据业务情况,规划好需要分析的业务维度有哪些、每个业务维度需要有哪些属性,并在DataFinder的数据管理中创建好对应的业务维度。后续数据接入的业务维度和属性数据需与已添加的业务维度信息保持一致。添加业务维度的操作请参见业务维度

准备工作:获取ak/sk

该功能默认可以使用,但是上报item数据需要使用ak/sk,您可以通过页面右下角的工单功能或者联系您的客户成功经理告诉我们您要使用业务维度(Item)功能。我们会将上报数据所需的 ak/sk 发送到您指定的邮箱。

配置数据接入

在完成了业务维度创建和准备工作后,您可参考下文进行数据接入的配置,主要有两个环节:
**1)配置上报item的属性:**参考本文的 API 配置上报至DataFinder的 业务维度属性。
**2)配置item数据与事件数据关联:**配置业务维度数据和事件数据的关联规则,后续在上报事数据时,会根据配置的规则自动进行业务维度数据关联。

(1)配置上报item的属性

完成前提条件和准备工作后,您可以参考下文的API调用详情,进行接口调用完成数据接入的配置。
您需要调用属性值操作接口,配置需要上报的item id和其他属性,有多个属性时可使用多属性批量处理接口

注意

使用OpenAPI配置数据接入时,相关属性的数据类型一定要满足数据格式要求,类型错误的数据会被丢弃。数据格式要求请参见支持的数据格式与事件/属性分类

(2)配置item数据与事件数据关联

创建好的 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 是转为 stringjson 对象,其格式为:

[
    {"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_1id_value_2即为item id的取值,例如订单号id1、订单号2。

注意

如果事件数据上时,item数据没有被定义(即没有在数据管理中添加业务维度),则关联关系不生效,则无法正常使用item分析。

后续步骤:业务维度数据分析

当已经完成数据上报,并且属性没有被禁用的情况下。就可以在属性筛选、分组等处使用这些属性了。针对业务维度,我们还提供了业务维度分析功能,可以以业务维度为主体进行分析。业务维度数据分析的操作指导详情请参见业务维度分析

API调用详情

鉴权

通过提供AccessKey/SecretKey的方式鉴权,简写为ak/sk。

注意

AccessKey是app请求的唯一标识,SecretKey是app的密钥,它们相当于用户名和密码。在DataFinder上接入一个应用(app)之后就会生成一个AccessKey和SecretKey,您需要联系火山引擎技术支持人员获取对应的ak/sk,获取后请妥善保存。

在所有请求的header中包括如下鉴权信息:

Header

Type

Description

Required

Authorization

string

api鉴权使用(Global)

TRUE

API用法

域名

国内: 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"
}

item 属性查询接口

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取值说明

Operation

说明

SET

为属性设置一个值

SET_ONCE

属性不存在则设置

UNSET

删除一个属性

INCREASE

对数值类型的属性执行累加操作

APPEND

在list类型的属性值里插入一个值

REMOVE

在list类型的属性值里删除一个值

注:请先确认您所在环境的item对象是否支持list类型属性,确认支持方可使用append和remove操作。

示例代码

鉴权生成工具

Java (AuthUtil.class)

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&param2=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();
    }
}

Python (auth_util.py)

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&param2=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)

Js

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;
}

Authorization代码示例

Java

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);
    }
}

Python

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())