Commit e1035066e95244d011fae87d6a65a85b4adff027
Exists in
master
and in
21 other branches
Merge branch 'support_for_aggregations' of https://github.com/meetrajesh/searchk…
…ick into meetrajesh-support_for_aggregations
Showing
3 changed files
with
127 additions
and
1 deletions
Show diff stats
lib/searchkick/query.rb
... | ... | @@ -266,7 +266,7 @@ module Searchkick |
266 | 266 | # filters |
267 | 267 | filters = where_filters(options[:where]) |
268 | 268 | if filters.any? |
269 | - if options[:facets] | |
269 | + if options[:facets] || options[:aggs] | |
270 | 270 | payload[:filter] = { |
271 | 271 | and: filters |
272 | 272 | } |
... | ... | @@ -336,6 +336,44 @@ module Searchkick |
336 | 336 | end |
337 | 337 | end |
338 | 338 | |
339 | + # aggregations | |
340 | + if options[:aggs] | |
341 | + aggs = options[:aggs] | |
342 | + payload[:aggs] = {} | |
343 | + | |
344 | + if aggs.is_a?(Array) # convert to more advanced syntax | |
345 | + aggs = aggs.map { |f| [f, {}] }.to_h | |
346 | + end | |
347 | + | |
348 | + aggs.each do |field, agg_options| | |
349 | + payload[:aggs][field] = { | |
350 | + terms: { | |
351 | + field: agg_options[:field] || field | |
352 | + } | |
353 | + } | |
354 | + | |
355 | + agg_options.deep_merge!(where: options.fetch(:where, {}).reject { |k| k == field } ) if options[:smart_aggs] == true | |
356 | + agg_filters = where_filters(agg_options[:where]) | |
357 | + | |
358 | + if agg_filters.any? | |
359 | + payload[:aggs][field] = { | |
360 | + filter: { | |
361 | + bool: { | |
362 | + must: agg_filters | |
363 | + } | |
364 | + }, | |
365 | + aggs: { | |
366 | + field => { | |
367 | + terms: { | |
368 | + field: field | |
369 | + } | |
370 | + } | |
371 | + } | |
372 | + } | |
373 | + end | |
374 | + end | |
375 | + end | |
376 | + | |
339 | 377 | # suggestions |
340 | 378 | if options[:suggest] |
341 | 379 | suggest_fields = (searchkick_options[:suggest] || []).map(&:to_s) | ... | ... |
lib/searchkick/results.rb
... | ... | @@ -75,6 +75,17 @@ module Searchkick |
75 | 75 | response["facets"] |
76 | 76 | end |
77 | 77 | |
78 | + def aggs | |
79 | + response["aggregations"].each do |field, filtered_agg| | |
80 | + buckets = filtered_agg[field] | |
81 | + # move the buckets one level above into the field hash | |
82 | + if buckets | |
83 | + filtered_agg.delete(field) | |
84 | + filtered_agg.merge!(buckets) | |
85 | + end | |
86 | + end | |
87 | + end | |
88 | + | |
78 | 89 | def took |
79 | 90 | response["took"] |
80 | 91 | end | ... | ... |
... | ... | @@ -0,0 +1,77 @@ |
1 | +require_relative "test_helper" | |
2 | +require "active_support/core_ext" | |
3 | + | |
4 | +class TestAggs < Minitest::Test | |
5 | + | |
6 | + def setup | |
7 | + super | |
8 | + store [ | |
9 | + {name: "Product Show", latitude: 37.7833, longitude: 12.4167, store_id: 1, in_stock: true, color: "blue", price: 21, created_at: 2.days.ago}, | |
10 | + {name: "Product Hide", latitude: 29.4167, longitude: -98.5000, store_id: 2, in_stock: false, color: "green", price: 25, created_at: 2.days.from_now}, | |
11 | + {name: "Product B", latitude: 43.9333, longitude: -122.4667, store_id: 2, in_stock: false, color: "red", price: 5}, | |
12 | + {name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15} | |
13 | + ] | |
14 | + end | |
15 | + | |
16 | + def test_basic | |
17 | + assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: [:store_id]) | |
18 | + end | |
19 | + | |
20 | + def test_where | |
21 | + assert_equal ({1 => 1}), store_agg(aggs: {store_id: {where: {in_stock: true}}}) | |
22 | + end | |
23 | + | |
24 | + def test_field | |
25 | + assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {}}) | |
26 | + assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {field: "store_id"}}) | |
27 | + assert_equal ({1 => 1, 2 => 2}), store_agg({aggs: {store_id_new: {field: "store_id"}}}, "store_id_new") | |
28 | + end | |
29 | + | |
30 | + def test_where_no_smart_aggs | |
31 | + assert_equal ({2 => 2}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}}) | |
32 | + assert_equal ({2 => 2}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false}}}) | |
33 | + end | |
34 | + | |
35 | + def test_smart_aggs | |
36 | + assert_equal ({1 => 1}), store_agg(where: {in_stock: true}, aggs: [:store_id], smart_aggs: true) | |
37 | + end | |
38 | + | |
39 | + def test_smart_aggs_where | |
40 | + assert_equal ({2 => 1}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}}, smart_aggs: true) | |
41 | + end | |
42 | + | |
43 | + def test_smart_aggs_where_override | |
44 | + assert_equal ({2 => 1}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false, color: "blue"}}}, smart_aggs: true) | |
45 | + assert_equal ({}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false, color: "red"}}}, smart_aggs: true) | |
46 | + end | |
47 | + | |
48 | + def test_smart_aggs_skip_agg | |
49 | + assert_equal ({1 => 1, 2 => 2}), store_agg(where: {store_id: 2}, aggs: [:store_id], smart_aggs: true) | |
50 | + end | |
51 | + | |
52 | + def test_smart_aggs_skip_agg_complex | |
53 | + assert_equal ({1 => 1, 2 => 1}), store_agg(where: {store_id: 2, price: {gt: 5}}, aggs: [:store_id], smart_aggs: true) | |
54 | + end | |
55 | + | |
56 | + def test_multiple_aggs | |
57 | + assert_equal ({"store_id" => {1 => 1, 2 => 2}, "color" => {"blue" => 1, "green" => 1, "red" => 1}}), store_multiple_aggs(aggs: [:store_id, :color]) | |
58 | + end | |
59 | + | |
60 | + protected | |
61 | + | |
62 | + def buckets_as_hash(agg) | |
63 | + agg["buckets"].map { |v| [v["key"], v["doc_count"]] }.to_h | |
64 | + end | |
65 | + | |
66 | + def store_agg(options, agg_key = "store_id") | |
67 | + buckets = Product.search("Product", options).aggs[agg_key] | |
68 | + buckets_as_hash(buckets) | |
69 | + end | |
70 | + | |
71 | + def store_multiple_aggs(options) | |
72 | + Product.search("Product", options).aggs.map do |field, filtered_agg| | |
73 | + [field, buckets_as_hash(filtered_agg)] | |
74 | + end.to_h | |
75 | + end | |
76 | + | |
77 | +end | ... | ... |