Search and Filter¶
Search helps you find visually or semantically similar samples from a text or image. Filters narrow down the samples currently shown in the view by tags, annotations, dimensions, and other numeric metadata.
For more complex filtering, use the query feature — either in the GUI query editor or in Python when you need reusable filtering, sorting, and slicing.
Search in GUI¶
Use the search bar above the grid to find similar samples in one of these ways:
- Type a text query.
- Paste an image from your clipboard into the search bar. You can e.g. right-click an image in your browser and select
Copy image, then click the search bar and paste it withCtrl+VorCmd+V. - Click the image button to upload an image.
Then submit the search by hitting Enter. The number shown on each search result is its similarity score to the current query. Click the x button to remove the search query.
The screen recording below shows the search both by text query "dog" and by pasting an image.
Search requires embeddings
Search is available only when embeddings were generated during data loading.
Search works the same way in the Annotations view, where it finds similar objects using
object-level embeddings. See
Object-level embeddings for details.
Filter in GUI¶
The left sidebar combines the most common ways to narrow down the visible samples:
Tags: Click one or more tags to focus on the subset you care about, such aslabeledorunlabeled.Annotation classes: Click one or more annotation classes to show items with those annotations.Dimensions: UseWidthandHeightto constrain the visible item size.Metadata: If numeric metadata fields are available, they appear as additional sliders in the same area.

For videos, the sidebar adds Duration. If the videos in the current view contain varying frame rates, it also shows FPS.

Query in GUI¶
Query in GUI is currently available for image datasets only.
Your dataset can be filtered by a custom query written in an SQL-like language. Open the
query editor by clicking the Add query filter button in the left sidebar.

