VertexAIのFeatureStoreの検証
昨年のアップデートからFeatureStoreがBQのデータをお手軽にアプリケーションに使えるようになった雰囲気なので検証してみる
BQでダミーデータを100万行用意
user_idとitem_idと特徴量列を2000個もつデータを用意
user_id: 1000件
item_id: 1000件
1000 * 1000 = の100万行
一方user単位でitemをまとめて取りたいケースのために次のような形式も保持
{
user_id: "user1"
item_ids: ["item1", "item2", ...],
feature1: [1, 1, ...],
feature2: [1, 1, ...],
...
}
なおfeature_timestampというtimestamp 列が必須
オンラインストアは最適化されたオンライン サービングで作成
コンソールからオンラインストアを用意はできるが、データの同期はコンソールから行えなくてAPIを叩かないといけない
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d "" \
"https://us-central1-aiplatform.googleapis.com/v1/projects/{project_id}/locations/us-central1/featureOnlineStores/dummy_feature2/featureViews/view_array:sync"
連携にかかった時間は1000行で3分30分ほど、100万行で16分ほど
1000万行オーダーになったらだいぶきつそう
クライアントの作り方
endpoint urlというのを手に入れる必要があるがコンソールのどこにもないので次の方法で取ってくる
curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://us-central1-aiplatform.googleapis.com/v1/projects/{project_id}/locations/us-central1/featureOnlineStores/dummy_feature2"
次のような形で帰ってくる
{
"name": "projects/{project_id}/locations/us-central1/featureOnlineStores/dummy_feature2",
"createTime": "2024-12-14T13:43:58.910135Z",
"updateTime": "2024-12-14T13:43:59.552548Z",
"etag": "...",
"state": "STABLE",
"dedicatedServingEndpoint": {
"publicEndpointDomainName": "..."
},
"optimized": {}
}
リージョンまたぎでアクセスするレイテンシーが重そうだったのでGCPのcolabからレイテンシーを計測
そしたらlocustがうまく使えなかったので同時接続を1としてforで計測
domain_name = f"{上のpublicEndpointDomainName}"
data_client = FeatureOnlineStoreServiceClient(
client_options={"api_endpoint": domain_name}
)
elapsed = []
with open("user_ids.csv", "r") as f:
data = f.read().split("\n")[1:]
for i in range(1000):
start = time.time()
i = int(random.random() * 1000)
u = data[i]
data_client.fetch_feature_values(
request=feature_online_store_service_pb2.FetchFeatureValuesRequest(
feature_view=f"projects/{project_id}/locations/us-central1/featureOnlineStores/dummy_feature2/featureViews/view_array",
data_key=feature_online_store_service_pb2.FeatureViewDataKey(key=u),
)
)
elapsed.append(time.time() - start)
なお、キーが複数ある場合は
feature_online_store_service_pb2.FeatureViewDataKey(composite_key=feature_online_store_service_pb2.FeatureViewDataKey.CompositeKey(parts=["key1", "key2"]))
のようにするととれる
結果(単位は秒)
mean: 0.10111656045913696
50%: 0.09744226932525635
95% quantile: 0.14301396608352657
99% quantile: 0.15858708620071407
データ件数的には1000件 * 2002列取ってきているので可もなく不可もなくという時間(これは上記の通りアレイで一つのレコードにまとめているので一つのキーで取ってこれている
なお1件だけとってきたときは平均0.01秒ほどだったのでそこそこの速さと思いつつ推薦での用途では複数item同時にとってきたいのでやっぱちょっと遅いのでは...とは思う
コスト
7日間で22,000円
一か月で10万弱はほぼspannerとかbigtableのような高級DBと同等のコスト