跳转至

搜索与索引指南

借助搜索功能,您可以通过自然语言查询、精确关键词或视觉场景描述,在视频中找到特定时刻。

前提条件

视频在搜索前必须先建立索引。每种索引类型只需对每个视频执行一次。

建立索引

语音单词索引

对视频的转写语音内容建立索引,以支持语义搜索和关键词搜索:

video = coll.get_video(video_id)

# force=True makes indexing idempotent — skips if already indexed
video.index_spoken_words(force=True)

此操作会转写音轨,并在语音内容上构建可搜索的索引。语义搜索和关键词搜索都需要此操作。

参数:

参数 类型 默认值 说明
language_code str\|None None 视频的语言代码
segmentation_type SegmentationType SegmentationType.sentence 分段类型(sentence 或 llm)
force bool False 设为 True 时跳过已建立索引的内容(避免“已存在”错误)
callback_url str\|None None 异步通知的 Webhook URL

场景索引

通过生成场景的 AI 描述来为视觉内容建立索引。与语音单词索引类似,如果场景索引已存在,此操作会引发错误。请从错误消息中提取现有的 scene_index_id。

import re
from videodb import SceneExtractionType

try:
    scene_index_id = video.index_scenes(
        extraction_type=SceneExtractionType.shot_based,
        prompt="Describe the visual content, objects, actions, and setting in this scene.",
    )
except Exception as e:
    match = re.search(r"id\s+([a-f0-9]+)", str(e))
    if match:
        scene_index_id = match.group(1)
    else:
        raise

提取类型:

类型 说明 最佳用途
SceneExtractionType.shot_based 基于视觉镜头边界进行分段 通用、动作类内容
SceneExtractionType.time_based 按固定间隔分段 均匀采样、较长的静态内容
SceneExtractionType.transcript 基于转写文本段进行分段 音频驱动的场景边界

time_based 的参数:

video.index_scenes(
    extraction_type=SceneExtractionType.time_based,
    extraction_config={"time": 5, "select_frames": ["first", "last"]},
    prompt="Describe what is happening in this scene.",
)

搜索类型

使用自然语言查询匹配语音内容:

from videodb import SearchType

results = video.search(
    query="explaining the benefits of machine learning",
    search_type=SearchType.semantic,
)

返回与查询在语义上匹配的语音内容片段,并按相关度排序。

在转写的语音中进行精确的术语匹配:

results = video.search(
    query="artificial intelligence",
    search_type=SearchType.keyword,
)

返回包含精确关键词或短语的片段。

将视觉内容查询与已索引的场景描述进行匹配。需要事先调用 index_scenes()。

index_scenes() 会返回 scene_index_id。将其传给 video.search() 以针对特定的场景索引(当视频有多个场景索引时尤其重要):

from videodb import SearchType, IndexType
from videodb.exceptions import InvalidRequestError

# Search using semantic search against the scene index.
# Use score_threshold to filter low-relevance noise (recommended: 0.3+).
try:
    results = video.search(
        query="person writing on a whiteboard",
        search_type=SearchType.semantic,
        index_type=IndexType.scene,
        scene_index_id=scene_index_id,
        score_threshold=0.3,
    )
    shots = results.get_shots()
except InvalidRequestError as e:
    if "No results found" in str(e):
        shots = []
    else:
        raise

重要注意事项:

  • 将 SearchType.semantic 与 index_type=IndexType.scene 结合使用——这是在所有套餐中都能使用的最可靠组合。
  • SearchType.scene 虽然存在,但可能并非在所有套餐(例如免费套餐)中都可用。建议使用 IndexType.scene 和 SearchType.semantic。
  • scene_index_id 参数是可选的。如果省略,搜索将针对视频上的所有场景索引执行。如需针对特定索引,请传入此参数。
  • 可以为每个视频创建多个场景索引(使用不同的 prompt 或提取类型),并通过 scene_index_id 独立搜索。

带元数据过滤器的场景搜索

当使用自定义元数据为场景建立索引时,可以将语义搜索与元数据过滤器结合使用:

from videodb import SearchType, IndexType

results = video.search(
    query="a skillful chasing scene",
    search_type=SearchType.semantic,
    index_type=IndexType.scene,
    scene_index_id=scene_index_id,
    filter=[{"camera_view": "road_ahead"}, {"action_type": "chasing"}],
)

有关自定义元数据索引和过滤搜索的完整示例,请参阅 scene_level_metadata_indexing 示例。

处理结果

获取片段

访问单个结果片段:

results = video.search("your query")

for shot in results.get_shots():
    print(f"Video: {shot.video_id}")
    print(f"Start: {shot.start:.2f}s")
    print(f"End: {shot.end:.2f}s")
    print(f"Text: {shot.text}")
    print("---")

播放编译后的结果

将所有匹配的片段作为单个编译视频进行流式播放:

results = video.search("your query")
stream_url = results.compile()
results.play()  # opens compiled stream in browser

提取片段

下载或流式播放特定的结果片段:

for shot in results.get_shots():
    stream_url = shot.generate_stream()
    print(f"Clip: {stream_url}")

在集合内的所有视频中进行搜索:

coll = conn.get_collection()

# Search across all videos in the collection
results = coll.search(
    query="product demo",
    search_type=SearchType.semantic,
)

for shot in results.get_shots():
    print(f"Video: {shot.video_id} [{shot.start:.1f}s - {shot.end:.1f}s]")

注意: 集合级别的搜索仅支持 SearchType.semantic。将 SearchType.keyword 或 SearchType.scene 与 coll.search() 结合使用会引发 NotImplementedError。对于关键词或场景搜索,请改用单个视频上的 video.search()。

搜索 + 编译

对匹配的片段建立索引、进行搜索,并将其编译为单个可播放的流:

video.index_spoken_words(force=True)
results = video.search(query="your query", search_type=SearchType.semantic)
stream_url = results.compile()
print(stream_url)

提示

  • 索引一次,多次搜索:建立索引是一项高成本操作。索引一旦创建,搜索就会变快。
  • 组合索引类型:同时为语音单词和场景建立索引,以在同一视频上启用所有搜索类型。
  • 优化查询:语义搜索在使用描述性的自然语言短语时效果最佳,而非单个关键词。
  • 使用关键词搜索以提高精度:当需要精确的术语匹配时,关键词搜索可以避免语义漂移。
  • 处理“无结果”:如果没有匹配项,video.search() 会引发 InvalidRequestError。请始终用 try/except 包裹搜索调用,并将 "No results found" 视为空结果集。
  • 过滤场景搜索噪声:对于模糊查询,语义场景搜索可能会返回低相关性的结果。请使用 score_threshold=0.3(或更高值)来过滤噪声。
  • 幂等的索引创建:使用 index_spoken_words(force=True) 可以安全地重新建立索引。index_scenes() 没有 force 参数——请用 try/except 包裹,并使用 re.search(r"id\s+([a-f0-9]+)", str(e)) 从错误消息中提取现有的 scene_index_id。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC