Skip to content

feat: Vector Index & Columnar Engine Optimizations - #621

Open
madamsetty-pavan wants to merge 11 commits into
googleapis:mainfrom
madamsetty-pavan:feat/vector-optimizations
Open

feat: Vector Index & Columnar Engine Optimizations#621
madamsetty-pavan wants to merge 11 commits into
googleapis:mainfrom
madamsetty-pavan:feat/vector-optimizations

Conversation

@madamsetty-pavan

Copy link
Copy Markdown

Part 1 of 3 for AlloyDB AI Features Epic. Contains Vector Optimizations including ScaNN and Columnar Engine.

@madamsetty-pavan
madamsetty-pavan requested review from a team as code owners July 15, 2026 21:51
@product-auto-label product-auto-label Bot added the api: alloydb Issues related to the googleapis/langchain-google-alloydb-pg-python API. label Jul 15, 2026
@madamsetty-pavan
madamsetty-pavan marked this pull request as draft July 15, 2026 22:00
@madamsetty-pavan
madamsetty-pavan marked this pull request as ready for review July 22, 2026 04:35

@dishaprakash dishaprakash left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add functional tests that use the live database?
We can use fixtures to setup and teardown to bring them to original states.

Comment thread src/langchain_google_alloydb_pg/async_vectorstore.py Outdated
Comment thread src/langchain_google_alloydb_pg/async_vectorstore.py Outdated
Comment thread src/langchain_google_alloydb_pg/async_vectorstore.py Outdated
Comment thread src/langchain_google_alloydb_pg/engine.py
Comment thread src/langchain_google_alloydb_pg/vectorstore.py Outdated
Comment thread tests/test_async_vectorstore.py Outdated
@madamsetty-pavan

Copy link
Copy Markdown
Author

Done. Added live database functional tests using setup and teardown fixtures:

  • test_aapply_alloydb_scann_index_auto_mode in test_vectorstore_index.py / test_async_vectorstore_index.py to create, validate, and drop ScaNN AUTO mode indexes on live AlloyDB instances.
  • test_live_columnar_engine, test_live_auto_columnarization, and test_live_vector_assist in test_vectorstore.py / test_async_vectorstore.py to test columnar engine and vector assist against live AlloyDB instances.

@twishabansal

Copy link
Copy Markdown
Contributor

/gcbrun

1 similar comment
@twishabansal

Copy link
Copy Markdown
Contributor

/gcbrun

@twishabansal

Copy link
Copy Markdown
Contributor

Please fix the integration tests

params = []
if self.pct_leaves_to_search is not None:
params.append(f"scann.pct_leaves_to_search = {self.pct_leaves_to_search}")
if self.num_leaves_to_search is not None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScaNNQueryOptions() with no arguments used to emit scann.num_leaves_to_search = 1. After this change it emits scann.pct_leaves_to_search = 1 instead. T

hose aren't equivalent: one is an absolute leaf count, the other a proportion: so existing users get different recall/latency on upgrade with no error or warning. Could we keep num_leaves_to_search: int = 1 as the default and emit pct_leaves_to_search only when the user sets it? If the default change is intentional, it should be called out as a breaking change in the changelog.


def index_options(self) -> str:
"""Set index query options for vector store initialization."""
if self.mode and self.mode.upper() == "AUTO":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should we add a validation here? If mode is not auto, it should emit a warning

text(query),
{
"model_id": model_id,
"table_name": self.table_name,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be adding a schema_name arg here as well? Vectorstore does support schema_name

# First we need to get the spec ID for the current table
specs = await self.adefine_vector_assist_spec()
if not specs:
return []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have better error handling and logging here?


spec_id = specs[0].get("vector_spec_id")
if not spec_id:
return []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have better error handling and logging here?

params = {
"model_id": model_id,
"source_table": source_table,
"source_query": source_query,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a null check for source_query and conf_level?

{
"model_id": model_id,
"table_name": self.table_name,
"content_column": content_col,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a null check for content_column and embedding_column?

}
async with self.engine.connect() as conn:
result = await conn.execute(text(query), params)
result_map = result.mappings()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We can just use

return [dict(row) for row in result.mappings()] instead of the next three lines.
This can be cleaned up at multiple places in this PR

if self.pct_leaves_to_search is not None:
params.append(f"scann.pct_leaves_to_search = {self.pct_leaves_to_search}")
if self.num_leaves_to_search is not None:
params.append(f"scann.num_leaves_to_search = {self.num_leaves_to_search}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if pct_leaves_to_search and num_leaves_to_search both are set? Should we document this behaviour or link to somewhere?

return []

spec_id = specs[0].get("vector_spec_id")
if not spec_id:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should spec_id=0 be considered valid? It would also be true for if not spec_id

Comment thread tests/test_async_vectorstore.py Outdated
mock_conn = AsyncMock()
mock_connect.return_value.__aenter__.return_value = mock_conn
await vs.aenable_columnar_engine(["content"])
assert mock_conn.execute.called

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we should assert on some data not just that something is executed on the table? Maybe the generated sql and the results. Is there some limitations to doing that here?

Same goes for multiple places at which this assertion is present.

Comment thread tests/test_async_vectorstore.py Outdated
async def test_live_vector_assist(self, vs):
"""Test vector assist spec definition, application, and recommendations against live AlloyDB instance."""
specs = await vs.adefine_vector_assist_spec()
assert isinstance(specs, list)

@twishabansal twishabansal Aug 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have stronger assertions based on the content or structure instead? Same goes for other tests in this PR

@madamsetty-pavan

Copy link
Copy Markdown
Author

/gcbrun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: alloydb Issues related to the googleapis/langchain-google-alloydb-pg-python API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants