概述
FeatureStore Java SDK 是人工智能平台(PAI)下特征平台(FeatureStore)的 Java 客户端 SDK,提供特征数据的高性能读取和写入。
适用场景
在线推理场景快速获取特征数据
实时特征写入与更新
序列特征读取
模型特征批量获取
前提条件
在使用 FeatureStore Java SDK 之前,请确保已完成以下准备工作:
已创建FeatureStore项目(Project)、特征实体(FeatureEntity)、特征视图(FeatureView)和模型特征(ModelFeature),并完成数据同步操作。具体操作,请参见配置FeatureStore项目。
已获取阿里云账户的AccessKey ID和AccessKey Secret。具体操作,请参见创建AccessKey。
快速开始
FeatureStore Java SDK地址见:https://github.com/aliyun/aliyun-pai-featurestore-java-sdk
在 pom.xml 中添加以下依赖:
<dependency>
<groupId>com.aliyun.openservices.aiservice</groupId>
<artifactId>paifeaturestore-sdk</artifactId>
<version>1.2.8</version>
</dependency>
初始化配置类Configuration(以region为cn-hangzhou为例)。
public class Constants {
public static String accessId = "";
public static String accessKey = "";
public static String username = "";
public static String password = "";
static {
accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
username = System.getenv("FEATUREDB_USERNAME");
password = System.getenv("FEATUREDB_PASSWORD");
}
} // 配置regionId、accessId、accessKey以及项目名称
Configuration configuration = new Configuration("cn-hangzhou",Constants.accessId,Constants.accessKey,"my_project");参数介绍
参数名 | 类型 | 必填 | 说明 | 示例值 |
regionId | String | 是 | 地域ID | cn-hangzhou |
accessKeyId | String | 否 | 阿里云账号 AccessKey ID | 从环境变量获取 |
accessKeySecret | String | 否 | 阿里云账号 AccessKey Secret | 从环境变量获取 |
projectName | String | 是 | FeatureStore 项目名称 | my_project |
username | String | FeatureDB 必填 | FeatureDB 用户名,仅在线数据源为 FeatureDB 时需配置 | 从环境变量获取 |
password | String | FeatureDB 必填 | FeatureDB 密码,仅在线数据源为 FeatureDB 时需配置 | 从环境变量获取 |
由于SDK是直连在线数据源,客户端需要在VPC环境运行。例如FeatureDB数据源一般在VPC环境连接进行数据访问,为了追求更好的性能也可以配置FeatureDB VPC网络高速连通,配置详情及性能对比测试参见:VPC网络高速连通。本地环境调试时可配置公网地址访问,参考示例如下:
configuration.setUsername(Constants.username);
configuration.setPassword(Constants.password);
//公网地址
configuration.setDomain("paifeaturestore.cn-hangzhou.aliyuncs.com");
// 初始化客户端,true(代表使用公网访问)
FeatureStoreClient featureStoreClient = new FeatureStoreClient(apiClient, true);读取功能
获取 FeatureView 特征数据
通过 FeatureView 获取在线特征数据,支持离线特征、实时特征和序列特征的读取。
接口说明
public FeatureResult getOnlineFeatures(String[] joinIds);
public FeatureResult getOnlineFeatures(String[] joinIds, String[] features, Map<String, String> aliasFields);
参数说明
参数名 | 类型 | 必填 | 说明 |
joinIds | String[] | 是 | join_id 值列表,用于查询特征数据 |
features | String[] | 否 | 需要返回的特征字段列表,不指定默认 |
aliasFields | Map<String, String> | 否 | 特征字段别名映射,返回数据时显示别名 |
示例
示例一:获取离线特征 FeatureView 的特征数据
获取 FeatureView 及离线表同步的数据
// 获取项目 Project project = featureStoreClient.getProject("my_project"); if (project == null) { throw new RuntimeException("Project not found"); } // 获取离线特征 FeatureView FeatureView offlineView = project.getFeatureView("user_features"); if (offlineView == null) { throw new RuntimeException("FeatureView not found"); } // 获取离线特征数据 FeatureResult offlineResult = offlineView.getOnlineFeatures( new String[]{"100001167", "100004088", "100006646"}, new String[]{"*"}, null );返回示例结果
[ { "user_id": 100001167, "gender": "male", "age": 28, "city": "沈阳市", "item_cnt": 0, "follow_cnt": 0, "follower_cnt": 0, "register_time": 1696658585, "tags": "2" }, { "user_id": 100004088, "gender": "female", "age": 28, "city": "长春市", "item_cnt": 0, "follow_cnt": 8, "follower_cnt": 0, "register_time": 1695618449, "tags": "1" } ]
示例二:获取实时特征 FeatureView 的特征数据
获取 FeatureView 及在线表的数据
// 获取实时特征 FeatureView FeatureView onlineView = project.getFeatureView("user_profile_view"); if (onlineView == null) { throw new RuntimeException("FeatureView not found"); } // 获取实时特征数据 FeatureResult onlineResult = onlineView.getOnlineFeatures( new String[]{"user_001", "user_002", "user_003"}, new String[]{"*"}, null );返回示例结果
[ { "user_id": "user_001", "user_nickname": "科技爱好者" }, { "user_id": "user_002", "user_nickname": "编程达人" }, { "user_id": "user_003", "user_nickname": "数据分析师" } ]
示例三:获取序列特征 FeatureView 的特征数据
获取 SequenceFeatureView 类型的序列特征数据
// 获取序列特征 View SequenceFeatureView seqFeatureView = project.getSeqFeatureView("user_seq_features"); if (seqFeatureView == null) { throw new RuntimeException("SequenceFeatureView not found"); } // 获取序列特征 FeatureResult seqResult = seqFeatureView.getOnlineFeatures( new String[]{"157843277", "157843278"} );返回示例结果
[ { "user_id": "157843277", "click_50_seq": "null;200167895", "click_50_seq_item_id": "null;200167895", "click_50_seq_event": "null;click", "click_50_seq_playtime": "null;15.0", "click_50_seq_event_time": "null;1704684504747", "click_50_seq_ts": "625662604;625662604" }, { "user_id": "157843278", "click_50_seq": "null;299049390", "click_50_seq_item_id": "null;299049390", "click_50_seq_event": "null;click", "click_50_seq_playtime": "null;32.15", "click_50_seq_event_time": "null;1698180365", "click_50_seq_ts": "1704292547792;1704292547792" } ]序列特征字段说明:返回数据字段格式为
{seq_name}_seq_{field}字段格式
说明
{seq_name}_seq行为序列主键列表,多个值用分号分隔
{seq_name}_seq_item_id序列中的物品ID列表
{seq_name}_seq_event序列中的事件类型列表(如 click、view)
{seq_name}_seq_playtime序列中的播放时长列表
{seq_name}_seq_event_time序列中的事件时间戳列表
{seq_name}_seq_ts序列时间戳列表
获取 ModelFeature 关联特征
通过 Model 获取关联的所有 FeatureEntity 特征数据,支持上级-下级 Entity 层级关系。
接口说明
// 获取所有根实体及其关联的下级实体特征
public FeatureResult getOnlineFeatures(Map<String, List<String>> joinIds);
// 获取指定 Entity 及其下级 Entity 特征
public FeatureResult getOnlineFeaturesWithEntity(Map<String, List<String>> joinIds, String featureEntityName);
参数说明
参数名 | 类型 | 必填 | 说明 |
joinIds | Map<String, List<String>> | 是 | joinIds的map集合。key为JoinId的名称,values为JoinId的值。 |
featureEntityName | String | 否 | 指定获取某个 FeatureEntity 的特征数据 |
Model 可关联多个 FeatureEntity,存在上下级嵌套关系:
* 上级 Entity:包含主特征字段 + 关联下级 Entity 的字段
* 下级 Entity:被上级 Entity 引用,包含独立的特征字段
获取特征时,只需传入根实体的 join_id,SDK 会自动根据上级实体的特征值获取下级实体的特征。
不同场景示例
场景1:获取 Model 关联的全部特征
调用 getOnlineFeatures 传入所有根实体的 join_id,SDK 自动获取 Model 关联的全部特征(包括下级实体)。
Model model = project.getModelFeature("model_fv1");
if (null == model) {
throw new RuntimeException("model not found");
}
// 传入所有根实体的 join_id
Map<String, List<String>> joinIds = new HashMap<>();
joinIds.put("item_id", Arrays.asList("1001", "1002", "1003"));
joinIds.put("user_id", Arrays.asList("U001", "U002", "U003"));
// 会一并获取所有根实体及其关联下级实体的特征
FeatureResult result = model.getOnlineFeatures(joinIds);
返回示例:
{
"item_id": "1001",
"item_title": "智能手表",
"item_price": 299.00,
"author_id": "A001",
"author_name": "张三",
"author_fans_count": 10000,
"category_id": "C001",
"category_name": "电子产品",
"category_level": 1,
"user_id": "U001",
"user_age": 28,
"user_gender": "male"
}
场景2:获取指定 Entity 侧特征(含下级实体)
调用 getOnlineFeaturesWithEntity 指定 Entity 名称,获取该 Entity 及其下级实体特征。示例中 item Entity 关联 author、category 两个下级实体,返回 item 侧全部特征。
Map<String, List<String>> joinIds = new HashMap<>();
joinIds.put("item_id", Arrays.asList("1001", "1002", "1003"));
// 指定获取 item Entity 的特征
// item侧关联下级实体 author、category,一并返回
FeatureResult result = model.getOnlineFeaturesWithEntity(joinIds, "item");
返回示例:
{
"item_id": "1001",
"item_title": "智能手表",
"item_price": 299.00,
"author_id": "A001",
"author_name": "张三",
"author_fans_count": 10000,
"category_id": "C001",
"category_name": "电子产品",
"category_level": 1
}
场景3:获取指定 Entity 侧特征(无下级实体)
调用 getOnlineFeaturesWithEntity 指定实体名称,获取该实体特征。示例中 author 实体无下级实体,只返回 author 本身的特征字段。
Map<String, List<String>> joinIds = new HashMap<>();
joinIds.put("author_id", Arrays.asList("A001", "A002", "A003"));
// 指定获取 author Entity 的特征
// author侧无下级实体,只返回 author侧特征
FeatureResult result = model.getOnlineFeaturesWithEntity(joinIds, "author");
返回示例:
{
"author_id": "A001",
"author_name": "张三",
"author_fans_count": 10000
}
ModelFeature 包含序列特征示例
当 ModelFeature 关联序列特征 FeatureView 时,返回数据中会包含序列特征字段:
Model model = project.getModelFeature("model_with_seq");
if (null == model) {
throw new RuntimeException("model not found");
}
Map<String, List<String>> joinIds = new HashMap<>();
joinIds.put("user_id", Arrays.asList("100001167", "100024146"));
joinIds.put("item_id", Arrays.asList("200138790", "200385417"));
FeatureResult result = model.getOnlineFeatures(joinIds);
返回示例:
[
{
"user_id": "100001167",
"gender": "male",
"age": 28,
"city": "沈阳市",
"item_id": "200138790",
"title": "#成语故事",
"click_count": 2,
"click_50_seq": "null;204153583",
"click_50_seq_item_id": "null;204153583",
"click_50_seq_event": "null;click",
"click_50_seq_playtime": "null;98.94",
"click_50_seq_ts": "1704292557212;1704292557212"
},
{
"user_id": "100024146",
"gender": "male",
"age": 28,
"city": "宁波市",
"item_id": "200385417",
"title": "#健身打卡",
"click_count": 4,
"click_50_seq": "null;299049390",
"click_50_seq_item_id": "null;299049390",
"click_50_seq_event": "null;click",
"click_50_seq_playtime": "null;32.15",
"click_50_seq_ts": "1704292547792;1704292547792"
}
]
写入功能
将特征数据实时写入 FeatureDB 数据源,支持实时特征和行为序列特征的写入。
适用场景
实时更新用户特征(如在线特征更新)
写入用户行为序列数据(点击、播放等事件)
实时特征数据的部分字段更新(不影响其他字段)
目前写入接口仅支持在线数据源为 FeatureDB 的实时特征视图和行为序列特征视图,初始化时需配置 FeatureDB 用户名和密码。
实时特征写入
整行更新
FeatureView featureView = project.getFeatureView("user_feature_view");
if (null == featureView) {
throw new RuntimeException("featureview not found");
}
// 构造写入数据
Map<String, Object> record = new HashMap<>();
record.put("user_id", "user_001");
record.put("name", "张三");
record.put("age", 28);
record.put("city", "北京");
featureView.writeFeatures(Arrays.asList(record));
featureView.writeFlush();
方法 | 参数 | 必填 | 说明 |
writeFeatures | List<Map<String,Object>> | 是 | 批量写入数据 |
writeFlush | - | - | 确保数据完成写入(调用后不能再写入) |
部分字段更新
List<Map<String, Object>> writeData = new ArrayList<>();
Map<String, Object> record = new HashMap<>();
record.put("user_id", "user_001");
record.put("name", "李四");
writeData.add(record);
// 默认整行替换,部分字段更新需指定 InsertMode
featureView.writeFeatures(writeData, InsertMode.PartialFieldWrite);
序列特征写入
序列特征写入用于实时记录用户行为事件(点击、播放、购买等),支持在线推理场景的行为序列特征构建。
示例
SequenceFeatureView sequenceFeatureView = project.getSeqFeatureView("sequence");
if (null == seqFeatureView) {
throw new RuntimeException("sequence feature view not found");
}
// 构造序列数据
List<Map<String, Object>> writeData = new ArrayList<>();
Map<String, Object> data = new HashMap<>();
data.put("request_id", 901850344);
data.put("user_id", "172040759");
data.put("page", "home");
data.put("net_type", "wifi");
data.put("day_h", 17);
data.put("week_day", 6);
data.put("event_unix_time", System.currentTimeMillis()/1000);
data.put("item_id", "223466789");
data.put("event","click");
data.put("playtime", 54.7296554003366);
writeData.add(data);
sequenceFeatureView.writeFeatures(writeData);
sequenceFeatureView.writeFlush();