ExAliyunOts.Search (ex_aliyun_ots v0.11.0) View Source
Use the multiple efficient index schemas of search index to solve complex query problems.
Here are links to the search section of Alibaba official document: Chinese | English
To use ExAliyunOts, a module that calls use ExAliyunOts has to be defined:
defmodule MyApp.Tablestore do
use ExAliyunOts, instance: :my_instance
endThis automatically defines some search functions in MyApp.Tablestore module, we can use them as helpers when invoke MyApp.Tablestore.search/3, here are some examples:
import MyApp.Tablestore
search "table", "index_name",
search_query: [
query: match_query("age", 28),
sort: [
field_sort("age", order: :desc)
]
]
search "table", "index_name",
search_query: [
query: exists_query("column_a"),
group_bys: [
group_by_field("group_name", "column_b",
sub_group_bys: [
group_by_range("group_name_1", "column_d", [{0, 10}, {10, 20}])
],
sort: [
group_key_sort(:desc)
]
),
group_by_field("group_name2", "column_c")
],
aggs: [
agg_min("aggregation_name", "column_e")
]
]Please notice:
- The statistics(via
:aggs) and GroupBy type aggregations(via:group_bys) can be used at the same time. - The GroupBy type aggregations support the nested sub statistics(via
:sub_aggs) and sub GroupBy type aggregations(via:sub_group_bys). - To ensure the performance and reduce the complexity of aggregations, there is a limitation with a certain number of levels for nesting.
- If you are only care about using
:aggsor:group_bys, meanwhile do not need the returned rows, you can set:limitas 0 to ignore the matched rows return, there will have a better query performance.
Link to this section Summary
Query
Use BoolQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use ExistsQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use GeoBoundingBoxQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use GeoDistanceQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use GeoPolygonQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use MatchAllQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use MatchPhraseQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use MatchQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use NestedQuery as the nested :query option of :search_query option in ExAliyunOts.search/4, the target field
need to be a nested type, it is used to query sub documents of nested type.
Use PrefixQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use RangeQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use TermQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use TermsQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Use WildcardQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Sort
Sort by the value of a column, use it in the nested :sort option of :search_query option in ExAliyunOts.search/4.
Geographic distance sorting, according to the sum of distances between to the input geographical points, sort by the minimum/maximum/average summation value.
Use for the nested type field in field_sort/2 as :nested_filter option, the input filter
is a Query to filter results.
Sort by the primary key(s) of row, use it in the nested :sort option of :search_query option in ExAliyunOts.search/4.
Sort by the relevance score to apply the full-text indexing properly, use it in the nested :sort option of
:search_query option in ExAliyunOts/search/4.
Aggregation
Calculate the average value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Calculate the count of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Calculate the distinct count of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Calculate the maximum value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Calculate the minimum value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Calculate the summation of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
GroupBy
The :group_bys results are grouped according to the value of a field, the same value will be put into a group, finally,
the value of each group and the number corresponding to the value will be returned.
On the query results, group by filters (they're Query usecase), and then get the number of matched filters,
the order of the returned results is the same as that of the added filter(s).
The query results are grouped according to the range from a certain center Geo point, if the distance difference is within a certain range, it will be put into a group, and finally the number of corresponding items in each range will be returned.
The :group_bys results are grouped according to the range of a field, if the field value is within a range,
it will be put into a group, finally, the number corresponding to the value will be returned.
Sort in GroupByField
Use in group_by_field/3 scenario, in ascending/descending order of field literal.
Use in group_by_field/3 scenario, in ascending/descending order of row(s) count.
Use in group_by_field/3 scenario, in ascending/descending order of the value from sub statistics.
Link to this section Query
Specs
Use BoolQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: bool_query(
must: range_query("age", from: 20, to: 32),
must_not: term_query("age", 28)
)
]The following options can be a single Query or a list of Query to combine the "And | Or | At least"
search condition.
Options
:must, specifies the Queries that the query result must match, this option is equivalent to theANDoperator.:must_not, specifies the Queries that the query result must not match, this option is equivalent to theNOToperator.:should, specifies the Queries that the query result may or may not match, this option is equivalent to theORoperator.:minimum_should_match, specifies the minimum number of:shouldthat the query result must match.
Specs
Use ExistsQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: exists_query("values")
] Specs
geo_bounding_box_query( field_name :: String.t(), top_left :: String.t(), bottom_right :: String.t() ) :: map()
Use GeoBoundingBoxQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: geo_bounding_box_query("location", "10,-10", "-10,10")
]Please notice that all geographic coordinates are in "$latitude,$longitude" format.
Specs
geo_distance_query( field_name :: String.t(), distance :: float() | integer(), center_point :: String.t() ) :: map()
Use GeoDistanceQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: geo_distance_query("location", 500_000, "5,5")
]Please notice that all geographic coordinates are in "$latitude,$longitude" format.
Specs
Use GeoPolygonQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: geo_polygon_query("location", ["11,11", "0,0", "1,5"])
]Please notice that all geographic coordinates are in "$latitude,$longitude" format.
Specs
match_all_query() :: map()
Use MatchAllQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: match_all_query()
] Specs
Use MatchPhraseQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Similar to MatchQuery, however, the location relationship of multiple terms after word segmentation will be considered,
multiple terms after word segmentation must exist in the same order and location in the row data to be hit this query.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: match_phrase_query("content", "tablestore")
] Specs
Use MatchQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: match_query("age", 28)
]Official document in Chinese | English
Options
:minimum_should_match, the minimum number of terms that the value of the fieldName field in a row contains when Table Store returns this row in the query result, by default it's 1.:operator, the operator used in a logical operation, by default it'sOr, it means that as long as several terms after the participle are partially hit, they are considered hit this query.
Specs
Use NestedQuery as the nested :query option of :search_query option in ExAliyunOts.search/4, the target field
need to be a nested type, it is used to query sub documents of nested type.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: nested_query(
"content",
term_query("content.header", "header1")
)
]Options
:score_mode, available options have:none|:avg|:max|:total|:min, by default it's:none.
Specs
Use PrefixQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: prefix_query("name", "n")
] Specs
Use RangeQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: range_query(
"score",
from: 60,
to: 80,
include_upper: false,
include_lower: false
)
]Options
:from, the value of the start position.:to, the value of the end position.:include_lower, specifies whether to include the:fromvalue in the result, available options aretrue|false, by default it'strue.:include_upper, specifies whether to include the:tovalue in the result, available options aretrue|false, by default it'strue.
Specs
Use TermQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: term_query("age", 28)
] Specs
Use TermsQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: terms_query("age", [28, 29, 30])
] Specs
Use WildcardQuery as the nested :query option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: wildcard_query("name", "n*")
] Link to this section Sort
Specs
Sort by the value of a column, use it in the nested :sort option of :search_query option in ExAliyunOts.search/4.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
sort: [
field_sort("field_a", order: :desc)
]
]If there's a nested type of search index, and they are a integer or float list, we can use :mode to
sort according to the minimum/maximum/average value of the list, by default it's :nil.
For example, there's a nested type as "values" field, the following query will find "values" field existed as matched rows, and sort by the minimum value of list items.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: exists_query("values"),
sort: [
field_sort("values", mode: :min)
]
]Still for nested type of search index, we can sort by the nested value via :nested_filter option, for example,
sort by the value of "content.header" in :desc order.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: nested_query(
"content",
[
exists_query("content.header")
]
),
sort: [
field_sort("content.header",
order: :desc,
nested_filter: nested_filter(
"content",
prefix_query("content.header", "header")
)
)
]
]Please ensure that the query criteria matched will participate in sorting, if there exists any not matched case will lead to uncertainty of sorting results.
Options
:mode, optional, available options are:min|:max|:avg, by default it's:nil;:order, optional, available options are:asc|:desc, by default it's:asc;:nested_filter, optional, seenested_filter/2for details.
Specs
Geographic distance sorting, according to the sum of distances between to the input geographical points, sort by the minimum/maximum/average summation value.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: geo_distance_query("location", 500_000, "5,5"),
sort: [
geo_distance_sort("location", ["5.14,5.21"], order: :asc)
]
]The input points are a list of string, each format as "$latitude,$longitude".
Options
:order, optional, available options are:asc|:desc;:mode, optional, used for nested type field within integer or float, as:minwill sort by the minimum value of items, as:maxwill sort by the maximum value of items, as:avgwill sort by the average value of items, by default it's:nil;:distance_type, optional, available options are:arc|:plane, as:arcmeans distance calculated by arc surface, as:planemeans distance calculated by plane.
Specs
Use for the nested type field in field_sort/2 as :nested_filter option, the input filter
is a Query to filter results.
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: nested_query(
"content",
[
exists_query("content.header")
]
),
sort: [
field_sort("content.header",
order: :desc,
nested_filter: nested_filter(
"content",
prefix_query("content.header", "header")
)
)
]
]Please ensure that the query criteria matched will participate in sorting, if there exists any not matched case will lead to uncertainty of sorting results.
Specs
pk_sort(order :: :asc | :desc) :: map()
Sort by the primary key(s) of row, use it in the nested :sort option of :search_query option in ExAliyunOts.search/4.
Each search request use this sort by default.
Specs
score_sort(order :: :asc | :desc) :: map()
Sort by the relevance score to apply the full-text indexing properly, use it in the nested :sort option of
:search_query option in ExAliyunOts/search/4.
Link to this section Aggregation
Specs
agg_avg( aggregation_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
Calculate the average value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_avg("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
Options
:missing, when the field is not existed in a row of data, if:missingis not set, the row will be ignored in statistics; if:missingis set, the row will use:missingvalue to participate in the statistics of average value, by default it'snil(not-set).
Specs
Calculate the count of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_sum("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
If the field is not existed in a row of data, then this row does not participate in the statistics of count.
Specs
agg_distinct_count( aggregation_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
Calculate the distinct count of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_distinct_count("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
Options
:missing, when the field is not existed in a row of data, if:missingis not set, the row will be ignored in statistics; if:missingis set, the row will use:missingvalue to participate in the statistics of distinct count, by default it'snil(not-set).
Specs
agg_max( aggregation_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
Calculate the maximum value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_max("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
Options
:missing, when the field is not existed in a row of data, if:missingis not set, the row will be ignored in statistics; if:missingis set, the row will use:missingvalue to participate in the statistics of maximum value, by default it'snil(not-set).
Specs
agg_min( aggregation_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
Calculate the minimum value of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_min("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
Options
:missing, when the field is not existed in a row of data, if:missingis not set, the row will be ignored in statistics; if:missingis set, the row will use:missingvalue to participate in the statistics of minimum value, by default it'snil(not-set).
Specs
agg_sum( aggregation_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
Calculate the summation of the assigned field by aggregation in the nested :aggs option of :search_query
option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
aggs: [
agg_sum("agg_name", "score")
]
]The aggregation_name can be any business description string, when get the calculated results, we need to use
it to fetch them.
Options
:missing, when the field is not existed in a row of data, if:missingis not set, the row will be ignored in statistics; if:missingis set, the row will use:missingvalue to participate in the statistics of summation value, by default it'snil(not-set).
Link to this section GroupBy
Specs
group_by_field( group_name :: String.t(), field_name :: String.t(), options :: Keyword.t() ) :: map()
The :group_bys results are grouped according to the value of a field, the same value will be put into a group, finally,
the value of each group and the number corresponding to the value will be returned.
We can set it in the nested :group_bys option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_field("group_name", "type",
size: 3,
sub_group_bys: [
group_by_field("sub_gn1", "is_actived")
],
sort: [
row_count_sort(:asc),
group_key_sort(:desc)
]
),
group_by_field("group_name2", "is_actived")
]
]The group_name can be any business description string, when get the grouped results, we need to use
it to fetch them.
Options
:sort, optional, add sorting rules for items in a group, by default, sort in descending order according to the quantity of items in the group. Supportgroup_key_sort/1|row_count_sort/1|sub_agg_sort/2sort.:size, optional, the number of returned groups.:sub_group_bys, optional, add sub GroupBy type aggregations.:sub_aggs, optional, add sub statistics.
Specs
On the query results, group by filters (they're Query usecase), and then get the number of matched filters,
the order of the returned results is the same as that of the added filter(s).
We can set it in the nested :group_bys option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_filter(
"group_name",
[
term_query("is_actived", true),
range_query("price", from: 50)
]
)
]
]Options
:sub_group_bys, optional, add sub GroupBy type aggregations.:sub_aggs, optional, add sub statistics.
group_by_geo_distance(group_name, field_name, ranges, options \\ [])
View SourceSpecs
group_by_geo_distance( group_name :: String.t(), field_name :: String.t(), ranges :: list(), options :: Keyword.t() ) :: map()
The query results are grouped according to the range from a certain center Geo point, if the distance difference is within a certain range, it will be put into a group, and finally the number of corresponding items in each range will be returned.
We can set it in the nested :group_bys option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_geo_distance("test", "location",
[
{0, 100_000},
{100_000, 500_000},
{500_000, 1000_000},
],
lon: 0,
lat: 0,
sub_aggs: [
agg_sum("test_sum", "value")
]
)
]
]Options
:lon, required, the longitude of the origin center point, integer or float.:lat, required, the latitude of the origin center point, integer or float.:sub_group_bys, optional, add sub GroupBy type aggregations.:sub_aggs, optional, add sub statistics.
Specs
group_by_range( group_name :: String.t(), field_name :: String.t(), ranges :: list(), options :: Keyword.t() ) :: map()
The :group_bys results are grouped according to the range of a field, if the field value is within a range,
it will be put into a group, finally, the number corresponding to the value will be returned.
We can set it in the nested :group_bys option of :search_query option in ExAliyunOts.search/4.
Official document in Chinese | English
Example
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_range("group_name", "price",
[
{0, 18},
{18, 50}
],
sub_group_bys: [
group_by_field("sorted_by_type", "type",
sort: [
group_key_sort(:asc)
]
)
],
sub_aggs: [
agg_distinct_count("distinct_price", "price")
]
)
]
]The group_name can be any business description string, when get the grouped results, we need to use
it to fetch them.
Please notice that each range item(as a tuple, according to {from, to}) of ranges, its start is greater
than or equal to from, and its ending is less than to, the range interval value can be integer or float.
Options
:sub_group_bys, optional, add sub GroupBy type aggregations.:sub_aggs, optional, add sub statistics.
Link to this section Define Field Schema
Specs
Official document in Chinese | English
Example
field_schema_boolean("status")Options
:index, specifies whether to set as index, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."[false,true,false]".
Specs
Official document in Chinese | English
Example
field_schema_float("price")Options
:index, specifies whether to set as index, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."[1.0,2.0]".
Official document in Chinese | English
Example
field_schema_geo_point("location")Options
:index, specifies whether to set as index, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."["10.21,10","10.31,9.98"]".
Specs
Official document in Chinese | English
Example
field_schema_integer("age")Options
:index, specifies whether to set as index, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."[1,2]".
Official document in Chinese | English
Example
field_schema_keyword("status")Options
:index, specifies whether to set as index, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."["a","b"]".
Official document in Chinese | English
Example
field_schema_nested(
"content",
field_schemas: [
field_schema_keyword("header"),
field_schema_keyword("body"),
]Options
:field_schemas, required, the nested field schema(s);:index, specifies whether to set as index, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:enable_sort_and_agg, specifies whether to support sort and statistics, by default it is true.
Official document in Chinese | English
Example
field_schema_text("content")Options
:index, specifies whether to set as index, by default it is true;:store, specifies whether to store the origin value in search index for a better read performance, by default it is true;:is_array, specifies whether the stored data is a JSON encoded list as a string, e.g."["a","b"]".:analyzer, optional, please see analyzer document in Chinese | English.
Link to this section Sort in GroupByField
Specs
group_key_sort(order :: :asc | :desc) :: map()
Use in group_by_field/3 scenario, in ascending/descending order of field literal.
Official document in Chinese | English
Example
In the following example, the returned results will be sorted in descending order of the "type" field:
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_field(
"group_name",
"type",
sub_group_bys: [
...
],
sort: [
group_key_sort(:desc)
]
)
]
] Specs
row_count_sort(order :: :asc | :desc) :: %ExAliyunOts.Var.Search.RowCountSort{
order: term()
}
Use in group_by_field/3 scenario, in ascending/descending order of row(s) count.
Official document in Chinese | English
Example
In the following example, the returned results will be sorted in ascending order of the matched row(s):
import MyApp.TableStore
search "table", "index_name",
search_query: [
query: ...,
group_bys: [
group_by_field(
"group_name",
"type",
sub_group_bys: [
...
],
sort: [
row_count_sort(:asc)
]
)
]
] Specs
Use in group_by_field/3 scenario, in ascending/descending order of the value from sub statistics.