Module: ParadeDB::Aggregations

Defined in:
lib/parade_db/aggregations.rb

Overview

Typed helpers for building agg JSON payloads passed to pdb.agg(…).

Defined Under Namespace

Classes: FieldTermFilter, FilteredSpec

Constant Summary collapse

TERMS_ORDER =
{
  count_desc: { "_count" => "desc" },
  count_asc: { "_count" => "asc" },
  key_desc: { "_key" => "desc" },
  key_asc: { "_key" => "asc" }
}.freeze

Class Method Summary collapse

Class Method Details

.avg(field) ⇒ Object



50
51
52
# File 'lib/parade_db/aggregations.rb', line 50

def avg(field)
  metric("avg", field)
end

.build_named_payload(named_aggregations) ⇒ Object

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
35
36
# File 'lib/parade_db/aggregations.rb', line 28

def build_named_payload(named_aggregations)
  specs = named_aggregations.to_h
  raise ArgumentError, "with_agg/facets_agg requires at least one named aggregation" if specs.empty?

  specs.each_with_object({}) do |(alias_name, spec), payload|
    alias_key = normalize_alias(alias_name)
    payload[alias_key] = normalize_named_spec(spec)
  end
end

.date_histogram(field, calendar_interval: nil, fixed_interval: nil, interval: nil, min_doc_count: nil, offset: nil, time_zone: nil, format: nil, hard_bounds: nil, extended_bounds: nil) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/parade_db/aggregations.rb', line 91

def date_histogram(
  field,
  calendar_interval: nil,
  fixed_interval: nil,
  interval: nil,
  min_doc_count: nil,
  offset: nil,
  time_zone: nil,
  format: nil,
  hard_bounds: nil,
  extended_bounds: nil
)
  interval_args = {
    "calendar_interval" => calendar_interval,
    "fixed_interval" => fixed_interval,
    "interval" => interval
  }.compact

  if interval_args.empty?
    raise ArgumentError, "date_histogram requires one of: calendar_interval, fixed_interval, interval"
  end

  if interval_args.length > 1
    raise ArgumentError, "date_histogram interval arguments are mutually exclusive"
  end

  payload = { "field" => normalize_field(field) }.merge(interval_args)
  payload["min_doc_count"] = normalize_non_negative_integer(min_doc_count, "min_doc_count") unless min_doc_count.nil?
  payload["offset"] = offset unless offset.nil?
  payload["time_zone"] = time_zone unless time_zone.nil?
  payload["format"] = format unless format.nil?
  payload["hard_bounds"] = normalize_bounds(hard_bounds, "hard_bounds") unless hard_bounds.nil?
  payload["extended_bounds"] = normalize_bounds(extended_bounds, "extended_bounds") unless extended_bounds.nil?
  { "date_histogram" => payload }
end

.filtered(spec, filter: nil, field: nil, term: nil, distance: nil, prefix: nil, transposition_cost_one: nil) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/parade_db/aggregations.rb', line 157

def filtered(spec, filter: nil, field: nil, term: nil, distance: nil, prefix: nil, transposition_cost_one: nil)
  normalized_spec = normalize_spec(spec)
  normalized_filter = normalize_filter(
    filter: filter,
    field: field,
    term: term,
    distance: distance,
    prefix: prefix,
    transposition_cost_one: transposition_cost_one
  )
  FilteredSpec.new(spec: normalized_spec, agg_filter: normalized_filter)
end

.histogram(field, interval:, min_doc_count: nil, offset: nil, hard_bounds: nil, extended_bounds: nil) ⇒ Object

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/parade_db/aggregations.rb', line 77

def histogram(field, interval:, min_doc_count: nil, offset: nil, hard_bounds: nil, extended_bounds: nil)
  raise ArgumentError, "interval is required" if interval.nil?

  payload = {
    "field" => normalize_field(field),
    "interval" => interval
  }
  payload["min_doc_count"] = normalize_non_negative_integer(min_doc_count, "min_doc_count") unless min_doc_count.nil?
  payload["offset"] = offset unless offset.nil?
  payload["hard_bounds"] = normalize_bounds(hard_bounds, "hard_bounds") unless hard_bounds.nil?
  payload["extended_bounds"] = normalize_bounds(extended_bounds, "extended_bounds") unless extended_bounds.nil?
  { "histogram" => payload }
end

.max(field) ⇒ Object



62
63
64
# File 'lib/parade_db/aggregations.rb', line 62

def max(field)
  metric("max", field)
end

.min(field) ⇒ Object



58
59
60
# File 'lib/parade_db/aggregations.rb', line 58

def min(field)
  metric("min", field)
end

.percentiles(field, percents:) ⇒ Object

Raises:

  • (ArgumentError)


70
71
72
73
74
75
# File 'lib/parade_db/aggregations.rb', line 70

def percentiles(field, percents:)
  values = Array(percents)
  raise ArgumentError, "percents must include at least one value" if values.empty?

  { "percentiles" => { "field" => normalize_field(field), "percents" => values } }
end

.range(field, ranges:) ⇒ Object

Raises:

  • (ArgumentError)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/parade_db/aggregations.rb', line 127

def range(field, ranges:)
  serialized_ranges = Array(ranges).map do |entry|
    raise ArgumentError, "range entries must be Hash values" unless entry.is_a?(Hash)

    normalized = deep_stringify(entry)
    unless normalized.key?("from") || normalized.key?("to")
      raise ArgumentError, "range entries require at least one of: from, to"
    end

    normalized
  end
  raise ArgumentError, "ranges must include at least one entry" if serialized_ranges.empty?

  {
    "range" => {
      "field" => normalize_field(field),
      "ranges" => serialized_ranges
    }
  }
end

.stats(field) ⇒ Object



66
67
68
# File 'lib/parade_db/aggregations.rb', line 66

def stats(field)
  metric("stats", field)
end

.sum(field) ⇒ Object



54
55
56
# File 'lib/parade_db/aggregations.rb', line 54

def sum(field)
  metric("sum", field)
end

.terms(field, size: 10, order: :count_desc, missing: nil) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/parade_db/aggregations.rb', line 38

def terms(field, size: 10, order: :count_desc, missing: nil)
  terms_payload = { "field" => normalize_field(field) }
  terms_payload["size"] = normalize_non_negative_integer(size, "size") unless size.nil?
  terms_payload["order"] = normalize_terms_order(order) unless order.nil?
  terms_payload["missing"] = missing unless missing.nil?
  { "terms" => terms_payload }
end

.top_hits(size: nil, from: nil, sort: nil, docvalue_fields: nil) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/parade_db/aggregations.rb', line 148

def top_hits(size: nil, from: nil, sort: nil, docvalue_fields: nil)
  payload = {}
  payload["size"] = normalize_non_negative_integer(size, "size") unless size.nil?
  payload["from"] = normalize_non_negative_integer(from, "from") unless from.nil?
  payload["sort"] = normalize_top_hits_sort(sort) unless sort.nil?
  payload["docvalue_fields"] = normalize_docvalue_fields(docvalue_fields) unless docvalue_fields.nil?
  { "top_hits" => payload }
end

.value_count(field) ⇒ Object



46
47
48
# File 'lib/parade_db/aggregations.rb', line 46

def value_count(field)
  metric("value_count", field)
end