Skip to content

Commit ca61c5a

Browse files
holtskinnercopybara-github
authored andcommitted
feat: add vertex_rag_source to create_feature_view method
PiperOrigin-RevId: 697000979
1 parent c5121da commit ca61c5a

File tree

11 files changed

+260
-17
lines changed

11 files changed

+260
-17
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START aiplatform_sdk_create_feature_view_from_rag_source]
16+
17+
from google.cloud import aiplatform
18+
from vertexai.resources.preview import feature_store
19+
20+
21+
def create_feature_view_from_rag_source(
22+
project: str,
23+
location: str,
24+
existing_feature_online_store_id: str,
25+
feature_view_id: str,
26+
bq_table_uri: str,
27+
):
28+
aiplatform.init(project=project, location=location)
29+
fos = feature_store.FeatureOnlineStore(existing_feature_online_store_id)
30+
fv = fos.create_feature_view(
31+
name=feature_view_id,
32+
source=feature_store.utils.FeatureViewVertexRagSource(uri=bq_table_uri),
33+
)
34+
return fv
35+
36+
37+
# [END aiplatform_sdk_create_feature_view_from_rag_source]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from feature_store import create_feature_view_from_rag_source
16+
import test_constants as constants
17+
18+
19+
def test_create_feature_view_from_rag_source_sample(
20+
mock_sdk_init,
21+
mock_get_feature_online_store,
22+
):
23+
create_feature_view_from_rag_source.create_feature_view_from_rag_source(
24+
project=constants.PROJECT,
25+
location=constants.LOCATION,
26+
existing_feature_online_store_id=constants.FEATURE_ONLINE_STORE_ID,
27+
feature_view_id=constants.FEATURE_VIEW_ID,
28+
bq_table_uri=constants.FEATURE_VIEW_BQ_URI,
29+
)
30+
31+
mock_sdk_init.assert_called_once_with(
32+
project=constants.PROJECT, location=constants.LOCATION
33+
)
34+
35+
mock_get_feature_online_store.assert_called_once()
36+
mock_get_feature_online_store.return_value.create_feature_view.assert_called_once_with(
37+
name=constants.FEATURE_VIEW_ID,
38+
source=constants.FEATURE_VIEW_RAG_SOURCE,
39+
)

samples/model-builder/test_constants.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@
264264
entity_id_columns=FEATURE_VIEW_BQ_ENTITY_ID_COLUMNS,
265265
)
266266
)
267+
FEATURE_VIEW_RAG_SOURCE = (
268+
vertexai.resources.preview.feature_store.utils.FeatureViewVertexRagSource(
269+
uri=FEATURE_VIEW_BQ_URI,
270+
)
271+
)
267272
FEATURE_VIEW_BQ_EMBEDDING_COLUMN = "embedding"
268273
FEATURE_VIEW_BQ_EMBEDDING_DIMENSIONS = 10
269274
FEATURE_VIEW_BQ_INDEX_CONFIG = (

tests/unit/vertexai/conftest.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
_TEST_FG1_F2,
6565
_TEST_FG1_FM1,
6666
_TEST_FV1,
67+
_TEST_FV3,
6768
_TEST_OPTIMIZED_EMBEDDING_FV,
6869
_TEST_OPTIMIZED_FV1,
6970
_TEST_OPTIMIZED_FV2,
@@ -432,6 +433,16 @@ def get_fv_mock():
432433
yield get_fv_mock
433434

434435

436+
@pytest.fixture
437+
def get_rag_fv_mock():
438+
with patch.object(
439+
feature_online_store_admin_service_client.FeatureOnlineStoreAdminServiceClient,
440+
"get_feature_view",
441+
) as get_rag_fv_mock:
442+
get_rag_fv_mock.return_value = _TEST_FV3
443+
yield get_rag_fv_mock
444+
445+
435446
@pytest.fixture
436447
def create_bq_fv_mock():
437448
with patch.object(
@@ -444,6 +455,18 @@ def create_bq_fv_mock():
444455
yield create_bq_fv_mock
445456

446457

458+
@pytest.fixture
459+
def create_rag_fv_mock():
460+
with patch.object(
461+
feature_online_store_admin_service_client.FeatureOnlineStoreAdminServiceClient,
462+
"create_feature_view",
463+
) as create_rag_fv_mock:
464+
create_rag_fv_lro_mock = mock.Mock(ga_operation.Operation)
465+
create_rag_fv_lro_mock.result.return_value = _TEST_FV3
466+
create_rag_fv_mock.return_value = create_rag_fv_lro_mock
467+
yield create_rag_fv_mock
468+
469+
447470
@pytest.fixture
448471
def create_embedding_fv_from_bq_mock():
449472
with patch.object(

tests/unit/vertexai/feature_store_constants.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,21 @@
155155
labels=_TEST_FV2_LABELS,
156156
)
157157

158-
_TEST_FV_LIST = [_TEST_FV1, _TEST_FV2]
158+
# Test feature view 3
159+
_TEST_FV3_ID = "my_fv3"
160+
_TEST_FV3_PATH = f"{_TEST_BIGTABLE_FOS1_PATH}/featureViews/my_fv3"
161+
_TEST_FV3_LABELS = {"my_key": "my_fv3"}
162+
_TEST_FV3_BQ_URI = f"bq://{_TEST_PROJECT}.my_dataset.my_table"
163+
_TEST_FV3 = types.feature_view.FeatureView(
164+
name=_TEST_FV3_PATH,
165+
vertex_rag_source=types.feature_view.FeatureView.VertexRagSource(
166+
uri=_TEST_FV3_BQ_URI,
167+
),
168+
labels=_TEST_FV3_LABELS,
169+
)
170+
171+
172+
_TEST_FV_LIST = [_TEST_FV1, _TEST_FV2, _TEST_FV3]
159173

160174
# Test feature view sync 1
161175
_TEST_FV_SYNC1_ID = "my_fv_sync1"

tests/unit/vertexai/test_feature_online_store.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
_TEST_FV1_ID,
4848
_TEST_FV1_LABELS,
4949
_TEST_FV1_PATH,
50+
_TEST_FV3_BQ_URI,
51+
_TEST_FV3_ID,
52+
_TEST_FV3_LABELS,
53+
_TEST_FV3_PATH,
5054
_TEST_LOCATION,
5155
_TEST_OPTIMIZED_EMBEDDING_FV_ID,
5256
_TEST_OPTIMIZED_EMBEDDING_FV_PATH,
@@ -63,6 +67,7 @@
6367
FeatureOnlineStore,
6468
FeatureOnlineStoreType,
6569
FeatureViewBigQuerySource,
70+
FeatureViewVertexRagSource,
6671
IndexConfig,
6772
TreeAhConfig,
6873
)
@@ -463,7 +468,9 @@ def test_create_fv_wrong_object_type_raises_error(get_fos_mock):
463468

464469
with pytest.raises(
465470
ValueError,
466-
match=re.escape("Only FeatureViewBigQuerySource is a supported source."),
471+
match=re.escape(
472+
"Only FeatureViewBigQuerySource and FeatureViewVertexRagSource are supported sources."
473+
),
467474
):
468475
fos.create_feature_view("bq_fv", fos)
469476

@@ -594,3 +601,81 @@ def test_create_embedding_fv(
594601
location=_TEST_LOCATION,
595602
labels=_TEST_FV1_LABELS,
596603
)
604+
605+
606+
def test_create_rag_fv_bad_uri_raises_error(get_fos_mock):
607+
aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION)
608+
fos = FeatureOnlineStore(_TEST_BIGTABLE_FOS1_ID)
609+
610+
with pytest.raises(
611+
ValueError,
612+
match=re.escape("Please specify URI in Vertex RAG source."),
613+
):
614+
fos.create_feature_view(
615+
"rag_fv",
616+
FeatureViewVertexRagSource(uri=None),
617+
)
618+
619+
620+
@pytest.mark.parametrize("create_request_timeout", [None, 1.0])
621+
@pytest.mark.parametrize("sync", [True, False])
622+
def test_create_rag_fv(
623+
create_request_timeout,
624+
sync,
625+
get_fos_mock,
626+
create_rag_fv_mock,
627+
get_rag_fv_mock,
628+
fos_logger_mock,
629+
):
630+
aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION)
631+
fos = FeatureOnlineStore(_TEST_BIGTABLE_FOS1_ID)
632+
633+
rag_fv = fos.create_feature_view(
634+
_TEST_FV3_ID,
635+
FeatureViewVertexRagSource(uri=_TEST_FV3_BQ_URI),
636+
labels=_TEST_FV3_LABELS,
637+
create_request_timeout=create_request_timeout,
638+
)
639+
640+
if not sync:
641+
fos.wait()
642+
643+
# When creating, the FeatureView object doesn't have the path set.
644+
expected_fv = types.feature_view.FeatureView(
645+
vertex_rag_source=types.feature_view.FeatureView.VertexRagSource(
646+
uri=_TEST_FV3_BQ_URI,
647+
),
648+
labels=_TEST_FV3_LABELS,
649+
)
650+
create_rag_fv_mock.assert_called_with(
651+
parent=_TEST_BIGTABLE_FOS1_PATH,
652+
feature_view=expected_fv,
653+
feature_view_id=_TEST_FV3_ID,
654+
metadata=(),
655+
timeout=create_request_timeout,
656+
)
657+
658+
fv_eq(
659+
fv_to_check=rag_fv,
660+
name=_TEST_FV3_ID,
661+
resource_name=_TEST_FV3_PATH,
662+
project=_TEST_PROJECT,
663+
location=_TEST_LOCATION,
664+
labels=_TEST_FV3_LABELS,
665+
)
666+
667+
fos_logger_mock.assert_has_calls(
668+
[
669+
call("Creating FeatureView"),
670+
call(
671+
f"Create FeatureView backing LRO: {create_rag_fv_mock.return_value.operation.name}"
672+
),
673+
call(
674+
"FeatureView created. Resource name: projects/test-project/locations/us-central1/featureOnlineStores/my_fos1/featureViews/my_fv3"
675+
),
676+
call("To use this FeatureView in another session:"),
677+
call(
678+
"feature_view = aiplatform.FeatureView('projects/test-project/locations/us-central1/featureOnlineStores/my_fos1/featureViews/my_fv3')"
679+
),
680+
]
681+
)

