Skip to content

Python: OracleCollection vector search raises AttributeError when filter is a list of multiple filters #14539

Description

What happens

OracleCollection raises AttributeError: 'tuple' object has no attribute 'values' when filter is a list of two or more filters. VectorSearchOptions documents that multiple filters are combined with AND.

Where

python/semantic_kernel/connectors/oracle.py, OracleCollection._inner_search_vector:

parsed_filter = self._build_filter(options.filter)
filter_clause: str | None = None
filter_binds: list[Any] = []

if parsed_filter is not None:
    filter_clause = parsed_filter[0]
    filter_binds.extend(parsed_filter[1].values())

VectorStoreCollection._build_filter returns a single (sql, binds) tuple for one filter, but a list of those tuples for several. The code above only handles the single tuple case. With a list, parsed_filter[0] is a whole tuple and parsed_filter[1] is the second filter's tuple, which has no .values().

A second problem is hidden behind this one. _build_filter parses each filter with a fresh BindCounter, so every filter starts at :bind_val1. Even if the list were handled, the names would collide.

Repro (current main, 9974625, oracledb installed, no database needed)

import asyncio, oracledb
from dataclasses import dataclass
from typing import Annotated
from unittest.mock import MagicMock
from semantic_kernel.connectors.oracle import OracleCollection
from semantic_kernel.data.vector import VectorStoreField, vectorstoremodel, VectorSearchOptions

@vectorstoremodel
@dataclass
class R:
    id: Annotated[int, VectorStoreField("key")]
    color: Annotated[str, VectorStoreField("data", is_indexed=True)]
    size: Annotated[int, VectorStoreField("data", is_indexed=True)]
    vec: Annotated[list[float] | None, VectorStoreField("vector", type="float", dimensions=2)] = None

async def main():
    c = OracleCollection(record_type=R, collection_name="x",
                         connection_pool=MagicMock(spec=oracledb.AsyncConnectionPool))
    opts = VectorSearchOptions(
        filter=["lambda x: x.color == 'red'", "lambda x: x.size > 5"],
        vector_property_name="vec")
    print(await c._inner_search_vector(opts, None, [1.0, 0.0]))

asyncio.run(main())

Actual: AttributeError: 'tuple' object has no attribute 'values'. A single filter works.

Expected: a query with WHERE ("color" = :bind_val1) AND ("size" > :bind_val2) and binds ['red', 5].

Fix

Override _build_filter in OracleCollection to parse all filters with one shared BindCounter and return one combined (sql, binds) tuple. I have this ready with tests and will open the PR right away.

No activity

Activity on this issue will appear here.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonPull requests for the Python Semantic Kerneltriage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions