Skip to content

Batch convert docs to achieve acceleration - #647

Open
zzlin237 wants to merge 2 commits into
alibaba:mainfrom
zzlin237:reduce-overhead
Open

Batch convert docs to achieve acceleration#647
zzlin237 wants to merge 2 commits into
alibaba:mainfrom
zzlin237:reduce-overhead

Conversation

@zzlin237

@zzlin237 zzlin237 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Change the query result materialization from converting each document individually across the Python/C++ boundary into a PyDoc, to batch-materializing results as lightweight tuples according to the schema in a single C++ call and then constructing Doc objects via Doc._from_tuple on the Python side.
This aims to eliminate the per-document language binding conversion overhead on the query hot path, thereby reducing query latency.
Dataset: cohere-1m, M: 15

recall QPS
94.0% 15868.8129 -> 16825.6338
92.66% 17108.384 -> 18478.759
91.76% 18642.1531 -> 19924.5225

Copilot AI review requested due to automatic review settings August 3, 2026 09:22
@zzlin237
zzlin237 requested a review from Cuiyus as a code owner August 3, 2026 09:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR changes the Python query hot path to avoid per-document Python/C++ binding overhead by batch-materializing query results as lightweight tuples in C++, then constructing Doc objects from those tuples in Python.

Changes:

  • Refactors _Collection.Query bindings to return a batch of (id, score, fields, vectors) tuples, parameterized by schema.
  • Extracts per-doc materialization into a shared C++ helper (ZVecPyDoc::doc_to_tuple) and reuses it for both per-doc and batch paths.
  • Updates the Python QueryExecutor to consume tuples via Doc._from_tuple, and adds correctness tests for the new batch-materialized behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/binding/python/model/python_doc.cc Extracts get_all logic into doc_to_tuple and binds get_all to it.
src/binding/python/model/python_collection.cc Changes Query bindings to return batch-materialized tuples and adds docs_to_tuples helper.
src/binding/python/include/python_doc.h Declares doc_to_tuple and adds schema dependency for the new signature.
python/zvec/executor/query_executor.py Switches query execution to consume tuple batches and build Doc via Doc._from_tuple.
python/tests/test_query_executor.py Adjusts unit test to patch Doc._from_tuple instead of convert_to_py_doc.
python/tests/test_batch_materialize.py Adds integration-style correctness tests for batch-materialized query results.
Suppressed comments (1)

src/binding/python/include/python_doc.h:1

  • Including <zvec/db/schema.h> in this public binding header increases compile-time coupling for every translation unit that includes python_doc.h. Since doc_to_tuple only needs CollectionSchema by reference in the declaration, you can forward-declare class CollectionSchema; in namespace zvec here and move the schema include into the corresponding .cc file.
// Copyright 2025-present the zvec project

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +279 to +294
// Query with the GIL released, then materialize all hits into
// (id, score, fields, vectors) tuples in one crossing (see docs_to_tuples).
col.def(
"Query",
[](const Collection &self, const SearchQuery &query,
const CollectionSchema &schema) {
Result<DocPtrList> result;
{
py::gil_scoped_release release;
result = self.Query(query);
}
return docs_to_tuples(unwrap_expected(result), schema);
},
py::arg("query"), py::arg("schema"),
"Execute a query and return results as a list of "
"(id, score, fields, vectors) tuples materialized in one batch.")

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确实有点问题,_Collection.Query到底算不算公共API

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_Collection.Query不算公共API。 作为pybind层的wrapper。用来封装py -> c++的调用

Comment thread src/binding/python/model/python_collection.cc
Comment thread python/tests/test_query_executor.py Outdated
Copilot AI review requested due to automatic review settings August 4, 2026 03:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment on lines +279 to +294
// Query with the GIL released, then materialize all hits into
// (id, score, fields, vectors) tuples in one crossing (see docs_to_tuples).
col.def(
"Query",
[](const Collection &self, const SearchQuery &query,
const CollectionSchema &schema) {
Result<DocPtrList> result;
{
py::gil_scoped_release release;
result = self.Query(query);
}
return docs_to_tuples(unwrap_expected(result), schema);
},
py::arg("query"), py::arg("schema"),
"Execute a query and return results as a list of "
"(id, score, fields, vectors) tuples materialized in one batch.")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_Collection.Query不算公共API。 作为pybind层的wrapper。用来封装py -> c++的调用

Result<CollectionSchema> schema_result;
{
py::gil_scoped_release release;
result = self.Query(query);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.Query(query) & self.Schema() 不是同一把锁吧? 并发情况下,如果drop_column,会不会有解析丢字段的问题?

if (!self.has_value(field)) {
continue;
}
py::tuple ZVecPyDoc::doc_to_tuple(Doc &self, const CollectionSchema &schema) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_any 里的 DataType -> Python switch 逻辑和 doc_to_tuple方法里的逻辑有重复。 这次抽一个doc_valude_to_py的方法,来复用相关逻辑

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants