fix(python): preserve phrase semantics in sync queries (#3654)

## Summary

- serialize sync phrase queries consistently for execution and query
plans
- restore the documented no-argument hybrid `phrase_query()` behavior
- keep reranker input as the original user text without mutating the
builder

Fixes #3653.

## Testing

- `python/.venv/bin/python -m pytest <8 focused test nodes> -q` (`8
passed`)
- `python/.venv/bin/python -m ruff format --check
python/python/lancedb/query.py python/python/tests/test_fts.py
python/python/tests/test_hybrid_query.py`
- `python/.venv/bin/python -m ruff check .`
- `git diff --check origin/main...HEAD`

The complete hybrid module and the real native FTS phrase test were not
completed
in the current PyO3 runtime environment: both stalled in the native
`lancedb.connect()` fixture and were interrupted without an assertion
failure.
This commit is contained in:
kid
2026-07-14 14:44:35 +08:00
committed by GitHub
parent 60428e1a32
commit 40238d240a
3 changed files with 116 additions and 15 deletions
+19
View File
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright The LanceDB Authors
from unittest import mock
import lancedb
from lancedb.query import LanceHybridQueryBuilder
@@ -191,6 +193,23 @@ async def test_analyze_plan(table: AsyncTable):
assert "metrics=" in res
def test_hybrid_phrase_query_is_preserved_in_analyze_plan():
table = mock.Mock()
analyzed_queries = []
table._analyze_plan.side_effect = lambda query: analyzed_queries.append(query) or ""
(
LanceHybridQueryBuilder(table)
.vector([0.1, 0.2])
.text("puppy runs")
.phrase_query()
.analyze_plan()
)
assert len(analyzed_queries) == 2
assert analyzed_queries[1].full_text_query.query == '"puppy runs"'
@pytest.fixture
def table_with_id(tmpdir_factory) -> Table:
tmp_path = str(tmpdir_factory.mktemp("data"))