Open6

VertexAIのFeatureStoreの検証

rtanakartanaka

昨年のアップデートからFeatureStoreがBQのデータをお手軽にアプリケーションに使えるようになった雰囲気なので検証してみる

rtanakartanaka

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 列が必須
rtanakartanaka

オンラインストアは最適化されたオンライン サービングで作成

コンソールからオンラインストアを用意はできるが、データの同期はコンソールから行えなくて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万行オーダーになったらだいぶきつそう

rtanakartanaka

クライアントの作り方

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"]))
のようにするととれる

rtanakartanaka

結果(単位は秒)

mean:  0.10111656045913696 
50%:  0.09744226932525635 
95% quantile:  0.14301396608352657 
99% quantile:  0.15858708620071407

データ件数的には1000件 * 2002列取ってきているので可もなく不可もなくという時間(これは上記の通りアレイで一つのレコードにまとめているので一つのキーで取ってこれている
なお1件だけとってきたときは平均0.01秒ほどだったのでそこそこの速さと思いつつ推薦での用途では複数item同時にとってきたいのでやっぱちょっと遅いのでは...とは思う

rtanakartanaka

コスト
7日間で22,000円

一か月で10万弱はほぼspannerとかbigtableのような高級DBと同等のコスト