The language supports filtering by image fields such as dimensions or file name, tags, annotations, as well as logical combinations of these. For a full reference, see the Lightly Query Language documentation.
Example queries:
# Images that are at least 640 pixels wide or 400 pixels tall
width >= 640 OR height >= 400
# Images which do not have the tag "reviewed"
NOT "reviewed" IN tags
# Images with a "car" segmentation mask that is less than 100 pixels wide
segmentation_mask(class_name = "car" AND width < 100)
Query in Python¶
You can programmatically filter samples by attributes (e.g., image size, tags) or annotations (object detections, classifications and segmentation masks), sort them, and select subsets. This is useful for creating training/validation splits, finding specific samples, or exporting filtered data.
Create a query object by combining match, order_by and slice (or [start:end]) calls. The query is composed lazily and executed against the database once it is consumed, e.g. by iterating over it or calling add_tag.
The example below uses the ImageSampleField for
sample-level filtering; for video datasets, use
VideoSampleField instead. It also uses
ObjectDetectionField to demonstrate annotation
filtering. For the other annotation types, see
ClassificationField and
SegmentationMaskField. For filtering by
evaluation run metrics, see
SampleEvaluationQuery and
EvaluationMetricField in the reference below.
from lightly_studio.core.dataset_query import (
AND,
NOT,
OR,
ImageSampleField,
OrderByField,
ObjectDetectionField,
ObjectDetectionQuery,
)
# QUERY: Define a lazy query, composed by: match, order_by, slice
# match: Find all samples that need labeling plus small samples (< 500px) that haven't been reviewed.
# For video datasets: use VideoSampleField instead of ImageSampleField.
query = dataset.match(
OR(
AND(
ImageSampleField.width < 500,
NOT(ImageSampleField.tags.contains("reviewed"))
),
ImageSampleField.tags.contains("needs-labeling")
)
)
# match (with annotations): Samples with at least one confident "person" detection
# larger than 100 px tall, in an image with 500 px or more width.
query = dataset.match(
AND(
ImageSampleField.width >= 500,
# Criteria inside annotation filters are combined using AND(..) operator
ObjectDetectionQuery(
ObjectDetectionField.class_name == "person",
ObjectDetectionField.source == "predictions",
ObjectDetectionField.confidence >= 0.8,
ObjectDetectionField.height >= 100,
)
)
)
# order_by: Sort the samples by their width descending.
query.order_by(
OrderByField(ImageSampleField.width).desc()
)
# slice: Extract a slice of samples.
query[10:20]
# chaining: The query can also be constructed in chained way
query = dataset.match(...).order_by(...)[...]
# Ways to consume the query
# Tag this subset for easy filtering in the UI.
query.add_tag("needs-review")
# Iterate over resulting samples
for sample in query:
# Access sample attributes such as tags, file_name, or metadata
# Collect all resulting samples as list
samples = query.to_list()
# Export all resulting samples in coco format
dataset.export(query).to_coco_object_detections()
# For video datasets: export in a video format
# dataset.export(query).to_youtube_vis_segmentation_mask()
Reference¶
The following sections explain the available methods for defining a query in more detail.
Examples use ImageSampleField for sample-level
filters and the annotation query helpers for annotation-level filters. For video datasets, the
sample-level examples translate to VideoSampleField.
You can define query filters with:
query.match(<expression>)
Sample queries¶
Sample-level queries use the ImageSampleField.<field_name> <operator> <value> syntax.
Available field names can be seen in
ImageSampleField.
from lightly_studio.core.dataset_query import ImageSampleField
# Ordinal fields: <, <=, >, >=, ==, !=
expr = ImageSampleField.height >= 10 # All samples with images that are taller than 9 pixels
expr = ImageSampleField.width == 10 # All samples with images that are exactly 10 pixels wide
expr = ImageSampleField.created_at > datetime # All samples created after datetime (actual datetime object)
# String fields: ==, !=
expr = ImageSampleField.file_name == "some" # All samples with "some" as file name
expr = ImageSampleField.file_path_abs != "other" # All samples that are not having "other" as file_path
# Tags: contains()
expr = ImageSampleField.tags.contains("dog") # All samples that contain the tag "dog"
# Assign any of the previous expressions to a query:
query.match(expr)
Annotation queries¶
Annotation queries use ClassificationQuery(...), ObjectDetectionQuery(...), and
SegmentationMaskQuery(...). Each helper matches a sample when it has at least one
annotation of that type that satisfies all passed criteria.
from lightly_studio.core.dataset_query import (
ClassificationField,
ClassificationQuery,
ObjectDetectionField,
ObjectDetectionQuery,
SegmentationMaskField,
SegmentationMaskQuery,
)
# Classification fields: class_name, source, confidence
expr = ClassificationQuery(
ClassificationField.class_name == "approved",
ClassificationField.source == "ground_truth",
ClassificationField.confidence >= 0.9,
)
# Object detection fields: class_name, source, confidence, x, y, width, height
expr = ObjectDetectionQuery(
ObjectDetectionField.class_name == "person",
ObjectDetectionField.source == "predictions",
ObjectDetectionField.confidence >= 0.8,
ObjectDetectionField.x >= 10,
ObjectDetectionField.y >= 20,
ObjectDetectionField.width >= 40,
ObjectDetectionField.height >= 100,
)
# Segmentation mask fields: class_name, source, confidence, x, y, width, height
expr = SegmentationMaskQuery(
SegmentationMaskField.class_name == "road",
SegmentationMaskField.source == "ground_truth",
SegmentationMaskField.confidence >= 0.95,
SegmentationMaskField.x >= 0,
SegmentationMaskField.y >= 0,
SegmentationMaskField.width >= 300,
SegmentationMaskField.height >= 80,
)
# Assign any of the previous expressions to a query:
query.match(expr)
Sample evaluation queries¶
Sample evaluation queries use SampleEvaluationQuery(...) together with
EvaluationMetricField(...) to filter samples by metrics from a specific evaluation run.
They match only samples that are part of the named run and satisfy all passed metric
criteria.
from lightly_studio.core.dataset_query import (
AND,
EvaluationMetricField,
ImageSampleField,
SampleEvaluationQuery,
)
# Metric operators: <, <=, >, >=, ==, !=
expr = SampleEvaluationQuery(
"run1",
EvaluationMetricField("score") > 0.5,
)
# Multiple metrics inside SampleEvaluationQuery are combined with AND
expr = SampleEvaluationQuery(
"run1",
EvaluationMetricField("precision") > 0.5,
EvaluationMetricField("recall") > 0.5,
)
# Evaluation queries can be combined with sample-level filters
expr = AND(
ImageSampleField.tags.contains("reviewed"),
SampleEvaluationQuery(
"run1",
EvaluationMetricField("score") >= 0.8,
),
)
# Assign any of the previous expressions to a query:
query.match(expr)
Annotation evaluation queries¶
Filtering samples by annotation evaluation results from a specific evaluation run, can be realized via AnnotationMetricQuery.confusion(...) together with AnnotationEvaluationMetricField(...). In the below example we filter for samples where cat got confused as a dog by the model, and the IOU is higher than 0.3.
from lightly_studio.core.dataset_query import (
AnnotationEvaluationMetricField,
AnnotationMetricQuery,
)
expr = AnnotationMetricQuery.confusion(
"run1",
"cat",
"dog",
AnnotationEvaluationMetricField("iou") > 0.3,
)
# Assign the expression to a query:
query.match(expr)
Boolean operators¶
The filtering on individual fields can flexibly be combined to create more complex match expression. For this, the boolean operators AND, OR, and NOT are available. Boolean operators can arbitrarily be nested.
from lightly_studio.core.dataset_query import (
AND,
NOT,
OR,
ImageSampleField,
ObjectDetectionField,
ObjectDetectionQuery,
)
# All samples with images that are between 10 and 20 pixels wide
expr = AND(
ImageSampleField.width > 10,
ImageSampleField.width < 20
)
# All samples with file names that are either "a" or "b"
expr = OR(
ImageSampleField.file_name == "a",
ImageSampleField.file_name == "b"
)
# All samples which do not contain a tag "dog"
expr = NOT(ImageSampleField.tags.contains("dog"))
# All samples for a nested expression
expr = OR(
ImageSampleField.file_name == "a",
ImageSampleField.file_name == "b",
AND(
ImageSampleField.width > 10,
ImageSampleField.width < 20,
NOT(
ImageSampleField.tags.contains("dog")
),
),
)
# Combine sample and annotation filters, use logical `OR` inside annotation filter
expr = AND(
ImageSampleField.tags.contains("reviewed"),
ObjectDetectionQuery(
ObjectDetectionField.class_name == "car",
OR(ObjectDetectionField.width >= 80, ObjectDetectionField.height >= 80)
),
)
# Assign any of the previous expressions to a query:
query.match(expr)
Setting the sorting of a query can be done by
query.order_by(<expression>)
The order expression can be defined by
OrderByField(ImageSampleField.<field_name>).<order_direction>() for sample fields or
OrderByEvaluationMetricField("<run_name>", "<metric_name>").<order_direction>() for
evaluation metrics.
from lightly_studio.core.dataset_query import (
ImageSampleField,
OrderByEvaluationMetricField,
OrderByField,
)
# Sort the query by the width of the image in ascending order
expr = OrderByField(ImageSampleField.width)
expr = OrderByField(ImageSampleField.width).asc()
# Sort the query by the file name in descending order
expr = OrderByField(ImageSampleField.file_name).desc()
# Sort the query by an evaluation metric in descending order
expr = OrderByEvaluationMetricField("run1", "score").desc()
# Assign any of the previous expressions to a query:
query.order_by(expr)
Setting the slicing of a query can be done by:
query.slice(<offset>, <limit>)
# OR
query[<offset>:<stop>]
# Slice 2:5
query.slice(offset=2, limit=3)
query[2:5]
# Slice :5
query.slice(limit=5)
query[:5]
# Slice 5:
query.slice(offset=5)
query[5:]
For more details, see the API reference of DatasetQuery.