Skip to content

Commit 1a3ba6d

Browse files
andy-stark-redistishun
authored andcommitted
DOC-5596 reactive range query examples
1 parent 9e8fb8f commit 1a3ba6d

File tree

2 files changed

+235
-3
lines changed

2 files changed

+235
-3
lines changed

src/test/java/io/redis/examples/async/QueryRangeExample.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ public void run() {
3232
// REMOVE_START
3333
asyncCommands.ftDropindex("idx:bicycle").exceptionally(ex -> null) // Ignore errors if the index doesn't exist.
3434
.toCompletableFuture().join();
35-
asyncCommands.ftDropindex("idx:email").exceptionally(ex -> null) // Ignore errors if the index doesn't exist.
36-
.toCompletableFuture().join();
3735
asyncCommands.del("bicycle:0", "bicycle:1", "bicycle:2", "bicycle:3", "bicycle:4", "bicycle:5", "bicycle:6",
38-
"bicycle:7", "bicycle:8", "bicycle:9", "key:1").toCompletableFuture().join();
36+
"bicycle:7", "bicycle:8", "bicycle:9").toCompletableFuture().join();
3937
// REMOVE_END
4038

4139
List<FieldArgs<String>> bicycleSchema = Arrays.asList(
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// EXAMPLE: query_range
2+
// REMOVE_START
3+
package io.redis.examples.reactive;
4+
5+
// REMOVE_END
6+
import io.lettuce.core.*;
7+
import io.lettuce.core.api.reactive.RedisReactiveCommands;
8+
9+
import io.lettuce.core.search.arguments.*;
10+
import io.lettuce.core.search.SearchReply;
11+
12+
import io.lettuce.core.json.JsonPath;
13+
import io.lettuce.core.json.JsonParser;
14+
import io.lettuce.core.json.JsonObject;
15+
import io.lettuce.core.api.StatefulRedisConnection;
16+
17+
import java.util.*;
18+
import reactor.core.publisher.Mono;
19+
// REMOVE_START
20+
import org.junit.jupiter.api.Test;
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
// REMOVE_END
23+
24+
public class QueryRangeExample {
25+
26+
@Test
27+
public void run() {
28+
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
29+
30+
try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
31+
RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();
32+
// REMOVE_START
33+
reactiveCommands.ftDropindex("idx:bicycle").onErrorReturn("Index `idx:bicycle` does not exist").block();
34+
reactiveCommands.del("bicycle:0", "bicycle:1", "bicycle:2", "bicycle:3", "bicycle:4", "bicycle:5", "bicycle:6",
35+
"bicycle:7", "bicycle:8", "bicycle:9", "key:1").block();
36+
// REMOVE_END
37+
38+
List<FieldArgs<String>> bicycleSchema = Arrays.asList(
39+
TextFieldArgs.<String> builder().name("$.brand").as("brand").build(),
40+
TextFieldArgs.<String> builder().name("$.model").as("model").build(),
41+
TextFieldArgs.<String> builder().name("$.description").as("description").build(),
42+
NumericFieldArgs.<String> builder().name("$.price").as("price").build(),
43+
TagFieldArgs.<String> builder().name("$.condition").as("condition").build());
44+
45+
CreateArgs<String, String> bicycleCreateArgs = CreateArgs.<String, String> builder().on(CreateArgs.TargetType.JSON)
46+
.withPrefix("bicycle:").build();
47+
48+
reactiveCommands.ftCreate("idx:bicycle", bicycleCreateArgs, bicycleSchema).block();
49+
50+
JsonParser parser = reactiveCommands.getJsonParser();
51+
52+
List<JsonObject> bicycleJsons = Arrays.asList(parser.createJsonObject()
53+
.put("brand", parser.createJsonValue("\"Velorim\"")).put("model", parser.createJsonValue("\"Jigger\""))
54+
.put("description", parser
55+
.createJsonValue("\"Small and powerful, the Jigger is the best ride for the smallest of tikes! "
56+
+ "This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger "
57+
+ "is the vehicle of choice for the rare tenacious little rider raring to go.\""))
58+
.put("price", parser.createJsonValue("270")).put("condition", parser.createJsonValue("\"new\"")),
59+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Bicyk\""))
60+
.put("model", parser.createJsonValue("\"Hillcraft\""))
61+
.put("description",
62+
parser.createJsonValue("\"Kids want to ride with as little weight as possible. Especially "
63+
+ "on an incline! They may be at the age when a 27.5'' wheel bike is just too clumsy coming "
64+
+ "off a 24'' bike. The Hillcraft 26 is just the solution they need!\""))
65+
.put("price", parser.createJsonValue("1200")).put("condition", parser.createJsonValue("\"used\"")),
66+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Nord\""))
67+
.put("model", parser.createJsonValue("\"Chook air 5\""))
68+
.put("description",
69+
parser.createJsonValue("\"The Chook Air 5 gives kids aged six years and older a durable "
70+
+ "and uberlight mountain bike for their first experience on tracks and easy cruising through "
71+
+ "forests and fields. The lower top tube makes it easy to mount and dismount in any "
72+
+ "situation, giving your kids greater safety on the trails.\""))
73+
.put("price", parser.createJsonValue("815")).put("condition", parser.createJsonValue("\"used\"")),
74+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Eva\""))
75+
.put("model", parser.createJsonValue("\"Eva 291\""))
76+
.put("description",
77+
parser.createJsonValue("\"The sister company to Nord, Eva launched in 2005 as the first "
78+
+ "and only women-dedicated bicycle brand. Designed by women for women, allEva bikes "
79+
+ "are optimized for the feminine physique using analytics from a body metrics database. "
80+
+ "If you like 29ers, try the Eva 291. It’s a brand new bike for 2022.. This "
81+
+ "full-suspension, cross-country ride has been designed for velocity. The 291 has "
82+
+ "100mm of front and rear travel, a superlight aluminum frame and fast-rolling "
83+
+ "29-inch wheels. Yippee!\""))
84+
.put("price", parser.createJsonValue("3400")).put("condition", parser.createJsonValue("\"used\"")),
85+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Noka Bikes\""))
86+
.put("model", parser.createJsonValue("\"Kahuna\""))
87+
.put("description",
88+
parser.createJsonValue("\"Whether you want to try your hand at XC racing or are looking "
89+
+ "for a lively trail bike that's just as inspiring on the climbs as it is over rougher "
90+
+ "ground, the Wilder is one heck of a bike built specifically for short women. Both the "
91+
+ "frames and components have been tweaked to include a women’s saddle, different bars "
92+
+ "and unique colourway.\""))
93+
.put("price", parser.createJsonValue("3200")).put("condition", parser.createJsonValue("\"used\"")),
94+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Breakout\""))
95+
.put("model", parser.createJsonValue("\"XBN 2.1 Alloy\""))
96+
.put("description",
97+
parser.createJsonValue("\"The XBN 2.1 Alloy is our entry-level road bike – but that’s "
98+
+ "not to say that it’s a basic machine. With an internal weld aluminium frame, a full "
99+
+ "carbon fork, and the slick-shifting Claris gears from Shimano’s, this is a bike which "
100+
+ "doesn’t break the bank and delivers craved performance.\""))
101+
.put("price", parser.createJsonValue("810")).put("condition", parser.createJsonValue("\"new\"")),
102+
parser.createJsonObject().put("brand", parser.createJsonValue("\"ScramBikes\""))
103+
.put("model", parser.createJsonValue("\"WattBike\""))
104+
.put("description",
105+
parser.createJsonValue("\"The WattBike is the best e-bike for people who still "
106+
+ "feel young at heart. It has a Bafang 1000W mid-drive system and a 48V 17.5AH "
107+
+ "Samsung Lithium-Ion battery, allowing you to ride for more than 60 miles on one "
108+
+ "charge. It’s great for tackling hilly terrain or if you just fancy a more "
109+
+ "leisurely ride. With three working modes, you can choose between E-bike, "
110+
+ "assisted bicycle, and normal bike modes.\""))
111+
.put("price", parser.createJsonValue("2300")).put("condition", parser.createJsonValue("\"new\"")),
112+
parser.createJsonObject().put("brand", parser.createJsonValue("\"Peaknetic\""))
113+
.put("model", parser.createJsonValue("\"Secto\""))
114+
.put("description",
115+
parser.createJsonValue("\"If you struggle with stiff fingers or a kinked neck or "
116+
+ "back after a few minutes on the road, this lightweight, aluminum bike alleviates "
117+
+ "those issues and allows you to enjoy the ride. From the ergonomic grips to the "
118+
+ "lumbar-supporting seat position, the Roll Low-Entry offers incredible comfort. "
119+
+ "The rear-inclined seat tube facilitates stability by allowing you to put a foot "
120+
+ "on the ground to balance at a stop, and the low step-over frame makes it "
121+
+ "accessible for all ability and mobility levels. The saddle is very soft, with "
122+
+ "a wide back to support your hip joints and a cutout in the center to redistribute "
123+
+ "that pressure. Rim brakes deliver satisfactory braking control, and the wide tires "
124+
+ "provide a smooth, stable ride on paved roads and gravel. Rack and fender mounts "
125+
+ "facilitate setting up the Roll Low-Entry as your preferred commuter, and the "
126+
+ "BMX-like handlebar offers space for mounting a flashlight, bell, or phone holder.\""))
127+
.put("price", parser.createJsonValue("430")).put("condition", parser.createJsonValue("\"new\"")),
128+
parser.createJsonObject().put("brand", parser.createJsonValue("\"nHill\""))
129+
.put("model", parser.createJsonValue("\"Summit\""))
130+
.put("description",
131+
parser.createJsonValue("\"This budget mountain bike from nHill performs well both "
132+
+ "on bike paths and on the trail. The fork with 100mm of travel absorbs rough "
133+
+ "terrain. Fat Kenda Booster tires give you grip in corners and on wet trails. "
134+
+ "The Shimano Tourney drivetrain offered enough gears for finding a comfortable "
135+
+ "pace to ride uphill, and the Tektro hydraulic disc brakes break smoothly. "
136+
+ "Whether you want an affordable bike that you can take to work, but also take "
137+
+ "trail in mountains on the weekends or you’re just after a stable, comfortable "
138+
+ "ride for the bike path, the Summit gives a good value for money.\""))
139+
.put("price", parser.createJsonValue("1200")).put("condition", parser.createJsonValue("\"new\"")),
140+
parser.createJsonObject().put("brand", parser.createJsonValue("\"ThrillCycle\""))
141+
.put("model", parser.createJsonValue("\"BikeShind\""))
142+
.put("description",
143+
parser.createJsonValue("\"An artsy, retro-inspired bicycle that’s as "
144+
+ "functional as it is pretty: The ThrillCycle steel frame offers a smooth ride. "
145+
+ "A 9-speed drivetrain has enough gears for coasting in the city, but we wouldn’t "
146+
+ "suggest taking it to the mountains. Fenders protect you from mud, and a rear "
147+
+ "basket lets you transport groceries, flowers and books. The ThrillCycle comes "
148+
+ "with a limited lifetime warranty, so this little guy will last you long "
149+
+ "past graduation.\""))
150+
.put("price", parser.createJsonValue("815"))
151+
.put("condition", parser.createJsonValue("\"refurbished\"")));
152+
153+
Mono<?>[] bikeFutures = new Mono<?>[bicycleJsons.size()];
154+
155+
for (int i = 0; i < bicycleJsons.size(); i++) {
156+
bikeFutures[i] = reactiveCommands.jsonSet("bicycle:" + i, JsonPath.ROOT_PATH, bicycleJsons.get(i));
157+
}
158+
159+
Mono.when(bikeFutures).block();
160+
161+
// STEP_START range1
162+
Mono<SearchReply<String, String>> priceResults = reactiveCommands.ftSearch("idx:bicycle", "@price:[500 1000]")
163+
.doOnNext(res -> {
164+
res.getResults().stream().sorted((doc1, doc2) -> doc1.getId().compareTo(doc2.getId())).forEach(doc -> {
165+
System.out.printf("ID: %s\n", doc.getId());
166+
});
167+
// >>> ID: bicycle:2
168+
// >>> ID: bicycle:5
169+
// >>> ID: bicycle:9
170+
// REMOVE_START
171+
assertThat(res.getResults().size()).isEqualTo(3);
172+
assertThat(res.getResults().stream().map(SearchReply.SearchResult<String, String>::getId).sorted()
173+
.toArray()).containsExactly("bicycle:2", "bicycle:5", "bicycle:9");
174+
// REMOVE_END
175+
});
176+
// STEP_END
177+
178+
// STEP_START range2
179+
180+
// `Filter` is not supported.
181+
182+
// STEP_END
183+
184+
// STEP_START range3
185+
SearchArgs<String, String> priceSearchArgs2 = SearchArgs.<String, String> builder().returnField("price").build();
186+
187+
Mono<SearchReply<String, String>> priceResults2 = reactiveCommands
188+
.ftSearch("idx:bicycle", "@price:[(1000 +inf]", priceSearchArgs2).doOnNext(res -> {
189+
res.getResults().stream().sorted((doc1, doc2) -> doc1.getId().compareTo(doc2.getId())).forEach(doc -> {
190+
System.out.printf("ID: %s, price: %s\n", doc.getId(), doc.getFields().get("price"));
191+
});
192+
// >>> ID: bicycle:1, price: 1200
193+
// >>> ID: bicycle:3, price: 3400
194+
// >>> ID: bicycle:4, price: 3200
195+
// >>> ID: bicycle:6, price: 2300
196+
// >>> ID: bicycle:8, price: 1200
197+
// REMOVE_START
198+
assertThat(res.getResults().size()).isEqualTo(5);
199+
assertThat(res.getResults().stream().map(SearchReply.SearchResult<String, String>::getId).sorted()
200+
.toArray()).containsExactly("bicycle:1", "bicycle:3", "bicycle:4", "bicycle:6", "bicycle:8");
201+
// REMOVE_END
202+
});
203+
// STEP_END
204+
205+
// STEP_START range4
206+
SearchArgs<String, String> priceSearchArgs3 = SearchArgs.<String, String> builder().returnField("price")
207+
.sortBy(SortByArgs.<String> builder().attribute("price").build()).limit(0, 5).build();
208+
209+
Mono<SearchReply<String, String>> priceResults3 = reactiveCommands
210+
.ftSearch("idx:bicycle", "@price:[-inf 2000]", priceSearchArgs3).doOnNext(res -> {
211+
res.getResults().stream().sorted((doc1, doc2) -> doc1.getId().compareTo(doc2.getId())).forEach(doc -> {
212+
System.out.printf("ID: %s, price: %s\n", doc.getId(), doc.getFields().get("price"));
213+
});
214+
// >>> ID: bicycle:0, price: 270
215+
// >>> ID: bicycle:2, price: 815
216+
// >>> ID: bicycle:5, price: 810
217+
// >>> ID: bicycle:7, price: 430
218+
// >>> ID: bicycle:9, price: 815
219+
// REMOVE_START
220+
assertThat(res.getResults().size()).isEqualTo(5);
221+
assertThat(res.getResults().stream().map(SearchReply.SearchResult<String, String>::getId).sorted()
222+
.toArray()).containsExactly("bicycle:0", "bicycle:2", "bicycle:5", "bicycle:7", "bicycle:9");
223+
// REMOVE_END
224+
});
225+
// STEP_END
226+
227+
Mono.when(priceResults, priceResults2, priceResults3).block();
228+
229+
} finally {
230+
redisClient.shutdown();
231+
}
232+
}
233+
234+
}

0 commit comments

Comments
 (0)