#
Aggregations
You can define simple to complex aggregations.
class ArticleSearch < Caoutsearch::Search::Base
has_aggregation :view_count, { sum: { field: :view_count } }
has_aggregation :popular_tags, {
filter: { term: { published: true } },
aggs: {
published: {
terms: { field: :tags, size: 10 }
}
}
}
end
Then you can request one or more aggregations at the same time or chain the aggregate
method.
The aggregations
method will trigger a request and returns a Response::Aggregations.
ArticleSearch.aggregate(:view_count).aggregations
# ArticleSearch Search { "body": { "aggs": { "view_count": { "sum": { "field": "view_count" }}}}}
# ArticleSearch Search (10ms / took 5ms)
=> #<Caoutsearch::Response::Aggregations view_count=#<Caoutsearch::Response::Response value=119652>>
ArticleSearch.aggregate(:view_count, :popular_tags).aggregations
# ArticleSearch Search { "body": { "aggs": { "view_count": {…}, "popular_tags": {…}}}}
# ArticleSearch Search (10ms / took 5ms)
=> #<Caoutsearch::Response::Aggregations view_count=#<Caoutsearch::Response::Response value=119652> popular_tags=#<Caoutsearch::Response::Response buckets=…>>
ArticleSearch.aggregate(:view_count).aggregate(:popular_tags).aggregations
# ArticleSearch Search { "body": { "aggs": { "view_count": {…}, "popular_tags": {…}}}}
# ArticleSearch Search (10ms / took 5ms)
=> #<Caoutsearch::Response::Aggregations view_count=#<Caoutsearch::Response::Response value=119652> popular_tags=#<Caoutsearch::Response::Response buckets=…>>
You can create powerful aggregations using blocks and pass arguments to them.
class ArticleSearch < Caoutsearch::Search::Base
has_aggregation :popular_tags_since do |date|
raise TypeError unless date.is_a?(Date)
query.aggregations[:popular_tags_since] = {
filter: { range: { publication_date: { gte: date.to_s } } },
aggs: {
published: {
terms: { field: :tags, size: 20 }
}
}
}
end
end
ArticleSearch.aggregate(popular_tags_since: 1.day.ago).aggregations
# ArticleSearch Search { "body": { "aggs": { "popular_tags_since": {…}}}}
# ArticleSearch Search (10ms / took 5ms)
=> #<Caoutsearch::Response::Aggregations popular_tags_since=#<Caoutsearch::Response::Response …
Only one argument can be passed to an aggregation block.
Use an Array or a Hash if you need to pass multiple options.
class ArticleSearch < Caoutsearch::Search::Base
has_aggregation :popular_tags_since do |options|
# …
end
has_aggregation :popular_tags_between do |(first_date, end_date)|
# …
end
end
ArticleSearch.aggregate(popular_tags_since: { date: 1.day.ago, size: 20 })
ArticleSearch.aggregate(popular_tags_between: [date1, date2])
Finally, you can create a "catch-all" aggregation to handle cumbersome behaviors:
class ArticleSearch < Caoutsearch::Search::Base
has_aggregation do |name, options = {}|
raise "unxpected_error" unless name.match?(/^view_count_(?<year>\d{4})$/)
query.aggregations[name] = {
filter: { term: { year: $LAST_LATCH_INFO[:year] } },
aggs: {
filtered: {
sum: { field: :view_count }
}
}
}
end
end
ArticleSearch.aggregate(:view_count_2020, :view_count_2019).aggregations
# ArticleSearch Search { "body": { "aggs": { "view_count_2020": {…}, "view_count_2019": {…}}}}
# ArticleSearch Search (10ms / took 5ms)
=> #<Caoutsearch::Response::Aggregations view_count_2020=#<Caoutsearch::Response::Response …