-
Notifications
You must be signed in to change notification settings - Fork 19
Search Expressions
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.
Enter a search expression in the Search window to return a result:
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.
- The
-
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
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 "" )
|
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.
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).
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}
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
-
t:texture
: finds all texture in the project and then selects the size property. -
sort{ t:texture, @size}
: sorts all these textures according to their size property. -
first{10
: selects the first 10 sorted textures. -
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 itempath=@path
.
Example in the **Console **window:
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)
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.
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 namedassets
and then selects thetype
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.
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:
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)
>>>>>
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}
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}
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}
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.
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.
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}
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.
count{...groupBy{a:assets, @type}} -> {numberOfAssetType1, numberOfAssetType2, ... numberOfAssetTypeN}
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}
A project has three types of assets (prefabs, shaders, and textures). The following expression would count all prefabs, shaders and textures.
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}}
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.
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}}
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
Running the query t:texture
in a project:
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}
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:
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}}
- For each texture in the project, create a new search item (
t:texture
) - whose label is equal to the @path of the texture (
@path
) - 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.
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:
- For each script in my project create a new item (t:script)
- Create a new property called mypath in the item and assign it the value of the selector @path.
- Use the print function to print on the console the value of the @mypath selector.
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.
This example shows that duplicate are removed.
union{[1,2,3], [3,4,5]} -> {1,2,3,4,5}
union{*.mat, t:shader} -> {all materials and shaders in the project}
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.
This example shows that duplicates are removed.
distinct{[1,2,3], [3,4,5]} -> {1,2,3,4,5}
distinct{*.mat, t:shader} -> {all materials and shaders in the project}
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{set, sets...} -> {New set of elements}
Takes all elements in set that are not in any of the sets passed as parameters.
except{[1,2,3,4,5], [2,3], [5], [6]} -> {1,4}
except{t:prefab, t:prefab ref=select{t:texture, @path}}
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.
intersect{[1,2,3,4,5], [3, 5], [6, 3]} -> {3}
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{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.
first{[3, 4,5], [9, 28, 3]} -> {3,9}
first{3, [9, 28, 3, 4, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7]} -> {9, 28, 3, 1, 2, 3}
Sort all fbx files in my project by descending order and take the 3 biggest.
first{3,sort{*.fbx, @size, desc}}
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.
last{[3, 4,5], [9, 28, 3]} -> {5, 3}
last{3, [9, 28, 3, 4, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7]} -> {7,8,9,5,6,7}
Sort all fbx files in my project by ascending order and take the 3 biggest (the last ones)
last{3,sort{*.fbx, @size}}
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.
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}
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}
Sort all textures in my project according to their @size in descending order (from largest to smallest).
sort{t:texture, @size, desc}
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.
avg{[1,2,3,4, 5,6], [1, 1, 1], []} -> {3.5, 1, 1}
avg{@size, t:texture, t:material} -> {1100576, 3618}
count{sets...} -> {count of each set}
Count the number of results in each set passed as parameters.
count{t:texture, t:material} -> {359, 194}
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)
>>>>>
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.
max{[1,2,3,4,5,6], [2,4,5]} -> {6, 5}
Find the biggest png and the biggest jpg.
max{@size, *.png, *.jpg} -> {<biggest png>, <biggest jpg>}
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.
min{[1,2,3,4,5,6], [2,4,5]} -> {1, 2}
Find the smallest png and the biggest jpg.
min{@size, *.png, *.jpg} -> {<smallest png>, <smallest jpg>}
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.
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}
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.
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}
Finding all audio clips containing the word effect
in their path:
where{t:AudioClip, @path:effect}
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.
eq{[2,4,5,6,4,3], 4} -> {4,4} this is equivalent to :
where{[2,4,5,6,4,3], “@value=4”}
Find all textures with a #width serialized property of 256.
_eq{t:texture, #width, 256} _this is equivalent to
t:texture #width=256
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.
gt{[2,4,5,6,4,3], 4} -> {5,6}
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.
gte{[2,4,5,6,4,3], 4} -> {4,5,6,4}
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.
lw{[2,4,5,6,4,3], 4} -> {2,3}
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.
lwe{[2,4,5,6,4,3], 4} -> {2,4,3,4}
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.
neq{[2,4,5,6,4,3], 4} -> {2,5,6,3}
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]
print{@value, [1,2,3,4]} would print [1,2,3,4] in the console window.
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.
print{format{“value=@value”, [1,2,3,4]}} would print [“value=1”,”value=2”,”value=3”,”value=4”] in the console window.
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}}
Assign the alias “number” to the elements: 1, 2 and 3.
_alias{[1, 2, 3], 'number'} _
Assign and alias dynamically computed from a format string to 1,2 and 3:
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{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{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{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{sets...} -> {random elements in each set}
Create a set out of a random elements taken from each sets of items passed as parameter.
This returns a random results in each set:
random{[1,3,5], [6,4,2]} -> {3, 2}