Skip to content

Search Expressions

Jonathan Schmidt edited this page Aug 24, 2021 · 1 revision

Search expressions allow you to add to the search query language to express complex queries that cross-reference multiple providers, for example, to search for all objects in a scene that use a shader that doesn’t compile.

Search expressions can be chained together to transform or perform set manipulations on Search Items.

How to use search expressions

Enter a search expression in the Search window to return a result:

alt_text

Creating a search expression

A search expression starts with a root expression that can contain inner expressions.

A simple query like t:shader is an expression. It returns all of the Search Items corresponding to shaders in your project.

Use the search expression language to combine multiple queries into a single expression to create more flexible searches.

Search expressions support the following:

  • query: t:shader
  • query with a nested expression: t:prefab ref={t:texture}
  • function: count{t:shader}
  • literal: 3 or "this is a string literal"
  • property selector: @path or @mesh (any identifier beginning with @ is assumed to be a selector that extracts a value from a Search Item. Selectors can find properties of an Object or be used to compute results dynamically. )

All search expressions return a set of Search Items. As a general guideline, the search expression language uses curly braces {} to denote a set of items.

Combine search expressions to make more complex queries:

  • t:prefab ref={t:texture}
    • The t:texture part of the query finds all textures in your project
    • The t:prefab ref= part of the query finds all Prefabs referencing the textures in your project.
  • t:prefab ref={t:texture size>4000}: finds all Prefabs in a project with texture size larger than 4000 bytes.

This is the equivalent to:

  • Running t:texture size>4000to return a list of all 4K textures in the project (for example, armor.png, treasure.png).
  • Running t:prefab ref=<one of the 4K textures> (for example, t:prefab ref=armor.png and then t:prefab ref=treasure.png).
  • Aggregating all results and returning this as a single list of Search Items.
  • t:[shader, material, texture]: finds all objects whose types are shader, material or texture.

Using a normal query it could be expressed as:

t:shader or t:material or t:texture

Using literals in search expressions

Literals are actual words or numbers that you would like to search for or number amounts you want to retrieve, as opposed to the query language. For example, t:texture searches for Assets with texture in the type name (e.g.,Texture2D), but adding quotation marks to make it a literal, "t:texture" searches for an Asset named t:texture.

Expression Description
Number A literal number (1,2,3, and so on)
Set Square brackets ([ ])
String Single or double quotes ('' or "")

Numbers

Number literals can be used as parameters to functions (such as first).

first{10, t:shader}: the first 10 shaders returned by the 't:shader' query.

Sets

Express a set of literal values using square brackets []. A set can contain any type of expression, but the search expression parser will assume the elements of a set in square brackets are literals instead of a search query.

Example:

[t:shader, hello, 3]: search for a set of two strings ("t:shader" and "hello") and a number (3).

Strings

String literals can be used as parameters for some functions (such as format). You can specify a string literal using single or double quotes:

"hello" or 'hello'

Example: the format function taking a format string as a parameter:

format{'@path (@size)', t:texture}

Functions

Unity has a library of search expression functions to create queries for Search Items. Each of these functions can take multiple arguments.

Use curly braces ({ }) to denote function calls.

The list of all functions is here.

Example: The function count counts the items of each set passed as parameters and returns a set number.

  • count{t:shader} : returns a set containing the number of shaders in the project. Example: {34}.
  • count{t:shader, t:texture} : returns a set containing the number of shaders and textures in the project. Example: {34, 2048}.

Functions can be chained together.

Note: There can only be a single root expression.

Example of a chain of functions being evaluated, in order of operation:

print{"path=@path", first{10, sort{t:texture, @size}}}: In the **Console **window, print the path of the 10 largest textures in the project

  1. t:texture: finds all texture in the project and then selects the size property.
  2. sort{ t:texture, @size}: sorts all these textures according to their size property.
  3. first{10: selects the first 10 sorted textures.
  4. print{ "path=@path": prints this list in the **Console **window according to a format string where Unity Search extracts the path property of each resulting item path=@path.

alt_text

Example in the **Console **window:

alt_text

alt_text

Functions:

  • can have multiple signatures (name of the method and the type and kind (value, reference, or output) of each of its formal parameters, similar to C#)
  • can support optional parameters (parameters that don't need to be passed to the function)
  • can support variadic parameters (parameters that can take a variable number of arguments)

Property selectors and search item values

A selector is an identifier denoted using the @ prefix. Use selectors to retrieve a property of an item in order to compute, filter, or format using the property. In the Table view, the property displays as a column.

Selectors can map to serialized properties of a UnityEngine.Object or to a custom function to allow access to dynamic data.

The base selectors that any Search Item supports are:

  • Description : Item description
  • Id: Unique ID of this item according to its Search Provider.
  • Label: Item label as shown in the Search window
  • Value: Internal value of an item. By default it is its ID, but functions can override the value of an item.
  • value: an item can have a custom value that will be set by specific functions. For example, if the count function creates new items where the value is the count number.

Unity also defines generic selectors for a Search Item, for example:

  • @size: file size on disk for an Asset
  • @path: Asset path
  • @extension: Asset file extension
  • @provider: Search provider that has yielded this item.

Examples

To access specific properties of a Search Item in order to perform an operation, use selectors.

  • count{t={distinct{select{a:assets, @type}}}}
    • a:assets, @type finds all of the objects named assets and then selects the type property for those objects.
    • distinct returns a list of all types that exist.
    • t={list of types} returns the multiple lists of each asset of each type.
    • count counts how many assets of each type are in your project.
  • avg{@size,t:shader}
    • t:shader, @size: finds all the shaders and then selects the size property.
    • avg: computes the average size for all shaders in your project.
  • print{@value, count{t:texture, t:material}}
    • This will print the count value extracted from the results of the count function in the Console window.

The @# selector finds serialized properties and material properties:

  • sort{t:texture, @#height}: sorts all textures in order of their height serialized properties.

Naming search expressions (alias)

You can name search expressions to make them easier to display in the Search window.

For example, entering the expression sort{count{t:audio,t:texture}, @value,desc} in the Search window, it may be difficult to read which count corresponds to which type:

alt_text

Using an alias: sort{count{t:audio as Audio,t:texture as Texture}, @value,desc} yields a more readable result:

>>>>> gd2md-html alert: inline image link here (to images/image6.png). Store image on your image server and adjust path/filename/extension if necessary.
(Back to top)(Next alert)
>>>>>

alt_text

To dynamically generate alias names, use the alias function. For example:

alias{[1, 2, 3], 'Title value'}

will yield items with these labels:

{Title 1, Title 2, Title 3}

alt_text

Expand Operator

All search expressions return a set of items. The expand operator allows a set of items to be grouped into multiple sets of items.

...{expandable expression} -> {sub expr 1} {sub expr 2} {sub expr N}

Search query expansion

The expand operator in a search query allows you to view group queried items into separate sets.

Example:

A small project has 3 prefabs, 4 textures and 5 shaders. The following expression provides a count for all:

count{t:[prefab, texture, shader]} -> {12}

The result of the search expression t:[prefab, texture, shader] is a unified list of 12 items of type prefabs, textures, and shaders. This could also be expressed as: t:shader or t:texture or t:prefab.

Use the expand operator to count the number of each type of asset separately:

count{...t:[prefab, texture, shader]} -> count{t:prefab, t:texture, t:shader} -> {3, 4, 5}

Expression evaluation

Search expression evaluation is based on the C# iterator pattern and uses of the yield keyword. This ensures that the evaluation is exposed as a fully asynchronous operation and is as non-blocking as possible. It allows each search expression to start its computation before the initial sets of search items are fully computed.

By default all search expression evaluation is done in a worker thread in order to not block the Editor. For operations that need to rely on non-thread safe Unity API (like some selector accessors), we have a utility API to queue those operations on the main thread and maintain the pattern of yielding search items.

Customizing the search expression language

The search expression language has been set up to be customizable. APIs to customize all parts of the framework will be available in a future release.

Search expression examples

These examples demonstrate how search expressions can be used for complex requests in a project.

  • Count prefab usage in scenes and sort by highest usage:
    sort{select{p: t:prefab *.prefab, @path, count{t:scene ref:@path} as count}, @count, desc}
  • Sort and count all asset types
    sort{count{...groupby{a:assets, @type}}, @value, desc}
  • Find the mesh with the most vertices (assuming the @vertices selector is available in the project).
    first{sort{t:mesh, @vertices, desc}}
  • Sort all meshes by their vertex count
    sort{select{h: t:mesh, @path, @vertices}, @vertices, desc}
  • Count the number of vertices for all meshes
    sum{select{h:t:mesh, @vertices}}
  • Find all assets referencing a mesh
    ref=select{p:t:mesh, @path}
  • List prefab scene references count
    select{p: *.prefab, @path, count{p: a:sceneIndex ref="@path"} as count}

Functions reference

Set manipulation

groupBy

groupBy{set, selector} -> {multiple sets of items grouped by their selector value}
set: an iterable value (query, function, set)
selector: a selector that will serve to group together all items having the same selector value. 

The groupBy function coupled with the Expand Operator is a way of grouping a flat list of items into multiple sets of items according to a selector. In the example below it creates a set of items of the same types. The Expand Operator allows you to expand this set of items into multiple sets of the same type.

Generally all search expressions return a list of items, but coupled with the expand operator, the groupBy function can be used like the LINQ GroupBy method.

Example

count{...groupBy{a:assets, @type}} -> {numberOfAssetType1, numberOfAssetType2, ... numberOfAssetTypeN}

alt_text

Example

To count the number of assets for each type in a project:

select{a:assets, @type} -> {new set of items with only a @type field}
distinct{select{a:assets, @type}} -> {sets of items with one of each type}

The following search expression

t=distinct{select{a:assets, @type}} would expand to t=<assetType1> t=<assetType2> ... t=<assetTypeN>

By using the Expand Operator counting the number of each type is:

count{...t=distinct{select{a:assets, @type}}} -> {numberOfAssetType1, numberOfAssetType2, .. numberOfAssetTypeN}

Example

A project has three types of assets (prefabs, shaders, and textures). The following expression would count all prefabs, shaders and textures.

alt_text

You can use the groupBy operator to group items by their type and then count each number of items per type: count{...groupBy{t:prefab or t:shader or t:texture, @type}}

alt_text

map

map{searchExpression1, query}
searchExpression1: query, set, or results of an evaluator
searchExpression2: searchExpression that can contain selectors 

The map operator is a functional way of expressing a query search expression. It will evaluate searchExpression2 for each item returned by searchExpression1 and resolve all selectors in searchExpression2 by selecting values of the items of searchExpression1.

Example

The search expression:

map{t:texture town, t:material ref=@path}
Would be evaluated as follow to:
Expression1: `t:texture` would evaluate to -> [texturePath1, texturePath2, … texturePathN]
Expression2 `t:material ref=@path` would be evaluated for each texture yielded by expression1.
t:material ref=<texturePath1>} {t:material ref=<texturePath2>} ... {t:material ref=<texturePathN>}

In that specific query this would be equivalent to running:

{t:material ref={t:texture town}}

alt_text

select

select(<set>, selectorForLabel, selectorForDesc, otherSelectors...)

Select is a function similar to SQL Select or LINQ Select: from a given set of search items it creates a new set of search items and extracts or transforms properties of the original set.

The second parameter (selectorForLabel) of the select function will assign the selected value to the label of the new item. The third parameter (selectorForDesc) will assign the selected value to the description of the new item.

The last selector in a select function will also specify the value of the item

Example

Running the query t:texture in a project:

alt_text

Using select, generates a new set of items where the label is the path and where the description becomes the size of the texture:

select{t:texture, @path, @size}

alt_text

The last selector used in a select statement also sets the value of the item. Switch to the Table view to see how the search expression replaces the label and description sets the value:

alt_text

Example

Selectors of a select function can also be functions themselves. Selectors in these functions are evaluated according to the search item being processed.

select{t:texture, @path, count{t:material ref=@path}}

  1. For each texture in the project, create a new search item (t:texture)
  2. whose label is equal to the @path of the texture (@path)
  3. and whose description and value are equal to how many materials are referring to that texture (count{t:prefab ref=@path}). Where @path refers to the file path of each texture item.

alt_text

Example

You can assign a property value to a search item field if you use the alias operator.

print{"@mypath", select{t:script, @path as mypath}} -> {NewBehavior.cs, PlayerInput.cs}

This expression reads like:

  1. For each script in my project create a new item (t:script)
  2. Create a new property called mypath in the item and assign it the value of the selector @path.
  3. Use the print function to print on the console the value of the @mypath selector.

union

union{sets...} -> {Unified set of all unique elements in all sets}

Create a set of all elements found in all sets passed as parameter. Note that no duplicate of elements are kept. This is equivalent to distinct.

Example

This example shows that duplicate are removed.

union{[1,2,3], [3,4,5]} -> {1,2,3,4,5} 

Example

union{*.mat, t:shader} -> {all materials and shaders in the project}

distinct

distinct{sets...} -> {Unified set of all unique elements in all sets}

Create a set of all elements found in all sets passed as parameters. Note that no duplicate of elements are kept. This is equivalent to union.

Example

This example shows that duplicates are removed.

distinct{[1,2,3], [3,4,5]} -> {1,2,3,4,5} 

Example

distinct{*.mat, t:shader} -> {all materials and shaders in the project}

Example

Select the @type of each asset in my index named: project and keep a single asset of each type since duplicate are computed according to the @value of an item.

distinct{select{a:project, @type}}

except

except{set, sets...} -> {New set of elements}

Takes all elements in set that are not in any of the sets passed as parameters.

Example

except{[1,2,3,4,5], [2,3], [5], [6]} -> {1,4}

Example

except{t:prefab, t:prefab ref=select{t:texture, @path}}

intersect

intersect{sets...} -> {elements that are in all sets}
intersect{sets…, selector} -> {elements whose selector value is contained in all sets}

Create a new set of elements whose @value is contained in all sets. If a selector is passed as parameter the selector value is used to compare elements.

Example

intersect{[1,2,3,4,5], [3, 5], [6, 3]} -> {3}

Example

Find all textures whose size is bigger than 4000 bytes and intersect with all texture whose path contains the word rock.

intersect{t:texture size>4000, t:texture @path:rock}

first

first{sets...} -> {all first element in each sets}
first{count, sets...} -> {first count elements in each sets}

Returns a set of the first element found in each sets passed as parameter. If count is passed as parameter, will take the first count element in each sets.

Example

first{[3, 4,5], [9, 28, 3]} -> {3,9}

Example

first{3, [9, 28, 3, 4, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7]} -> {9, 28, 3, 1, 2, 3}

Example

Sort all fbx files in my project by descending order and take the 3 biggest.

first{3,sort{*.fbx, @size, desc}}

last

last{sets...} -> {all last element in each sets}
last{count, sets...} -> {last count elements in each sets}

Returns a set of the last element found in each sets passed as parameter. If count is passed as parameter, will take the last count elements in each sets.

Example

last{[3, 4,5], [9, 28, 3]} -> {5, 3}

Example

last{3, [9, 28, 3, 4, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7]} -> {7,8,9,5,6,7}

Example

Sort all fbx files in my project by ascending order and take the 3 biggest (the last ones)

last{3,sort{*.fbx, @size}}

sort

sort{set, selector} -> {set of items sorted in ascending order according to selector value}
sort{set, selector, desc} -> {set of items sorted in descending order according to selector value}

Sort a set of item according to a selector value in descending or ascending order.

Example

Sort this set in ascending order (from smallest to largest).

sort{[4,2,7,5,8,1,9], @value} -> {1,2,4,5,7,8,9}

Example

Sort this set in descending order (from largest to smallest).

sort{[4,2,7,5,8,1,9], @value, desc} -> {9,8,7,5,4,2,1}

Example

Sort all textures in my project according to their @size in descending order (from largest to smallest).

sort{t:texture, @size, desc}

Math functions

avg

avg{selector, sets...} -> {Average of selector value in each set}
avg{set...} -> {Average of @value in each set}

Find the average value of each item in each set passed as parameters.

Example

avg{[1,2,3,4, 5,6], [1, 1, 1], []} -> {3.5, 1, 1}

Example

avg{@size, t:texture, t:material} -> {1100576, 3618}

count

count{sets...} -> {count of each set}

Count the number of results in each set passed as parameters.

Example

count{t:texture, t:material} -> {359, 194}

alt_text

Example

From my index named “assets”, group assets by type and count each of those asset groups. Take the 5 biggest groups.

first{5, sort{count{...groupBy{a:assets, @type}}, @value, desc}}

>>>>> gd2md-html alert: inline image link here (to images/image17.png). Store image on your image server and adjust path/filename/extension if necessary.
(Back to top)(Next alert)
>>>>>

alt_text

max

max{sets...} -> {max value element in each set}
max{selector, sets...} -> {max selector value element in each set}

Find the maximum @value for each set passed as parameters. If a selector is passed as parameter, find the element with maximum @selector value.

Example

max{[1,2,3,4,5,6], [2,4,5]} -> {6, 5}

Example

Find the biggest png and the biggest jpg.

max{@size, *.png, *.jpg} -> {<biggest png>, <biggest jpg>}

min

min{sets...} -> {min value element in each set}
min{selector, sets...} -> {min selector value element in each set}

Find the minimum @value for each set passed as parameters. If a selector is passed as parameter, find the element with minimum @selector value.

Example

min{[1,2,3,4,5,6], [2,4,5]} -> {1, 2}

Example

Find the smallest png and the biggest jpg.

min{@size, *.png, *.jpg} -> {<smallest png>, <smallest jpg>}

sum

sum{sets...} -> {sum of all elements in each set}
sum{selector, sets...} -> {sum of all elements in each set}

Find the sum @value of each item in each set passed as parameters. If a selector is passed as parameter, find the sum @selector value of each element in each set.

Example

sum{[1,2,3,4,5,6], [2,4,5]} -> {21, 11}

Example

Find the sum of all textures @size in a project.

sum{@size, t:texture}

Filtering

where

where{set, filterString | selector} -> {filtered set of items}

Where is a general filtering function that accepts a selector or a string containing selector usage and operators (>, ==, ...) to filter elements of a set and returns the new filtered set.

Example

Filtering out numbers according to their value:

where{[1,2,3,4,5,6,7,8,9,10], '@value>4 and @value<9'} -> {5,6,7,8}

Example

Finding all audio clips containing the word effect in their path:

where{t:AudioClip, @path:effect}

eq

eq{set, value} -> {all elements equal to value}
eq{set, selector, value} -> {all selector value equal to value}

Filter a set of element by keeping those equal to a given value.

Example

eq{[2,4,5,6,4,3], 4} -> {4,4} this is equivalent to :

where{[2,4,5,6,4,3], “@value=4”}

Example

Find all textures with a #width serialized property of 256.

_eq{t:texture, #width, 256} _this is equivalent to

t:texture #width=256

gt

gt{set, value} -> {all elements greater than value}
gt{set, selector, value} -> {all elements with selector value greater than value}

Filter a set of element by keeping those greater than a given value.

Example

gt{[2,4,5,6,4,3], 4} -> {5,6}

gte

gte{set, value} -> {all elements greater or equal than value}
gte{set, selector, value} -> {all with a selector value greater or equal than value}

Filter a set of element by keeping those greater than or equal to a given value.

Example

gte{[2,4,5,6,4,3], 4} -> {4,5,6,4}

lw

lw{set, value} -> {all elements lower than value}
lw{set, selector, value} -> {all elements with selector value lower than value}

Filter a set of element by keeping those lower than a given value.

Example

lw{[2,4,5,6,4,3], 4} -> {2,3}

lwe

lwe{set, value} -> {all elements lower or equal than value}
lwe{set, selector, value} -> {all with a selector value lower or equal than value}

Filter a set of element by keeping those lower than or equal to a given value.

Example

lwe{[2,4,5,6,4,3], 4} -> {2,4,3,4}

neq

neq{set, value} -> {all elements not equal to value}
neq{set, selector, value} -> {all selector value not equal to value}

Filter a set of element by keeping those not equal to a given value.

Example

neq{[2,4,5,6,4,3], 4} -> {2,5,6,3}

Utility

print

print(formatString | selector, set)

Print takes a format string (or a selector) and a set of items and prints the formatted results of each item in the console. This can be useful to debug the values of an item.

In a project, the expression:

print{'path=@path', t:texture}

would print the following in the console window:

[path=Assets/Editor/Content/CustomObjectIndexersTests/mobile_friendly.png,path=Assets/Editor/Content/CustomObjectIndexersTests/non_mobile_friendly.png]

Example

print{@value, [1,2,3,4]} would print [1,2,3,4] in the console window.

format

format{expression} -> {set of items where the value is converted to a string}
format{formatString, expression} -> {set of items where the value is set by applying a format string}

Format can be used in two ways. When only a single expression argument is used it will try to convert the current @value of an item to a string representation.

If format is used with a format string, it will replace all selectors in the format string with the selected value of the item and set this formatted string in the @value of the item.

Example

print{format{“value=@value”, [1,2,3,4]}} would print [“value=1”,”value=2”,”value=3”,”value=4”] in the console window.

alias

alias{set, aliasName} -> {each element in set gets assigned an aliasName}
alias{set, formatString} -> {each element in set gets assigned an alias computed from the formatString}

This function effectively assigns an alias to an expression. This is equivalent to using the “as” keyword. For example:

count{t:material as material} is equivalent to:

count{alias{t:material, material}}

Example

Assign the alias “number” to the elements: 1, 2 and 3.

_alias{[1, 2, 3], 'number'} _

alt_text

Example

Assign and alias dynamically computed from a format string to 1,2 and 3:

alt_text

constant

constant{value} -> {constant value}

Attempt to convert the value to a constant literal value: either a number, string or boolean. This can use used to disambiguate parameters type in some specific functions.

This expression:

first{5, t:material} is equivalent to

first{constant{5}, t:material}

query

query{value} -> {query expression}

Attempt to convert value to a query expression. This can use used to disambiguate parameters type in some specific functions.

count{t:material} is equivalent to

count{query{t:material}}

set

set{sets...} -> {set of all elements in all sets}

Create a set of all elements contains in all the sets passed as parameter. This is equivalent to using the “[set, of , element]” notation.

set{[1, 2,3], [4,5,6]} is equivalent to:

1,2,3], [4,5,6 which is equivalent to:

[1,2,3,4,5,6]

text

text{expression} -> {"text of the expression"}

Create a string out of an expression. This is equivalent to using the “” or ‘’ delimiters.

[text{hello}] is equivalent to

[“hello”] or [‘hello’]

random

random{sets...} -> {random elements in each set}

Create a set out of a random elements taken from each sets of items passed as parameter.

Example

This returns a random results in each set:

random{[1,3,5], [6,4,2]} -> {3, 2}