Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/vidxp/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@
from vidxp.execution import ExecutionContext, execution_context
from vidxp.ports import IndexBackend, ModelRuntimePort, QueryModelPort
from vidxp.query_service import GroundedQueryService
from vidxp.search_fusion import fuse_search_results
from vidxp.search_fusion import (
fuse_search_results,
resolve_candidate_limit,
)
from vidxp.model_contracts import (
ModelArtifactDownloadError,
ModelArtifactUnavailableError,
Expand Down Expand Up @@ -529,6 +532,9 @@ def search(
config,
include_actor=False,
)
candidate_limit = resolve_candidate_limit(
command.top_k, self.settings.search_candidate_depth
)
with self._capability_dependencies(selected):
with self.index_backend.open_store(config) as storage:
context = CapabilityContext(
Expand All @@ -542,7 +548,7 @@ def search(
modality,
query=command.query,
media_id=command.media_id,
top_k=command.top_k,
top_k=candidate_limit,
context=context,
)
for modality in selected
Expand Down Expand Up @@ -667,6 +673,9 @@ def query_video(
results: list[SearchResult] = []
actors: tuple[ActorClusterSummary, ...] = ()
dependencies = search_modalities + (("actor",) if actor_overview else ())
candidate_limit = resolve_candidate_limit(
command.top_k, self.settings.search_candidate_depth
)
with self._capability_dependencies(dependencies):
with self.index_backend.open_store(config) as storage:
context = CapabilityContext(
Expand All @@ -683,7 +692,7 @@ def query_video(
step.modality,
query=step.query,
media_id=command.media_id,
top_k=command.top_k,
top_k=candidate_limit,

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.

Could you add a test for this path as well? The issue covers both regular search and video queries, but the new application test only exercises search(). Please confirm that video moment searches receive the expanded candidate limit while the final fused result still respects the requested top_k.

context=context,
)
)
Expand Down
20 changes: 20 additions & 0 deletions src/vidxp/search_fusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@


RRF_RANK_CONSTANT = 60
DEFAULT_CANDIDATE_DEPTH = 50
MAX_CANDIDATE_DEPTH = 500


def resolve_candidate_limit(
top_k: int,
candidate_depth: int = DEFAULT_CANDIDATE_DEPTH,
*,
max_candidates: int = MAX_CANDIDATE_DEPTH,
) -> int:
"""Determine the per-channel retrieval limit for candidate pools before fusion.

Uses an independent candidate depth budget, ensuring candidate depth is at
least `top_k` and bounded by `max_candidates`.
"""
if top_k <= 0:
raise ValueError("top_k must be greater than zero.")
if candidate_depth <= 0:
raise ValueError("candidate_depth must be greater than zero.")
return min(max(top_k, candidate_depth), max_candidates)


def _query_id(
Expand Down
Loading