Repository: meta-llama/llama-stack
File: src/llama_stack/providers/remote/vector_io/qdrant/qdrant.py (Python)

Code before:
                    query_filter=models.Filter(
                        must=[
                            models.FieldCondition(
                                key="chunk_content.content", match=models.MatchText(text=query_string)
                            )
                        ]
                    ),
                    limit=k,
                    with_payload=True,
                    with_vectors=False,
                    score_threshold=score_threshold,
                )
            ).points
        except Exception as e:
            log.error(f"Error querying keyword search in Qdrant collection {self.collection_name}: {e}")
            raise

        chunks, scores = [], []
        for point in results:
            assert isinstance(point, models.ScoredPoint)
            assert point.payload is not None

            try:
                chunk = Chunk(**point.payload["chunk_content"])
            except Exception:
                log.exception("Failed to parse chunk")
                continue

            chunks.append(chunk)
            scores.append(point.score)

        return QueryChunksResponse(chunks=chunks, scores=scores)

    async def query_hybrid(
        self,
        embedding: NDArray,
        query_string: str,
        k: int,
        score_threshold: float,
        reranker_type: str,
        reranker_params: dict[str, Any] | None = None,
    ) -> QueryChunksResponse:
        """
        Hybrid search combining vector similarity and keyword filtering in a single query.

        Uses Qdrant's native capability to combine a vector query with a query_filter,
        allowing vector similarity search to be filtered by keyword matches in one call.

        Args:
            embedding: The query embedding vector
            query_string: The text query for keyword filtering

Review comment (bug):
nit: We could also log the `point.payload`:

```suggestion
            try:
                chunk = Chunk(**point.payload["chunk_content"])
            except Exception:
                log.exception("Failed to parse chunk payload: {point.payload}")
```

Code after:
        Uses Qdrant's query_filter with MatchText to search for chunks containing
        the specified text query string in the chunk content.

        Args:
            query_string: The text query for keyword search
            k: Number of results to return
            score_threshold: Minimum similarity score threshold

        Returns:
            QueryChunksResponse with chunks and scores matching the keyword query
        """
        try:
            results = (
                await self.client.query_points(
                    collection_name=self.collection_name,
                    query_filter=models.Filter(
                        must=[
                            models.FieldCondition(
                                key="chunk_content.content", match=models.MatchText(text=query_string)
                            )
                        ]
                    ),
                    limit=k,
                    with_payload=True,
                    with_vectors=False,
                    score_threshold=score_threshold,
                )
            ).points
        except Exception as e:
            log.error(f"Error querying keyword search in Qdrant collection {self.collection_name}: {e}")
            raise

        chunks, scores = [], []
        for point in results:
            if not isinstance(point, models.ScoredPoint):
                raise RuntimeError(f"Expected ScoredPoint from Qdrant query, got {type(point).__name__}")
            if point.payload is None:
                raise RuntimeError("Qdrant query returned point with no payload")

            try:
                chunk = Chunk(**point.payload["chunk_content"])
            except Exception:
                chunk_id = point.payload.get(CHUNK_ID_KEY, "unknown") if point.payload else "unknown"
                point_id = getattr(point, "id", "unknown")
                log.exception(
                    f"Failed to parse chunk in collection {self.collection_name}: "
                    f"chunk_id={chunk_id}, point_id={point_id}"
                )
                continue

            chunks.append(chunk)