Skip to main content
fields controls how an artifact becomes an index. An artifact may contain many fields. VideoDB stores the additional artifact data with the indexed records, but only selected fields are optimized for retrieval capabilities:
  • direct semantic search
  • exact/text matching
  • structured filters
  • aggregation
  • sorting
Use return_fields at search time to choose which stored fields should come back in results.

Example artifact

A VLM scene artifact may contain scene records like this:
A fields config tells VideoDB how to index values that exist on that artifact:
The frames field is still stored with the record. Request it later with return_fields when you need it in search results. Object labels and brand names usually live on separate objects and brands artifacts.

Dotted paths for nested data

Field names may be dotted paths that reach inside nested objects, so you do not need to flatten your data. When a path crosses a list, values are collected from every element. An object-detection scene looks like this:
Index the nested values directly:
frames.detections.label becomes the list of every detection label in the scene (["person", "dog"]); frames.detections.score becomes the list of every score. Bounding boxes remain nested under frames[].detections[].box, and the raw frames structure stays stored-only; request the objects index data with return_fields when you need timestamps or boxes. Dotted paths work everywhere a field name does: fields groups, query() filters, aggregate(group_by=...), and targeted semantic refs (index_names=["scene.outputs.location"]).

Field groups

Do not add clip to fields. Clips are generated automatically from video_id, start, and end for moment results. Use include_clip=False at retrieval time if you do not need playable clips.

Supported field value types

Nested values you filter or aggregate on should be declared with their dotted path. Declaring them projects the values into the queryable store at ingest time, so retrieval stays fast.

Default fields

fields is optional per group. Any group you omit is derived from your data: well-known names get product defaults (text/scene_description → semantic, language/brand_names → filter + aggregate, frames.detections.label → filter + aggregate, frames.detections.score → filter + sort), and everything else is classified by shape — prose becomes semantic, scalars and scalar lists become filter + aggregate (numbers also sort), and nested structures stay stored-only. Groups you declare are used verbatim, and an explicit empty group ("filter": []) opts out. See Create an Index for the full derivation tables.

User-provided temporal records

If you index your own timestamped records, choose fields the same way:

Return fields at retrieval time

Indexing does not decide the result payload. Search does. Use return_fields to choose which stored fields to include in each result:
For multi-index search, namespace fields by index name:
For debugging or inspection, request all stored fields:
Returned fields can make responses larger. Keep them narrow for broad searches and request detailed fields only when you need to display or inspect them.

Filter syntax

Query filters use fields that were indexed in fields["filter"], including dotted paths. How filters behave on list-valued fields (anything a dotted path collected across a list, or a plain array field):
  • equality means element membership: {"frames.detections.label": "phone"} matches a scene where any detection is a phone
  • numeric comparators match any element: {"frames.detections.score": {">=": 0.9}} matches if any detection scores ≥ 0.9
  • contains is a per-element substring match: "car" matches ["car", "truck"] but not ["cartoon"]

Aggregation syntax

Aggregation uses fields that were indexed in fields["aggregate"].
List-valued fields explode to one group per element (each detection label counts separately). Dict-valued fields ({"person": 3, "phone": 1}) explode to one group per key, and numeric metrics (sum/avg/min/max) apply to the dict’s values. Common metrics:

Best practices

  1. Put natural-language descriptions in fields["semantic"].
  2. Put exact labels, enums, numbers, and booleans in fields["filter"].
  3. Put fields you want to count or facet in fields["aggregate"].
  4. Put fields you want to order by in fields["sort"].
  5. Keep indexing focused on retrieval capabilities; request display/debug details with return_fields during search.
  6. Reach into nested data with dotted paths (frames.detections.label) instead of reshaping your artifacts. Declare the paths in fields so the values are projected for fast retrieval.

Next steps

Create an Index

Create indexes from artifacts.

View Indexes

Inspect fields, schemas, and records after indexing.