qdrant-client icon indicating copy to clipboard operation
qdrant-client copied to clipboard

Switching to grpc crashes search code

Open jlkravitz opened this issue 1 year ago • 4 comments

When I run the code on the REST API on port 6333, the below code works fine.

(matches, _) = client.scroll(
        collection_name="database_mock_df_flat",
        scroll_filter={
            # type: ignore
            "must": [{"key": "CDS_ids", "match": {"any": protein_ids}}]
        },
        with_vectors=True,
        with_payload=True,
        limit=len(protein_ids),
    )

When I initialize the qdrant client with prefer_grpc=True, I get this error (expand for full traceback).

ValueError: Protocol message Condition has no "key" field.
tatta-playground-backend-1   | ERROR:    Exception in ASGI application
tatta-playground-backend-1   | Traceback (most recent call last):
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/responses.py", line 317, in __call__
tatta-playground-backend-1   |     stat_result = await anyio.to_thread.run_sync(os.stat, self.path)
tatta-playground-backend-1   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/anyio/to_thread.py", line 56, in run_sync
tatta-playground-backend-1   |     return await get_async_backend().run_sync_in_worker_thread(
tatta-playground-backend-1   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 2134, in run_sync_in_worker_thread
tatta-playground-backend-1   |     return await future
tatta-playground-backend-1   |            ^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 851, in run
tatta-playground-backend-1   |     result = context.run(func, *args)
tatta-playground-backend-1   |              ^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   | FileNotFoundError: [Errno 2] No such file or directory: 'static/assets/favicon.ico'
tatta-playground-backend-1   |
tatta-playground-backend-1   | During handling of the above exception, another exception occurred:
tatta-playground-backend-1   |
tatta-playground-backend-1   | Traceback (most recent call last):
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
tatta-playground-backend-1   |     result = await app(  # type: ignore[func-returns-value]
tatta-playground-backend-1   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
tatta-playground-backend-1   |     return await self.app(scope, receive, send)
tatta-playground-backend-1   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1054, in __call__
tatta-playground-backend-1   |     await super().__call__(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 116, in __call__
tatta-playground-backend-1   |     await self.middleware_stack(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
tatta-playground-backend-1   |     await self.app(scope, receive, _send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
tatta-playground-backend-1   |     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
tatta-playground-backend-1   |     await app(scope, receive, sender)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 746, in __call__
tatta-playground-backend-1   |     await route.handle(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 288, in handle
tatta-playground-backend-1   |     await self.app(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 75, in app
tatta-playground-backend-1   |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
tatta-playground-backend-1   |     await app(scope, receive, sender)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 73, in app
tatta-playground-backend-1   |     await response(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/responses.py", line 320, in __call__
tatta-playground-backend-1   |     raise RuntimeError(f"File at path {self.path} does not exist.")
tatta-playground-backend-1   | RuntimeError: File at path static/assets/favicon.ico does not exist.
tatta-playground-backend-1   | Calling qdrant at http://host.docker.internal:6333
tatta-playground-backend-1   | INFO:     192.168.65.1:53231 - "POST /api/protein_search HTTP/1.1" 500 Internal Server Error
tatta-playground-backend-1   | ERROR:    Exception in ASGI application
tatta-playground-backend-1   | Traceback (most recent call last):
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 408, in run_asgi
tatta-playground-backend-1   |     result = await app(  # type: ignore[func-returns-value]
tatta-playground-backend-1   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
tatta-playground-backend-1   |     return await self.app(scope, receive, send)
tatta-playground-backend-1   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1054, in __call__
tatta-playground-backend-1   |     await super().__call__(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 116, in __call__
tatta-playground-backend-1   |     await self.middleware_stack(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
tatta-playground-backend-1   |     await self.app(scope, receive, _send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
tatta-playground-backend-1   |     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
tatta-playground-backend-1   |     await app(scope, receive, sender)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 746, in __call__
tatta-playground-backend-1   |     await route.handle(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 288, in handle
tatta-playground-backend-1   |     await self.app(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 75, in app
tatta-playground-backend-1   |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 55, in wrapped_app
tatta-playground-backend-1   |     raise exc
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/_exception_handler.py", line 44, in wrapped_app
tatta-playground-backend-1   |     await app(scope, receive, sender)
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 70, in app
tatta-playground-backend-1   |     response = await func(request)
tatta-playground-backend-1   |                ^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 299, in app
tatta-playground-backend-1   |     raise e
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 294, in app
tatta-playground-backend-1   |     raw_response = await run_endpoint_function(
tatta-playground-backend-1   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
tatta-playground-backend-1   |     return await dependant.call(**values)
tatta-playground-backend-1   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/app/main.py", line 38, in protein_search
tatta-playground-backend-1   |     result = query_qdrant_with_protein_embedding(query_embedding, limit, ENV)
tatta-playground-backend-1   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/app/qdrant_utils.py", line 70, in query_qdrant_with_protein_embedding
tatta-playground-backend-1   |     proteins = fetch_protein_batch(
tatta-playground-backend-1   |                ^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/app/qdrant_utils.py", line 154, in fetch_protein_batch
tatta-playground-backend-1   |     (matches, _) = client.scroll(
tatta-playground-backend-1   |                    ^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/qdrant_client/qdrant_client.py", line 1094, in scroll
tatta-playground-backend-1   |     return self._client.scroll(
tatta-playground-backend-1   |            ^^^^^^^^^^^^^^^^^^^^
tatta-playground-backend-1   |   File "/usr/local/lib/python3.11/site-packages/qdrant_client/qdrant_remote.py", line 1407, in scroll
tatta-playground-backend-1   |     grpc.ScrollPoints(
tatta-playground-backend-1   | ValueError: Protocol message Condition has no "key" field.

The documentation implies I would not need to change my code to use REST vs. grpc. Is that wrong?

jlkravitz avatar Jul 26 '24 15:07 jlkravitz

hi

scroll_filter actually expects either models.Filter or grpc.Filter structure, but not plain dict that's probably why you had to write # type: ignore

You can convert your filter into models.Filter like this:

scroll_filter = models.Filter(
    must=[models.FieldCondition(key="CDS_ids", match=models.MatchAny(any=protein_ids))]
)

joein avatar Jul 26 '24 18:07 joein

Oh, wow! Good catch. I think I was playing around with the API so naturally copied over the json. Perhaps we could raise an error if a plain dict is passed in? Everything was working normally so seems like it'd be helpful to have that flagged. (Or at least log a warning.)

To clarify then, I would have to change my code to use grpc rather than REST? (e.g., in this case, changing models.Filter to grpc.Filter)

jlkravitz avatar Jul 26 '24 23:07 jlkravitz

@joein Is there a plan to unify the behavior of Filters so that models.Filter can be imported and used seamlessly with both gRPC and REST?

sam-hey avatar Feb 24 '25 11:02 sam-hey

Hey @sam-hey

If you are using models.Filter and not plain dicts, everything should already work seamlessly, you don't need to use gRPC structures.

If it is not the case for you, could you provide a code snippet when this does not work?

joein avatar Feb 24 '25 11:02 joein