1. 概述

虚拟属性是指对普通属性进行二次加工或上传维度字典,创建出的一个新属性。还可以通过建立维度关联关系,引入其它扩展属性来创建虚拟属性。

在当前表创建虚拟属性时,可引用的属性范围为:当前表的普通属性、与当前表建立了维度关联关系的数据表里的属性。

本文档所描述的内容属于神策分析的高级使用功能,涉及较多技术细节,适用于对相关功能有经验的用户参考。

2. 创建虚拟属性

  1. 依次选择 数据融合 > 元数据管理 > 用户表/事件表 > 虚拟属性
  2. 点击右上角的 创建虚拟属性 按钮。
  3. 填写 属性名。必填。属性名是属性在系统内的唯一标识。不能超过 100 个字符,以英文开头,默认仅支持大小写字母、数字、下划线、不支持其他字符,不能与预留字段名相同。同一张表内,属性名不能重名(包括普通属性)。
  4. 填写 属性显示名。必填。属性在使用过程中的显示名称。不能为空,不能超过 100 个字符或汉字,同一张表内属性显示名不能重名(包括普通属性)。
  5. 选择 可用该属性的事件。只有在创建 事件 的虚拟属性时需要设置,如果是 用户 的虚拟属性,默认所有的事件均可使用此虚拟属性。支持两种方式:
    1. 涵盖 SQL 表达式中至少一个属性的元事件
    2. 涵盖 SQL 表达式中所有属性的元事件
  6. 选择 数据类型。必选。只支持 <字符串 String>、<数值 Number>、<布尔 Bool>、<日期时间 Datetime>、<集合 List> 数据类型。
  7. 添加 虚拟属性计算逻辑。确定虚拟属性的值有 3 种方式:
    1. 使用 SQL 确定虚拟属性的值:在 属性引用语法 中填写对属性加工的 SQL 表达式片段,即可完成一个虚拟属性的创建。注意事项如下:
      1. 创建虚拟属性时,SQL 表达式的最大长度为 4096 个字符。
      2. 事件表中的 time 和 event 属于特殊字段,目前支持对 time 字段二次加工,具体可参考下述应用场景。不支持对 event 字段二次加工提取虚拟属性。
      3. 引用当前表下的普通属性,格式是 表名.表属性名,如 events.product_id ;引用已建立 维度关联关系 的数据表里的属性,格式是 表别名.表属性名,如 product.product_price。
    2. 从普通属性复制一个值:上传字典的普通属性,再上传字典文件,点击保存。只支持对 <字符串 String>、<数值 Number>、<布尔 Bool> 类型且数据来源不为 标签 的属性上传字典。
      1. 在神策分析 3.0 及以上版本,不支持对普通属性直接上传维度字典。如果您有此类需求,可通过本功能实现。
      2. 后续在分析模型中使用时,如果想使用原值,就选择原普通属性;如果想使用字典值,就选择上述创建的虚拟属性。
    3. 从普通属性解析获取对应值:为支持更多业务场景的数据上报和分析诉求,事件虚拟属性支持对象数组类型,可以将传值为 JSON 数组的事件属性解析成多个子属性,从而在后续分析过程中使用。
      1. 注意:仅事件虚拟属性支持此种创建方式。
      2. 使用步骤:
        1. 对 <字符串 String> 类型的普通属性上报数据,传值为 JSON 数组。
        2. 创建 <对象数组 ObjectArray> 类型的虚拟属性,创建方式为「从普通属性解析获取对应值」,选择上面的普通属性,解析为子属性。
        3. 分析时,可使用创建出的虚拟属性及其子属性进行筛选操作。
      3. 场景示例:电商行业购买商品下单时包含的商品名称、商品类别、订单金额等信息,可以通过 JSON 存储到一个 <字符串 String> 类型的普通属性 order_detail 中,后续再解析成对象数组类型的虚拟属性。
      4. JSON 数据示例:
        "distinct_id": "12345",
        "event_name": "pay_order"
        "time": 1437280200354,
        "order_detail":"[{\"product_name\":\"iPhone 13\", \"product_price\": 5000,\"product_type\": \"手机\", \"cnt\": 3, \"order_price\": 15000},{\"product_name\":\"switch\", \"product_price\": 2000, \"product_type\": \"游戏\",\"cnt\": 1, \"order_price\": 2000},{\"product_name\":\"macbookpro\", \"product_price\": 9000, \"product_type\": \"电脑\", \"cnt\": 1, \"order_price\": 9000},{\"product_name\":\"iphone 14\", \"product_price\": 6000, \"product_type\": \"手机\", \"cnt\": 1, \"order_price\": 6000}]"
        CODE
      5. 分析场景示例:创建出的对象数组类型的虚拟属性可以在事件分析等模块中使用,实现了一些之前不支持的分析场景,如:
        1. 订单中包含「手机」类商品且商品价格大于「5000」的下单次数
        2. 订单中包含「switch」且购买数量大于「1」的下单次数
  8. 填写 单位/格式备注。选填。长度限制 16 个字符以内。
  9. 填写 属性示例/说明。选填。长度限制 200 个字符以内。
  10. 点击 提交 按钮。

创建虚拟属性时,支持哪些字段,以及字段的必填选填由 字段显示配置 控制。

3. 管理虚拟属性

在虚拟属性列表页中,可以对已创建的虚拟属性进行搜索、筛选、排序,以及查看、编辑、删除、启用/禁用等操作。

3.1. 虚拟属性列表页

支持对虚拟属性进行搜索、筛选、排序等。

3.2. 编辑虚拟属性

在属性列表中,点击 操作 列中的 编辑 按钮,即可编辑虚拟属性,属性名、数据类型不支持编辑。

3.3. 启用/禁用虚拟属性

在属性列表中,点击 操作 列中的 禁用/启用 按钮,即可 禁用/启用 虚拟属性,禁用属性后,在标签分群、神策分析、智能运营等应用中,各类下拉组件中都不再展示该属性,之前引用该属性创建出的资源也会不可用。

4. 常见使用场景

4.1. 属性计算

举例 1:假设埋点的时候埋了两个事件属性:<商品标价 commodity_price> 和 <成交的最终价格 final_price>,均为数值类型,当我们想判断商品标价与最终价格的差值时我们可以直接创建一个新的虚拟事件属性 <净收入 Net Income>。此时,我们可以使用 加减乘除运算。

SQL 表达式:events.commodity_price - events.final_price

举例 2:我们需要基于已有属性,需要对 理财产品的本息总和 进行计算。此时,我们可以使用 幂次函数

SQL 表达式:events.capital + events.capital * pow(events.rate_of_interest, events.duration)

4.2. 属性抽取

举例 1:例如我们现在有一个事件属性是 $url,希望从 $url 中抽取出 q= 的属性,作为 search_keyword 来进行分析,那么我们可以使用以下表达式创建一个新的虚拟事件属性。

SQL 表达式:parse_url(events.$url, 'QUERY', 'q')

parse_url: 解析 URL,通过指定 URL 中的特定部分返回截取值。可指定要截取的值为 PROTOCOL、HOST、PATH、REF、AUTHORITY、FILE、USERINFO、QUERY。正常我们只需要输入指定的 URL 以及需要截取的部分两个参数, 特殊的当要截取的部分为 QUERY 时, 我们可以输入第三个参数指定 QUERY 键值对中的 KEY,获取指定参数值。

举例 2:例如我们有一个自定义事件属性 error_info_map(字符串类型),上报内容为 JSON 字符串,示例:

error_info_map: '{\"error\": {\"reason\": \"timeout\", \"code\": 3001}}'
JS

希望从这个 JSON 字符串中解析出 reason 的值,作为属性来进行分析,那么我们可以使用以下表达式创建一个新的虚拟属性:

SQL 表达式:GET_JSON_OBJECT(events.error_info_map, '$.error.reason')

GET_JSON_OBJECT:从 JSON 字符串中按照给定的 JSON 选择器解析出 JSON 对象中的值,得到的值为字符串类型。(GET_JSON_OBJECT Impala 官方文档

如果给定的字符串不符合 JSON 格式,或者 JSON 选择器没有匹配到值,则会返回 NULL。

JSON 选择器中支持下列操作符:

  • $:标识根节点
  • .:标识取子节点
  • []:标识数组的取值下标
  • *:标识数组或子节点的通配符

关于 JSON 选择器请参考官方文档

4.3. 属性合并

假设我们在埋点的时候埋了两个属性:item_id 和 item_id_1,但实际上它们是一个含义,希望在使用的时候进行合并,也可以使用虚拟属性功能来定义。

SQL 表达式:coalesce(events.item_id, events.item_id_1)

coalesce 是一个标准 SQL 函数,返回所有参数中第一个非 NULL 的值,这样我们在使用的时候只要使用 new_item_id 来进行分析就可以达到属性合并的目的。

4.4. 联合去重

在神策分析中,我们支持对某个属性进行去重数的计算,但是不直接支持对两个或者更多的属性进行去重。如果有这类需求,也可以使用虚拟属性的方式来实现,即定义一个新的属性,它的值是需要去重的多个属性的组合。

例如,我们想计算不同用户浏览不同商品的去重次数(即一个用户浏览同一个商品不重复计数,但是浏览不同的商品需要计数),那么可以定义一个虚拟属性如下:

SQL 表达式:concat(cast(events.user_id as string), events.product_id)

concat: 联合去重, 把所有string类型的参数连接成一个string类型。

4.5. 高精度小数

默认情况下,神策分析的 NUMBER 类型只支持小数点之后 3 位,如果需要支持高精度类型,可将属性以字符串类型上报给神策,再创建 NUMBER 类型的高精度小数虚拟属性。

将需要支持高精度的内容以字符串的类型来发送给神策分析,以避免精度丢失。此时我们可以通过虚拟属性将此字符串转化为一个高精度类型的虚拟属性。

SQL 表达式:cast(events.big_number as decimal(38,16))

注:不允许上传空字符串,否则自定义查询时无法使用 select * ,也无法使用「数据校验」工具

4.6. 校验数据

神策支持创建一个 Bool 类型的属性与正则表达式来校验某个属性值的数据质量。表达式示例如下:

SQL 表达式:cast ( case when regexp_like(users.user_name, '[a-zA-Z0-9._ //-//[//](){}]{1,15}') then 1 else 0 end as bigint)

regexp_like(string source, string pattern[, string options]) : 判断 source 字符串中是否包含以 pattern 为正则表达式的内容

4.7. 时间日期再加工

在用到时间日期函数, 只有 TIMESTAMP 类型可以直接使用 Impala 的时间日期函数, 所以如果当 Date/Datetime 类型的属性作为时间日期函数的参数时, 我们需要先使用 EPOCH_TO_TIMESTAMP 函数将属性转换为 TIMESTAMP 类型.

举例 1:需要使用每个事件的发生时间,作为分组项来分析数据,或需要在权限中限制某些角色,只可以授权仅可访问 近 N 天的数据 时。那么我们需要基于 event 中的 time 创建一个新的虚拟事件属性,应用在 分析模型 角色-数据权限 中。

SQL 表达式:UNIX_TIMESTAMP(events.time)*1000

举例 2:默认情况下,神策分析支持天、周、月等时间聚合方式,如果想要其它的时间聚合方式,也可以使用虚拟属性实现。例如,如果想要按照 "周X" 来对数据进行分析,可以从 time 属性中提取出一个 day_of_week 的属性:

SQL 表达式:dayofweek(EPOCH_TO_TIMESTAMP(events.register_time))

dayofweek: 函数求得的数值,1 表示星期天,7 表示星期六,2-6 表示星期一至星期五。类似的,也可以用 extract(hour from time) 表达式来提取时间中的小时部分。

举例 3:神策支持使用 users 表中的用户属性提取虚拟属性,比如根据用户属性 Birthday ,得到用户的年龄属性。创建 虚拟用户属性 后,使用此表达式即可。

SQL 表达式:cast (extract(year FROM now()) -extract(year FROM EPOCH_TO_TIMESTAMP(users.Birthday)) as int)

extract: 从 TIMESTAMP 值中截取数值型的时间域,例如年度,月份,日期,小时,分钟,秒/微秒(year,month,day,hour,minute,second,millisecond), 返回时间域的整数值.

注:不支持使用 user 表中的用户属性和维度表、事件表中的事件属性进行关联。

更多表达式参考

  • adddate: 在一个 TIMESTAMP 值上加一个给定的天数

    SQL 表达式:adddate(EPOCH_TO_TIMESTAMP(users.birthday), INT/BIGINT days)

  • datediff : 返回两个时间戳间隔天数

    SQL 表达式:datediff(EPOCH_TO_TIMESTAMP(events.enddata), EPOCH_TO_TIMESTAMP(events.startdate))

4.8. 数据类型转换

举例 1:创建 <日期时间 Datetime> 类型的虚拟属性

创建日期时间类型的虚拟属性,则要求:虚拟属性表达式的结果是 bigint 类型的时间戳,并设置虚拟属性类型为 <日期时间 Datetime> 类型。

例如,原本记录了一个 oldtimestamp 是数值类型,存储的是时间戳,为了便于分析,可以使用虚拟属性来新建一个 <日期时间 Datetime> 类型的属性方便进行日期比较的分析。如果是关联维度表再设置虚拟属性,那么要求关联的维度表里存储的就是时间戳。

SQL 表达式:cast(events.oldtimestamp as bigint)

举例 2:创建 <布尔 Bool> 类型的虚拟属性

创建布尔类型的虚拟属性,则要求:虚拟属性表达式的结果是 bigint 类型且值为 0、1 ,并设置虚拟属性类型为 <布尔 Bool> 类型。

例如,针对所有的支付记录区分是否为有效支付,可创建 是否有效支付 虚拟属性。若订单支付金额值为 0 或者 null,虚拟属性取值 ;若支付金额为其他情况,虚拟属性取值

SQL 表达式:cast((case when (events.ActualPaidAmount is null or events.ActualPaidAmount=0) then '0' else '1' end) as bigint)

5. 校验规则与常见错误

  • 涉及到两个属性的数值计算时必须保证两个属性数据类型相同;

  • <数值 Number> 类型的虚拟属性运算符号两边必须是数字运算数字;

  • 数据类型与 SQL 表达式返回值必须保持一致;
  • 创建虚拟属性后,不允许再上报相同名字的普通属性;
  • 引用当前表下的普通属性,格式必须是 表名.属性名,如 events.product_price;
  • 不支持 引用数据来源为 标签 的普通属性;
  • 如需引用已经建立 维度关联关系 的数据表里的字段,格式必须是 表别名.列名 ,如事件表关联了商品表,为商品表取别名为 commodity,需要使用商品表里的字段 manufacturer 创建事件虚拟属性,那么应该输入 commodity.manufacturer。

6. 权限

拥有 查看主表查看事件表 权限,则可进入对应页面查看虚拟属性。

拥有 管理主表管理事件表 权限,则可对用户表、事件表的虚拟属性进行管理。