tests/unit/vertexai/test_feature_view.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
_TEST_FV2_ID,
4848
_TEST_FV2_LABELS,
4949
_TEST_FV2_PATH,
50+
_TEST_FV3_ID,
51+
_TEST_FV3_LABELS,
52+
_TEST_FV3_PATH,
5053
_TEST_FV_FETCH1,
5154
_TEST_FV_LIST,
5255
_TEST_FV_SEARCH1,
@@ -289,6 +292,14 @@ def test_list(list_fv_mock, get_fos_mock):
289292
location=_TEST_LOCATION,
290293
labels=_TEST_FV2_LABELS,
291294
)
295+
fv_eq(
296+
feature_views[2],
297+
name=_TEST_FV3_ID,
298+
resource_name=_TEST_FV3_PATH,
299+
project=_TEST_PROJECT,
300+
location=_TEST_LOCATION,
301+
labels=_TEST_FV3_LABELS,
302+
)
292303

293304

294305
def test_delete(delete_fv_mock, fv_logger_mock, get_fos_mock, get_fv_mock, sync=True):

vertexai/resources/preview/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
FeatureView,
4747
FeatureViewBigQuerySource,
4848
FeatureViewReadResponse,
49+
FeatureViewVertexRagSource,
4950
IndexConfig,
5051
TreeAhConfig,
5152
BruteForceConfig,
@@ -77,6 +78,7 @@
7778
"FeatureView",
7879
"FeatureViewBigQuerySource",
7980
"FeatureViewReadResponse",
81+
"FeatureViewVertexRagSource",
8082
"IndexConfig",
8183
"TreeAhConfig",
8284
"BruteForceConfig",

vertexai/resources/preview/feature_store/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
FeatureGroupBigQuerySource,
4242
FeatureViewBigQuerySource,
4343
FeatureViewReadResponse,
44+
FeatureViewVertexRagSource,
4445
IndexConfig,
4546
TreeAhConfig,
4647
BruteForceConfig,
@@ -58,6 +59,7 @@
5859
FeatureView,
5960
FeatureViewBigQuerySource,
6061
FeatureViewReadResponse,
62+
FeatureViewVertexRagSource,
6163
IndexConfig,
6264
IndexConfig,
6365
TreeAhConfig,

0 commit comments

Comments
 (0)