qdrant / qdrant-client

Python client for Qdrant vector search engine
https://qdrant.tech
Apache License 2.0
732 stars 117 forks source link

Switching to grpc crashes search code #708

Open jlkravitz opened 1 month ago

jlkravitz commented 1 month ago

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?

joein commented 1 month ago

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))]
)
jlkravitz commented 1 month ago

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)