Repository navigation
[Python] Add Qdrant search enrichment handler - #40629
pangwangshu wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
📋 Review Summary
This PR adds QdrantSearchEnrichmentHandler and associated configuration dataclasses (QdrantDenseSearchParameters, QdrantSparseSearchParameters, QdrantHybridSearchParameters, QdrantSearchParameters) to support dense, sparse, and server-side hybrid vector search enrichment against Qdrant collections. The implementation cleanly aligns with the existing MilvusSearchEnrichmentHandler and QdrantWriteConfig patterns and includes comprehensive unit and integration tests.
🔍 General Feedback
- The design, API surface, default vector naming, and batching behavior via
query_batch_pointsare well-structured and idiomatic. - Two minor edge cases in hybrid search filtering and mutable input mutation in
join_fnare worth addressing.
💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #40629 +/- ##
=============================================
+ Coverage 56.16% 79.97% +23.81%
=============================================
Files 1124 489 -635
Lines 178336 82730 -95606
Branches 1489 0 -1489
=============================================
- Hits 100170 66167 -34003
+ Misses 75645 16563 -59082
+ Partials 2521 0 -2521
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Assigning reviewers: R: @shunping for label python. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
Add QdrantSearchEnrichmentHandler to ml.rag.enrichment so pipelines that ingest into Qdrant with QdrantWriteConfig can use Enrichment for the retrieval step. It supports dense, sparse and hybrid search; hybrid runs the dense and sparse searches as prefetches and fuses them server side with the Qdrant Query API (RRF by default, or DBSF). Each strategy takes a payload filter, limit, score_threshold and search_params, and hybrid search also takes a common filter and a threshold on the fused score. The handler reuses QdrantConnectionParameters from the ingestion module, its default vector names match QdrantWriteConfig, and each batch from BatchElements is sent as a single query_batch_points request. REST and gRPC quota and timeout errors are raised as UserCodeQuotaException and UserCodeTimeoutException so the Enrichment repeater retries them. join_fn stores results under metadata["enrichment_data"] and returns a copy of the item instead of mutating the input element. Builds on the earlier work in apache#35686. Fixes apache#40628 Co-authored-by: Anush <anushshetty90@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
01bb40d to
d84f8e5
Compare
Adds
QdrantSearchEnrichmentHandlertoapache_beam/ml/rag/enrichment, so a pipeline that ingests into Qdrant withQdrantWriteConfigcan useEnrichmentfor the retrieval step. Until now the enrichment handlers covered only BigQuery and Milvus.This builds on #35686 by @anush008, which was closed as stale before review. Anush agreed to my picking it up (comment) and is credited as a co-author on the commit.
Design
The handler follows
MilvusSearchEnrichmentHandler, so the two read the same way:VectorSearchParametersQdrantDenseSearchParametersKeywordSearchParametersQdrantSparseSearchParametersHybridSearchParameters+ rankerQdrantHybridSearchParameters+fusion(RRFdefault, orDBSF)MilvusSearchParametersQdrantSearchParametersMilvusSearchResult(id,distance,fields)QdrantSearchResult(id,score,payload)filter,limit,score_threshold,search_params, andkwargsfor otherQueryRequestfields.with_payloadcan be a bool or a list of payload keys.QdrantHybridSearchParametersalso takes a commonfilter, which Qdrant applies to both prefetches before their limits, and ascore_thresholdon the fused score.QdrantConnectionParametersis reused fromingestion/qdrant.pyand re-exported. The default vector names (dense/sparse) matchQdrantWriteConfig, so a collection written by Beam can be searched without extra configuration.BatchElementsis sent as a singlequery_batch_pointsrequest rather than one request per element.__call__return shape, empty-input handling andbatch_elements_kwargsmatch the Milvus handler.join_fnalso stores results undermetadata["enrichment_data"], but returns a copy of the item instead of mutating the input element.RESOURCE_EXHAUSTED,DEADLINE_EXCEEDED) are raised asUserCodeQuotaException/UserCodeTimeoutException, so theEnrichmentrepeater retries them. Other errors propagate unchanged.Compared with #35686: the handler uses
EmbeddableIteminstead of the oldChunktype, reuses the existing connection parameters instead of duplicating them, and batches queries. Nosetup.pychange is needed, becauseqdrant-clientis already part of theqdrantextra.A website example page, like the one for Milvus enrichment, can follow in a separate PR.
Testing
qdrant_search_test.py: 40 unit tests covering parameter validation, plus dense, sparse, hybrid (RRF and DBSF, common filter, fused score threshold), filter,score_threshold,with_payload, batching, empty input, missing-embedding and unsupported-strategy errors, error mapping with the default repeater, andjoin_fnnot mutating its input. They run against Qdrant's in-memory mode, so they need no Docker. All pass locally.qdrant_search_it_test.py: 7 integration tests. Each writes a corpus withQdrantWriteConfig(content_payload_key="content")to a testcontainers Qdrant instance, then reads it back throughEnrichment(dense, filtered dense, sparse, hybrid, hybrid with a common filter and fused score threshold, batched, empty input). All pass locally on DirectRunner.CHANGES.mdupdated.AI assistance disclosure
Per the ASF generative tooling guidance: this change was written with the help of Claude Code (Claude Opus 5.5). I have reviewed the code and tests and ran them locally, and to my knowledge the change contains no third-party copyrighted material.
Generated-by: Claude Code (Claude Opus 5.5)
Fixes #40628
🤖 Generated with Claude Code