Skip to content

Commit 98a37e9

Browse files
DOC-4296 added aggregation query examples (#3967)
Co-authored-by: M Sazzadul Hoque <[email protected]>
1 parent 8094063 commit 98a37e9

File tree

1 file changed

+353
-0
lines changed

1 file changed

+353
-0
lines changed
Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
// EXAMPLE: query_agg
2+
// REMOVE_START
3+
package io.redis.examples;
4+
5+
import org.junit.Assert;
6+
import org.junit.Test;
7+
// REMOVE_END
8+
9+
// HIDE_START
10+
import java.util.List;
11+
import java.util.ArrayList;
12+
import redis.clients.jedis.UnifiedJedis;
13+
import redis.clients.jedis.json.Path2;
14+
import redis.clients.jedis.search.FTCreateParams;
15+
import redis.clients.jedis.search.IndexDataType;
16+
import redis.clients.jedis.search.schemafields.*;
17+
import redis.clients.jedis.search.aggr.*;
18+
import redis.clients.jedis.exceptions.JedisDataException;
19+
// HIDE_END
20+
21+
// HIDE_START
22+
public class QueryAggExample {
23+
@Test
24+
public void run() {
25+
UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
26+
27+
//REMOVE_START
28+
// Clear any keys here before using them in tests.
29+
try { jedis.ftDropIndex("idx:bicycle"); } catch (JedisDataException j) {}
30+
//REMOVE_END
31+
// HIDE_END
32+
33+
SchemaField[] schema = {
34+
TextField.of("$.brand").as("brand"),
35+
TextField.of("$.model").as("model"),
36+
TextField.of("$.description").as("description"),
37+
NumericField.of("$.price").as("price"),
38+
TagField.of("$.condition").as("condition")
39+
};
40+
41+
jedis.ftCreate("idx:bicycle",
42+
FTCreateParams.createParams()
43+
.on(IndexDataType.JSON)
44+
.addPrefix("bicycle:"),
45+
schema
46+
);
47+
48+
String[] bicycleJsons = new String[] {
49+
" {"
50+
+ " \"pickup_zone\": \"POLYGON((-74.0610 40.7578, -73.9510 40.7578, -73.9510 40.6678, "
51+
+ "-74.0610 40.6678, -74.0610 40.7578))\","
52+
+ " \"store_location\": \"-74.0060,40.7128\","
53+
+ " \"brand\": \"Velorim\","
54+
+ " \"model\": \"Jigger\","
55+
+ " \"price\": 270,"
56+
+ " \"description\": \"Small and powerful, the Jigger is the best ride for the smallest of tikes! "
57+
+ "This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger "
58+
+ "is the vehicle of choice for the rare tenacious little rider raring to go.\","
59+
+ " \"condition\": \"new\""
60+
+ " }",
61+
62+
" {"
63+
+ " \"pickup_zone\": \"POLYGON((-118.2887 34.0972, -118.1987 34.0972, -118.1987 33.9872, "
64+
+ "-118.2887 33.9872, -118.2887 34.0972))\","
65+
+ " \"store_location\": \"-118.2437,34.0522\","
66+
+ " \"brand\": \"Bicyk\","
67+
+ " \"model\": \"Hillcraft\","
68+
+ " \"price\": 1200,"
69+
+ " \"description\": \"Kids want to ride with as little weight as possible. Especially "
70+
+ "on an incline! They may be at the age when a 27.5'' wheel bike is just too clumsy coming "
71+
+ "off a 24'' bike. The Hillcraft 26 is just the solution they need!\","
72+
+ " \"condition\": \"used\""
73+
+ " }",
74+
75+
" {"
76+
+ " \"pickup_zone\": \"POLYGON((-87.6848 41.9331, -87.5748 41.9331, -87.5748 41.8231, "
77+
+ "-87.6848 41.8231, -87.6848 41.9331))\","
78+
+ " \"store_location\": \"-87.6298,41.8781\","
79+
+ " \"brand\": \"Nord\","
80+
+ " \"model\": \"Chook air 5\","
81+
+ " \"price\": 815,"
82+
+ " \"description\": \"The Chook Air 5 gives kids aged six years and older a durable "
83+
+ "and uberlight mountain bike for their first experience on tracks and easy cruising through "
84+
+ "forests and fields. The lower top tube makes it easy to mount and dismount in any "
85+
+ "situation, giving your kids greater safety on the trails.\","
86+
+ " \"condition\": \"used\""
87+
+ " }",
88+
89+
" {"
90+
+ " \"pickup_zone\": \"POLYGON((-80.2433 25.8067, -80.1333 25.8067, -80.1333 25.6967, "
91+
+ "-80.2433 25.6967, -80.2433 25.8067))\","
92+
+ " \"store_location\": \"-80.1918,25.7617\","
93+
+ " \"brand\": \"Eva\","
94+
+ " \"model\": \"Eva 291\","
95+
+ " \"price\": 3400,"
96+
+ " \"description\": \"The sister company to Nord, Eva launched in 2005 as the first "
97+
+ "and only women-dedicated bicycle brand. Designed by women for women, allEva bikes "
98+
+ "are optimized for the feminine physique using analytics from a body metrics database. "
99+
+ "If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This "
100+
+ "full-suspension, cross-country ride has been designed for velocity. The 291 has "
101+
+ "100mm of front and rear travel, a superlight aluminum frame and fast-rolling "
102+
+ "29-inch wheels. Yippee!\","
103+
+ " \"condition\": \"used\""
104+
+ " }",
105+
106+
" {"
107+
+ " \"pickup_zone\": \"POLYGON((-122.4644 37.8199, -122.3544 37.8199, -122.3544 37.7099, "
108+
+ "-122.4644 37.7099, -122.4644 37.8199))\","
109+
+ " \"store_location\": \"-122.4194,37.7749\","
110+
+ " \"brand\": \"Noka Bikes\","
111+
+ " \"model\": \"Kahuna\","
112+
+ " \"price\": 3200,"
113+
+ " \"description\": \"Whether you want to try your hand at XC racing or are looking "
114+
+ "for a lively trail bike that's just as inspiring on the climbs as it is over rougher "
115+
+ "ground, the Wilder is one heck of a bike built specifically for short women. Both the "
116+
+ "frames and components have been tweaked to include a women’s saddle, different bars "
117+
+ "and unique colourway.\","
118+
+ " \"condition\": \"used\""
119+
+ " }",
120+
121+
" {"
122+
+ " \"pickup_zone\": \"POLYGON((-0.1778 51.5524, 0.0822 51.5524, 0.0822 51.4024, "
123+
+ "-0.1778 51.4024, -0.1778 51.5524))\","
124+
+ " \"store_location\": \"-0.1278,51.5074\","
125+
+ " \"brand\": \"Breakout\","
126+
+ " \"model\": \"XBN 2.1 Alloy\","
127+
+ " \"price\": 810,"
128+
+ " \"description\": \"The XBN 2.1 Alloy is our entry-level road bike – but that’s "
129+
+ "not to say that it’s a basic machine. With an internal weld aluminium frame, a full "
130+
+ "carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which "
131+
+ "doesn’t break the bank and delivers craved performance.\","
132+
+ " \"condition\": \"new\""
133+
+ " }",
134+
135+
" {"
136+
+ " \"pickup_zone\": \"POLYGON((2.1767 48.9016, 2.5267 48.9016, 2.5267 48.5516, "
137+
+ "2.1767 48.5516, 2.1767 48.9016))\","
138+
+ " \"store_location\": \"2.3522,48.8566\","
139+
+ " \"brand\": \"ScramBikes\","
140+
+ " \"model\": \"WattBike\","
141+
+ " \"price\": 2300,"
142+
+ " \"description\": \"The WattBike is the best e-bike for people who still "
143+
+ "feel young at heart. It has a Bafang 1000W mid-drive system and a 48V 17.5AH "
144+
+ "Samsung Lithium-Ion battery, allowing you to ride for more than 60 miles on one "
145+
+ "charge. It’s great for tackling hilly terrain or if you just fancy a more "
146+
+ "leisurely ride. With three working modes, you can choose between E-bike, "
147+
+ "assisted bicycle, and normal bike modes.\","
148+
+ " \"condition\": \"new\""
149+
+ " }",
150+
151+
" {"
152+
+ " \"pickup_zone\": \"POLYGON((13.3260 52.5700, 13.6550 52.5700, 13.6550 52.2700, "
153+
+ "13.3260 52.2700, 13.3260 52.5700))\","
154+
+ " \"store_location\": \"13.4050,52.5200\","
155+
+ " \"brand\": \"Peaknetic\","
156+
+ " \"model\": \"Secto\","
157+
+ " \"price\": 430,"
158+
+ " \"description\": \"If you struggle with stiff fingers or a kinked neck or "
159+
+ "back after a few minutes on the road, this lightweight, aluminum bike alleviates "
160+
+ "those issues and allows you to enjoy the ride. From the ergonomic grips to the "
161+
+ "lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. "
162+
+ "The rear-inclined seat tube facilitates stability by allowing you to put a foot "
163+
+ "on the ground to balance at a stop, and the low step-over frame makes it "
164+
+ "accessible for all ability and mobility levels. The saddle is very soft, with "
165+
+ "a wide back to support your hip joints and a cutout in the center to redistribute "
166+
+ "that pressure. Rim brakes deliver satisfactory braking control, and the wide tires "
167+
+ "provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts "
168+
+ "facilitate setting up the Roll Low-Entry as your preferred commuter, and the "
169+
+ "BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder.\","
170+
+ " \"condition\": \"new\""
171+
+ " }",
172+
173+
" {"
174+
+ " \"pickup_zone\": \"POLYGON((1.9450 41.4301, 2.4018 41.4301, 2.4018 41.1987, "
175+
+ "1.9450 41.1987, 1.9450 41.4301))\","
176+
+ " \"store_location\": \"2.1734, 41.3851\","
177+
+ " \"brand\": \"nHill\","
178+
+ " \"model\": \"Summit\","
179+
+ " \"price\": 1200,"
180+
+ " \"description\": \"This budget mountain bike from nHill performs well both "
181+
+ "on bike paths and on the trail. The fork with 100mm of travel absorbs rough "
182+
+ "terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. "
183+
+ "The Shimano Tourney drivetrain offered enough gears for finding a comfortable "
184+
+ "pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. "
185+
+ "Whether you want an affordable bike that you can take to work, but also take "
186+
+ "trail in mountains on the weekends or you’re just after a stable, comfortable "
187+
+ "ride for the bike path, the Summit gives a good value for money.\","
188+
+ " \"condition\": \"new\""
189+
+ " }",
190+
191+
" {"
192+
+ " \"pickup_zone\": \"POLYGON((12.4464 42.1028, 12.5464 42.1028, "
193+
+ "12.5464 41.7028, 12.4464 41.7028, 12.4464 42.1028))\","
194+
+ " \"store_location\": \"12.4964,41.9028\","
195+
+ " \"model\": \"ThrillCycle\","
196+
+ " \"brand\": \"BikeShind\","
197+
+ " \"price\": 815,"
198+
+ " \"description\": \"An artsy, retro-inspired bicycle that’s as "
199+
+ "functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. "
200+
+ "A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t "
201+
+ "suggest taking it to the mountains. Fenders protect you from mud, and a rear "
202+
+ "basket lets you transport groceries, flowers and books. The ThrillCycle comes "
203+
+ "with a limited lifetime warranty, so this little guy will last you long "
204+
+ "past graduation.\","
205+
+ " \"condition\": \"refurbished\""
206+
+ " }"
207+
};
208+
209+
for (int i = 0; i < bicycleJsons.length; i++) {
210+
jedis.jsonSet("bicycle:" + i, new Path2("$"), bicycleJsons[i]);
211+
}
212+
213+
// STEP_START agg1
214+
AggregationResult res1 = jedis.ftAggregate("idx:bicycle",
215+
new AggregationBuilder("@condition:{new}")
216+
.load("__key", "price")
217+
.apply("@price - (@price * 0.1)", "discounted")
218+
);
219+
220+
List<Row> rows1 = res1.getRows();
221+
System.out.println(rows1.size()); // >>> 5
222+
223+
for (int i = 0; i < rows1.size(); i++) {
224+
System.out.println(rows1.get(i));
225+
}
226+
// >>> {__key=bicycle:0, discounted=243, price=270}
227+
// >>> {__key=bicycle:5, discounted=729, price=810}
228+
// >>> {__key=bicycle:6, discounted=2070, price=2300}
229+
// >>> {__key=bicycle:7, discounted=387, price=430}
230+
// >>> {__key=bicycle:8, discounted=1080, price=1200}
231+
// STEP_END
232+
233+
// Tests for 'agg1' step.
234+
// REMOVE_START
235+
Assert.assertEquals(5, rows1.size());
236+
Assert.assertEquals("{__key=bicycle:0, discounted=243, price=270}", rows1.get(0).toString());
237+
Assert.assertEquals("{__key=bicycle:5, discounted=729, price=810}", rows1.get(1).toString());
238+
Assert.assertEquals("{__key=bicycle:6, discounted=2070, price=2300}", rows1.get(2).toString());
239+
Assert.assertEquals("{__key=bicycle:7, discounted=387, price=430}", rows1.get(3).toString());
240+
Assert.assertEquals("{__key=bicycle:8, discounted=1080, price=1200}", rows1.get(4).toString());
241+
// REMOVE_END
242+
243+
244+
// STEP_START agg2
245+
AggregationResult res2 = jedis.ftAggregate("idx:bicycle",
246+
new AggregationBuilder("*")
247+
.load("price")
248+
.apply("@price<1000", "price_category")
249+
.groupBy("@condition",
250+
Reducers.sum("@price_category").as("num_affordable"))
251+
);
252+
253+
List<Row> rows2 = res2.getRows();
254+
System.out.println(rows2.size()); // >>> 3
255+
256+
for (int i = 0; i < rows2.size(); i++) {
257+
System.out.println(rows2.get(i));
258+
}
259+
// >>> {condition=refurbished, num_affordable=1}
260+
// >>> {condition=used, num_affordable=1}
261+
// >>> {condition=new, num_affordable=3}
262+
// STEP_END
263+
264+
// Tests for 'agg2' step.
265+
// REMOVE_START
266+
Assert.assertEquals(3, rows2.size());
267+
Assert.assertEquals("{condition=refurbished, num_affordable=1}", rows2.get(0).toString());
268+
Assert.assertEquals("{condition=used, num_affordable=1}", rows2.get(1).toString());
269+
Assert.assertEquals("{condition=new, num_affordable=3}", rows2.get(2).toString());
270+
// REMOVE_END
271+
272+
273+
// STEP_START agg3
274+
AggregationResult res3 = jedis.ftAggregate("idx:bicycle",
275+
new AggregationBuilder("*")
276+
.apply("'bicycle'", "type")
277+
.groupBy("@type", Reducers.count().as("num_total"))
278+
);
279+
280+
List<Row> rows3 = res3.getRows();
281+
System.out.println(rows3.size()); // >>> 1
282+
283+
for (int i = 0; i < rows3.size(); i++) {
284+
System.out.println(rows3.get(i));
285+
}
286+
// >>> {type=bicycle, num_total=10}
287+
// STEP_END
288+
289+
// Tests for 'agg3' step.
290+
// REMOVE_START
291+
Assert.assertEquals(1, rows3.size());
292+
Assert.assertEquals("{type=bicycle, num_total=10}", rows3.get(0).toString());
293+
// REMOVE_END
294+
295+
296+
// STEP_START agg4
297+
AggregationResult res4 = jedis.ftAggregate("idx:bicycle",
298+
new AggregationBuilder("*")
299+
.load("__key")
300+
.groupBy("@condition",
301+
Reducers.to_list("__key").as("bicycles"))
302+
);
303+
304+
List<Row> rows4 = res4.getRows();
305+
System.out.println(rows4.size()); // >>> 3
306+
307+
for (int i = 0; i < rows4.size(); i++) {
308+
System.out.println(rows4.get(i));
309+
}
310+
// >>> {condition=refurbished, bicycles=[bicycle:9]}
311+
// >>> {condition=used, bicycles=[bicycle:3, bicycle:4, bicycle:1, bicycle:2]}
312+
// >>> {condition=new, bicycles=[bicycle:7, bicycle:0, bicycle:5, bicycle:6, bicycle:8]}
313+
// STEP_END
314+
315+
// Tests for 'agg4' step.
316+
// REMOVE_START
317+
Assert.assertEquals(3, rows4.size());
318+
319+
Row test4Row = rows4.get(0);
320+
Assert.assertEquals("refurbished", test4Row.getString("condition"));
321+
322+
ArrayList<String> test4Bikes = (ArrayList<String>) test4Row.get("bicycles");
323+
Assert.assertEquals(1, test4Bikes.size());
324+
Assert.assertTrue(test4Bikes.contains("bicycle:9"));
325+
326+
test4Row = rows4.get(1);
327+
Assert.assertEquals("used", test4Row.getString("condition"));
328+
329+
test4Bikes = (ArrayList<String>) test4Row.get("bicycles");
330+
Assert.assertEquals(4, test4Bikes.size());
331+
Assert.assertTrue(test4Bikes.contains("bicycle:1"));
332+
Assert.assertTrue(test4Bikes.contains("bicycle:2"));
333+
Assert.assertTrue(test4Bikes.contains("bicycle:3"));
334+
Assert.assertTrue(test4Bikes.contains("bicycle:4"));
335+
336+
test4Row = rows4.get(2);
337+
Assert.assertEquals("new", test4Row.getString("condition"));
338+
339+
test4Bikes = (ArrayList<String>) test4Row.get("bicycles");
340+
Assert.assertEquals(5, test4Bikes.size());
341+
Assert.assertTrue(test4Bikes.contains("bicycle:0"));
342+
Assert.assertTrue(test4Bikes.contains("bicycle:5"));
343+
Assert.assertTrue(test4Bikes.contains("bicycle:6"));
344+
Assert.assertTrue(test4Bikes.contains("bicycle:7"));
345+
Assert.assertTrue(test4Bikes.contains("bicycle:8"));
346+
// REMOVE_END
347+
348+
// HIDE_START
349+
jedis.close();
350+
}
351+
}
352+
// HIDE_END
353+

0 commit comments

Comments
 (0)